aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMelody Horn <melody@boringcactus.com>2020-10-28 17:01:55 -0600
committerMelody Horn <melody@boringcactus.com>2020-10-28 17:01:55 -0600
commitedf87f09045e8f56576b37078b4a0d220d6ddf55 (patch)
tree4503afb80ee7ea068db257c6381541a5fe1f716b
parent72e8cabe8e3c8ae272fb4771f0d1dabb306dc2ae (diff)
downloadspec-edf87f09045e8f56576b37078b4a0d220d6ddf55.tar.gz
spec-edf87f09045e8f56576b37078b4a0d220d6ddf55.zip
start using Sphinx for doc generation
-rw-r--r--.build.yml27
-rw-r--r--.gitignore1
-rw-r--r--LICENSE.md4
-rw-r--r--Makefile52
-rw-r--r--conf.py59
-rw-r--r--errors.md4
-rw-r--r--etc/gemtext.lua297
-rw-r--r--etc/md.yml20
-rw-r--r--etc/pdf.yml15
-rw-r--r--etc/process-md.lua12
-rw-r--r--etc/process-pdf.lua0
-rw-r--r--etc/template.gmi1
-rw-r--r--etc/template.html153
-rw-r--r--index.md39
-rw-r--r--index.rst30
-rw-r--r--intro.rst47
-rw-r--r--make.bat35
-rw-r--r--safety.md40
-rw-r--r--syntax.md36
-rw-r--r--tagged-unions.md4
-rw-r--r--types.md4
-rw-r--r--vs-c.md18
22 files changed, 255 insertions, 643 deletions
diff --git a/.build.yml b/.build.yml
index 6771d96..24a8ba1 100644
--- a/.build.yml
+++ b/.build.yml
@@ -1,21 +1,24 @@
image: debian/testing
packages:
- - pandoc
- - weasyprint
+ - python3-sphinx
+ - python3-pip
- poppler-utils
- - sic
- rsync
sources:
- https://git.sr.ht/~boringcactus/crowbar-spec
secrets:
- b5cb9b2b-1461-4486-95e1-886451674a89
tasks:
+ - prep: |
+ sudo pip3 install recommonmark rinohtype
- build: |
cd crowbar-spec
make
- compress: |
- tar czf spec-html.tar.gz crowbar-spec/*.html
- tar czf spec-gmi.tar.gz crowbar-spec/*.gmi
+ cd crowbar-spec/_build/html
+ tar czf ../crowbar-spec-html.tar.gz *
+ #cd ../gmi
+ #tar czf ../crowbar-spec-gmi.tar.gz *
- test-page-count: |
cd crowbar-spec
make check
@@ -25,14 +28,16 @@ tasks:
shift
rsync --rsh="ssh -o StrictHostKeyChecking=no" -rlt8hP --del $@ services@boringcactus.com:$dest
}
- cd crowbar-spec
- upload-to /var/www/html/crowbar-lang.org/ *.html spec.pdf
- upload-to /var/gemini/gmi/crowbar-lang.org/ *.gmi spec.pdf
+ cd crowbar-spec/_build/html
+ upload-to /var/www/html/crowbar-lang.org/ * ../rinoh/crowbarlanguage.pdf
+ #cd ../gmi
+ #upload-to /var/gemini/gmi/crowbar-lang.org/ * ../rinoh/crowbarlanguage.pdf
- notify: |
cd crowbar-spec
message="crowbar spec updated: $(git log -1 --no-decorate --oneline)"
echo "/NOTICE #crowbar-lang :$message" | ssh -o StrictHostKeyChecking=no services@boringcactus.com 'sh -c "cat > ~/irc/chat.freenode.net/#crowbar-lang/in"'
artifacts:
- - crowbar-spec/spec.pdf
- - spec-html.tar.gz
- - spec-gmi.tar.gz
+ - crowbar-spec/_build/rinoh/crowbarlanguage.pdf
+ - crowbar-spec/_build/epub/Crowbarlanguage.epub
+ - crowbar-spec/_build/crowbar-spec-html.tar.gz
+ #- crowbar-spec/_build/crowbar-spec-gmi.tar.gz
diff --git a/.gitignore b/.gitignore
index 055b012..2bd514e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
/*.html
/*.gmi
/spec.pdf
+/_build
diff --git a/LICENSE.md b/LICENSE.md
index 20ffc56..5613bc2 100644
--- a/LICENSE.md
+++ b/LICENSE.md
@@ -1,6 +1,4 @@
----
-title: License
----
+# License
[![Creative Commons BY-SA License](https://i.creativecommons.org/l/by-sa/4.0/80x15.png)](http://creativecommons.org/licenses/by-sa/4.0/)
This work is licensed under a [Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/).
diff --git a/Makefile b/Makefile
index 7bd231c..432029b 100644
--- a/Makefile
+++ b/Makefile
@@ -1,46 +1,32 @@
.POSIX:
.SUFFIXES:
-.SUFFIXES: .md .html .gmi
# commands
GIT = git
-PANDOC = pandoc
+SPHINXBUILD = sphinx-build
+SPHINXOPTS =
+SPHINXDEFVER = -D version="$$($(GIT) describe --tags --exact-match 2>/dev/null || $(GIT) log -1 --no-decorate --oneline)"
+SPHINXFULLOPTS = $(SPHINXDEFVER) $(SPHINXOPTS)
+SOURCEDIR = .
+BUILDDIR = _build
PDFINFO = pdfinfo
-# input files
-SRC = index.md vs-c.md tagged-unions.md types.md safety.md errors.md syntax.md LICENSE.md
-HTML = $(SRC:.md=.html)
-GMI = $(SRC:.md=.gmi)
+all: html pdf epub # gmi
-all: spec.pdf $(GMI)
+html: Makefile
+ @$(SPHINXBUILD) -M html "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXFULLOPTS)
-spec.pdf: $(HTML)
- @if $(GIT) describe --tags --exact-match 2>/dev/null; \
- then \
- metadata="subtitle=$$($(GIT) describe --tags --exact-match)"; \
- else \
- metadata="version=$$($(GIT) log -1 --no-decorate --oneline)"; \
- fi; \
- $(PANDOC) --defaults=etc/pdf.yml -M "$$metadata" -o $@ $(HTML)
+gmi: Makefile
+ @$(SPHINXBUILD) -M gmi "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXFULLOPTS)
-.md.html:
- @offset=`echo $(SRC) | awk '{for (i=1; i<=NF; i++) if ($$i == "$<") print (i-1) }'`; \
- $(PANDOC) --defaults=etc/md.yml --number-offset=$$offset -o $@ $<
+pdf: Makefile
+ @$(SPHINXBUILD) -M rinoh "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXFULLOPTS)
-.md.gmi:
- @offset=`echo $(SRC) | awk '{for (i=1; i<=NF; i++) if ($$i == "$<") print (i-1) }'`; \
- $(PANDOC) --defaults=etc/md.yml --write=etc/gemtext.lua --template=etc/template.gmi --number-offset=$$offset -o $@ $<
+epub: Makefile
+ @$(SPHINXBUILD) -M epub "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXFULLOPTS)
-clean: clean-pdf clean-html clean-gmi
+clean:
+ rm -rf _build/*
-clean-pdf:
- rm -f spec.pdf
-
-clean-html:
- rm -f $(HTML)
-
-clean-gmi:
- rm -f $(GMI)
-
-check: spec.pdf
- test $$($(PDFINFO) spec.pdf | grep Pages | awk '{ print $$2 }') -le 200
+check: pdf
+ test $$($(PDFINFO) _build/rinoh/crowbarlanguage.pdf | grep Pages | awk '{ print $$2 }') -le 200
diff --git a/conf.py b/conf.py
new file mode 100644
index 0000000..01bec76
--- /dev/null
+++ b/conf.py
@@ -0,0 +1,59 @@
+# Configuration file for the Sphinx documentation builder.
+#
+# This file only contains a selection of the most common options. For a full
+# list see the documentation:
+# https://www.sphinx-doc.org/en/master/usage/configuration.html
+
+# -- Path setup --------------------------------------------------------------
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#
+# import os
+# import sys
+# sys.path.insert(0, os.path.abspath('.'))
+
+
+# -- Project information -----------------------------------------------------
+
+project = 'Crowbar language'
+copyright = '2020 boringcactus (Melody Horn)'
+author = 'boringcactus (Melody Horn)'
+
+
+# -- General configuration ---------------------------------------------------
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = [
+ 'recommonmark',
+]
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+# This pattern also affects html_static_path and html_extra_path.
+exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
+
+latex_engine = 'xelatex'
+
+
+# -- Options for HTML output -------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+#
+html_theme = 'basic'
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+html_theme_options = {
+ "nosidebar": True,
+}
diff --git a/errors.md b/errors.md
index 15e4c78..3ed38e9 100644
--- a/errors.md
+++ b/errors.md
@@ -1,5 +1,3 @@
----
-title: Error Handling
----
+# Error Handling
TODO
diff --git a/etc/gemtext.lua b/etc/gemtext.lua
deleted file mode 100644
index 5fdff59..0000000
--- a/etc/gemtext.lua
+++ /dev/null
@@ -1,297 +0,0 @@
--- Invoke with: pandoc -t gemtext.lua
-
--- Tables to store links and footnotes, so they can be included correctly.
-local links = {}
-local notes = {}
-
--- Blocksep is used to separate block elements.
-function Blocksep()
- return "\n"
-end
-
--- This function is called once for the whole document. Parameters:
--- body is a string, metadata is a table, variables is a table.
--- This gives you a fragment. You could use the metadata table to
--- fill variables in a custom lua template. Or, pass `--template=...`
--- to pandoc, and pandoc will do the template processing as usual.
-function Doc(body, metadata, variables)
- local buffer = {}
- local function add(s)
- table.insert(buffer, s)
- end
- add(body)
- if #notes > 0 then
- add('')
- for _,note in pairs(notes) do
- add(note)
- end
- end
- return table.concat(buffer, '\n')
-end
-
--- The functions that follow render corresponding pandoc elements.
--- s is always a string, attr is always a table of attributes, and
--- items is always an array of strings (the items in a list).
--- Comments indicate the types of other variables.
-
-function Str(s)
- return s
-end
-
-function Space()
- return " "
-end
-
-function SoftBreak()
- return " "
-end
-
-function LineBreak()
- return "\n"
-end
-
-function Emph(s)
- return "_" .. s .. "_"
-end
-
-function Strong(s)
- return "**" .. s .. "**"
-end
-
-function Subscript(s)
- return "_" .. s
-end
-
-function Superscript(s)
- return "^" .. s
-end
-
-function SmallCaps(s)
- return s
-end
-
-function Strikeout(s)
- return '~~' .. s .. '~~'
-end
-
-function Link(s, tgt, tit, attr)
- if tgt:match("%.html$") and not tgt:match("^https?://") then
- tgt = tgt:gsub("%.html$", ".gmi")
- end
- table.insert(links, "=> " .. tgt .. " " .. s)
- return s
-end
-
-function Image(s, src, tit, attr)
- table.insert(links, "=> " .. src .. " [IMG] " .. s)
- return s
-end
-
-function Code(s, attr)
- return "`" .. s .. "`"
-end
-
-function InlineMath(s)
- return "\\(" .. s .. "\\)"
-end
-
-function DisplayMath(s)
- return "\\[" .. s .. "\\]"
-end
-
-function SingleQuoted(s)
- return "‘" .. s .. "’"
-end
-
-function DoubleQuoted(s)
- return "“" .. s .. "”"
-end
-
-function Note(s)
- local num = #notes + 1
- local num_fn = string.gsub(num, '0', '⁰')
- :gsub('1', '¹')
- :gsub('2', '²')
- :gsub('3', '³')
- :gsub('4', '⁴')
- :gsub('5', '⁵')
- :gsub('6', '⁶')
- :gsub('7', '⁷')
- :gsub('8', '⁸')
- :gsub('9', '⁹')
- -- add a list item with the note to the note table.
- table.insert(notes, num_fn .. ' ' .. s)
- -- return the footnote reference, linked to the note.
- return num_fn
-end
-
-function Span(s, attr)
- return s
-end
-
-function RawInline(format, str)
- if format == "gemtext" then
- return str
- else
- return ''
- end
-end
-
-function Cite(s, cs)
- local ids = {}
- for _,cit in ipairs(cs) do
- table.insert(ids, cit.citationId)
- end
- return s .. ids:concat(",")
-end
-
-function Plain(s)
- return s
-end
-
-function Para(s)
- local finished = s .. "\n"
- if #links > 0 then
- local link_text = links[1]:match('=> [^ ]+ (.+)')
- if link_text == s and #links == 1 then
- finished = links[1] .. "\n"
- else
- finished = finished .. table.concat(links, "\n") .. "\n"
- end
- end
- links = {}
- return finished
-end
-
--- lev is an integer, the header level.
-function Header(lev, s, attr)
- return string.rep("#", lev) .. " " .. s .. "\n"
-end
-
-function BlockQuote(s)
- return "> " .. s:gsub("\n", "\n> "):gsub("\n> $", "\n")
-end
-
-function HorizontalRule()
- return "-----\n"
-end
-
-function LineBlock(ls)
- return table.concat(ls, '\n') .. "\n"
-end
-
-function CodeBlock(s, attr)
- return "```\n" .. s .. "\n```\n"
-end
-
-function BulletList(items)
- local buffer = {}
- for _, item in pairs(items) do
- local finished = false
- if #links > 0 then
- local link_text = links[1]:match('=> [^ ]+ (.+)')
- if link_text == item then
- table.insert(buffer, links[1])
- table.remove(links, 1)
- finished = true
- end
- end
- if not finished then
- table.insert(buffer, "* " .. item)
- for _,link in pairs(links) do
- table.insert(buffer, link)
- end
- links = {}
- end
- end
- return table.concat(buffer, "\n") .. "\n"
-end
-
-function OrderedList(items)
- local buffer = {}
- for i, item in pairs(items) do
- table.insert(buffer, i .. ". " .. item)
- end
- return table.concat(buffer, "\n") .. "\n"
-end
-
-function DefinitionList(items)
- local buffer = {}
- for _,item in pairs(items) do
- local k, v = next(item)
- table.insert(buffer, k .. ":\n" .. table.concat(v, "\n"))
- end
- return table.concat(buffer, "\n") .. "\n"
-end
-
-function CaptionedImage(src, tit, caption, attr)
- return '=> ' .. src .. ' [IMG] ' .. caption .. '\n'
-end
-
--- Caption is a string, aligns is an array of strings,
--- widths is an array of floats, headers is an array of
--- strings, rows is an array of arrays of strings.
-function Table(caption, aligns, widths, headers, rows)
- local buffer = {}
- local function add(s)
- table.insert(buffer, s)
- end
- add("<table>")
- if caption ~= "" then
- add("<caption>" .. caption .. "</caption>")
- end
- if widths and widths[1] ~= 0 then
- for _, w in pairs(widths) do
- add('<col width="' .. string.format("%.0f%%", w * 100) .. '" />')
- end
- end
- local header_row = {}
- local empty_header = true
- for i, h in pairs(headers) do
- table.insert(header_row,'<th>' .. h .. '</th>')
- empty_header = empty_header and h == ""
- end
- if empty_header then
- head = ""
- else
- add('<tr class="header">')
- for _,h in pairs(header_row) do
- add(h)
- end
- add('</tr>')
- end
- local class = "even"
- for _, row in pairs(rows) do
- class = (class == "even" and "odd") or "even"
- add('<tr class="' .. class .. '">')
- for i,c in pairs(row) do
- add('<td>' .. c .. '</td>')
- end
- add('</tr>')
- end
- add('</table>')
- return table.concat(buffer,'\n') .. "\n"
-end
-
-function RawBlock(format, str)
- if format == "gemtext" then
- return str
- else
- return ''
- end
-end
-
-function Div(s, attr)
- return s
-end
-
--- The following code will produce runtime warnings when you haven't defined
--- all of the functions you need for the custom writer, so it's useful
--- to include when you're working on a writer.
-local meta = {}
-meta.__index =
- function(_, key)
- io.stderr:write(string.format("WARNING: Undefined function '%s'\n",key))
- return function() return "" end
- end
-setmetatable(_G, meta)
diff --git a/etc/md.yml b/etc/md.yml
deleted file mode 100644
index 52cdcfa..0000000
--- a/etc/md.yml
+++ /dev/null
@@ -1,20 +0,0 @@
-template: etc/template.html
-standalone: true
-
-filters:
- - etc/process-md.lua
-
-metadata:
- lang: "en"
-
-verbosity: INFO
-
-table-of-contents: false
-number-sections: true
-shift-heading-level-by: 1
-title-prefix: "Crowbar Specification"
-eol: lf
-
-# syntax-definition:
-
-fail-if-warnings: true
diff --git a/etc/pdf.yml b/etc/pdf.yml
deleted file mode 100644
index 85750bf..0000000
--- a/etc/pdf.yml
+++ /dev/null
@@ -1,15 +0,0 @@
-template: etc/template.html
-
-filters:
- - etc/process-pdf.lua
-
-metadata:
- title-before-toc: true
- title: "Crowbar Specification"
-
-verbosity: WARNING
-
-pdf-engine: weasyprint
-
-table-of-contents: true
-number-sections: false
diff --git a/etc/process-md.lua b/etc/process-md.lua
deleted file mode 100644
index f0e11dc..0000000
--- a/etc/process-md.lua
+++ /dev/null
@@ -1,12 +0,0 @@
-function Pandoc(doc)
- local title_header = pandoc.Header(1, '')
- local title = doc.meta.title
- title_header.content = title
- doc.blocks:insert(1, title_header)
- return doc
-end
-
-function Link(node)
- node.target = node.target:gsub(".md", ".html")
- return node
-end
diff --git a/etc/process-pdf.lua b/etc/process-pdf.lua
deleted file mode 100644
index e69de29..0000000
--- a/etc/process-pdf.lua
+++ /dev/null
diff --git a/etc/template.gmi b/etc/template.gmi
deleted file mode 100644
index 36d66c2..0000000
--- a/etc/template.gmi
+++ /dev/null
@@ -1 +0,0 @@
-$body$
diff --git a/etc/template.html b/etc/template.html
deleted file mode 100644
index 61cefb4..0000000
--- a/etc/template.html
+++ /dev/null
@@ -1,153 +0,0 @@
-<!DOCTYPE html>
-<html xmlns="http://www.w3.org/1999/xhtml" lang="$lang$" xml:lang="$lang$"$if(dir)$ dir="$dir$"$endif$>
-<head>
- <meta charset="utf-8" />
- <meta name="generator" content="pandoc" />
- <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
- <title>$if(title-prefix)$$title-prefix$ – $endif$$pagetitle$</title>
- <style>
- /* "derived" (stolen) from evenbettermotherfucking.website */
- html {
- margin: 1rem auto;
- background: #f2f2f2;
- color: #444444;
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
- font-size: 16px;
- line-height: 1.8;
- text-shadow: 0 1px 0 #ffffff;
- max-width: 60em;
- }
- @media print {
- html {
- background: white;
- }
- }
- body {
- margin: 0 1rem;
- }
- code {
- background: white;
- }
- pre {
- line-height: 1.25;
- }
- .highlight code {
- background: unset;
- }
- div.highlighter-rouge {
- background: white;
- padding: 1rem;
- line-height: 1;
- overflow-x: auto;
- }
- div.highlighter-rouge pre {
- padding: 0;
- margin: 0;
- }
- a {
- border-bottom: 1px solid #444444;
- color: #444444;
- text-decoration: none;
- }
- a:hover {
- border-bottom-style: dashed;
- }
- blockquote {
- margin-left: 1em;
- border-left: 2px solid #444444;
- padding-left: 1em;
- }
-
- #TOC .header-section-number {
- display: none;
- }
-
- /* https://github.com/richleland/pygments-css/blob/master/friendly.css */
- .highlight .hll { background-color: #ffffcc }
- .highlight .c { color: #60a0b0; font-style: italic } /* Comment */
- .highlight .err { border: 1px solid #FF0000 } /* Error */
- .highlight .k { color: #007020; font-weight: bold } /* Keyword */
- .highlight .o { color: #666666 } /* Operator */
- .highlight .ch { color: #60a0b0; font-style: italic } /* Comment.Hashbang */
- .highlight .cm { color: #60a0b0; font-style: italic } /* Comment.Multiline */
- .highlight .cp { color: #007020 } /* Comment.Preproc */
- .highlight .cpf { color: #60a0b0; font-style: italic } /* Comment.PreprocFile */
- .highlight .c1 { color: #60a0b0; font-style: italic } /* Comment.Single */
- .highlight .cs { color: #60a0b0; background-color: #fff0f0 } /* Comment.Special */
- .highlight .gd { color: #A00000 } /* Generic.Deleted */
- .highlight .ge { font-style: italic } /* Generic.Emph */
- .highlight .gr { color: #FF0000 } /* Generic.Error */
- .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
- .highlight .gi { color: #00A000 } /* Generic.Inserted */
- .highlight .go { color: #888888 } /* Generic.Output */
- .highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
- .highlight .gs { font-weight: bold } /* Generic.Strong */
- .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
- .highlight .gt { color: #0044DD } /* Generic.Traceback */
- .highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */
- .highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */
- .highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */
- .highlight .kp { color: #007020 } /* Keyword.Pseudo */
- .highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */
- .highlight .kt { color: #902000 } /* Keyword.Type */
- .highlight .m { color: #40a070 } /* Literal.Number */
- .highlight .s { color: #4070a0 } /* Literal.String */
- .highlight .na { color: #4070a0 } /* Name.Attribute */
- .highlight .nb { color: #007020 } /* Name.Builtin */
- .highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */
- .highlight .no { color: #60add5 } /* Name.Constant */
- .highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */
- .highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */
- .highlight .ne { color: #007020 } /* Name.Exception */
- .highlight .nf { color: #06287e } /* Name.Function */
- .highlight .nl { color: #002070; font-weight: bold } /* Name.Label */
- .highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
- .highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */
- .highlight .nv { color: #bb60d5 } /* Name.Variable */
- .highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */
- .highlight .w { color: #bbbbbb } /* Text.Whitespace */
- .highlight .mb { color: #40a070 } /* Literal.Number.Bin */
- .highlight .mf { color: #40a070 } /* Literal.Number.Float */
- .highlight .mh { color: #40a070 } /* Literal.Number.Hex */
- .highlight .mi { color: #40a070 } /* Literal.Number.Integer */
- .highlight .mo { color: #40a070 } /* Literal.Number.Oct */
- .highlight .sa { color: #4070a0 } /* Literal.String.Affix */
- .highlight .sb { color: #4070a0 } /* Literal.String.Backtick */
- .highlight .sc { color: #4070a0 } /* Literal.String.Char */
- .highlight .dl { color: #4070a0 } /* Literal.String.Delimiter */
- .highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */
- .highlight .s2 { color: #4070a0 } /* Literal.String.Double */
- .highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */
- .highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */
- .highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */
- .highlight .sx { color: #c65d09 } /* Literal.String.Other */
- .highlight .sr { color: #235388 } /* Literal.String.Regex */
- .highlight .s1 { color: #4070a0 } /* Literal.String.Single */
- .highlight .ss { color: #517918 } /* Literal.String.Symbol */
- .highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */
- .highlight .fm { color: #06287e } /* Name.Function.Magic */
- .highlight .vc { color: #bb60d5 } /* Name.Variable.Class */
- .highlight .vg { color: #bb60d5 } /* Name.Variable.Global */
- .highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */
- .highlight .vm { color: #bb60d5 } /* Name.Variable.Magic */
- .highlight .il { color: #40a070 } /* Literal.Number.Integer.Long */
- </style>
-</head>
-<body>
-$if(title-before-toc)$
-<h1>$title$</h1>
-$if(subtitle)$
-<h2>$subtitle$</h2>
-$endif$
-$if(version)$
-<p>from git: <code>$version$</code></p>
-$endif$
-$endif$
-$if(toc)$
-<nav id="$idprefix$TOC" role="doc-toc">
-$table-of-contents$
-</nav>
-$endif$
-$body$
-</body>
-</html>
diff --git a/index.md b/index.md
deleted file mode 100644
index f20cb69..0000000
--- a/index.md
+++ /dev/null
@@ -1,39 +0,0 @@
----
-title: Introduction
----
-
-Crowbar: the good parts of C, with a little bit extra.
-
-**This is entirely a work-in-progress, and should not be relied upon to be stable (or even true) in any way.**
-
-Crowbar is a language that is derived from (and, wherever possible, interoperable with) C, and aims to remove as many [footgun](https://en.wiktionary.org/wiki/footgun)s and as much needless complexity from C as possible while still being familiar to C developers.
-
-Ideally, a typical C codebase should be straightforward to rewrite in Crowbar, and any atypical C constructions not supported by Crowbar can be left as C.
-
-# Motivation
-
-- [Rust is not a good C replacement](https://drewdevault.com/2019/03/25/Rust-is-not-a-good-C-replacement.html)
-
-# Journal
-
-- [Crowbar: Defining a good C replacement](https://www.boringcactus.com/2020/09/28/crowbar-1-defining-a-c-replacement.html)
-- [Crowbar: Simplifying C's type names](https://www.boringcactus.com/2020/10/13/crowbar-2-simplifying-c-type-names.html)
-- [Crowbar: Turns out, language development is hard](https://www.boringcactus.com/2020/10/19/crowbar-3-this-is-tough.html)
-
-# Comparison with C
-
-The [comparison with C](vs-c.md) is an informal overview of the places where Crowbar and C diverge.
-
-# Syntax
-
-[Read the Syntax chapter of the spec.](syntax.md)
-
-# Semantics
-
-TODO
-
-# Discuss
-
-- [announcement mailing list](https://lists.sr.ht/~boringcactus/crowbar-lang-announce)
-- [permanent discussion mailing list](https://lists.sr.ht/~boringcactus/crowbar-lang-devel)
-- ephemeral discussions via IRC: #crowbar-lang on freenode ([join via irc](ircs://chat.freenode.net/#crowbar-lang), [join via web](https://webchat.freenode.net/#crowbar-lang))
diff --git a/index.rst b/index.rst
new file mode 100644
index 0000000..c3fa323
--- /dev/null
+++ b/index.rst
@@ -0,0 +1,30 @@
+.. Crowbar spec documentation master file, created by
+ sphinx-quickstart on Wed Oct 28 15:04:27 2020.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+.. include:: README.md
+
+Crowbar Specification
+=====================
+
+Version |version|
+
+.. toctree::
+ :maxdepth: 2
+ :caption: Contents:
+
+ intro
+ vs-c
+ tagged-unions
+ types
+ safety
+ errors
+ syntax
+ LICENSE
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`search`
diff --git a/intro.rst b/intro.rst
new file mode 100644
index 0000000..c77b2c7
--- /dev/null
+++ b/intro.rst
@@ -0,0 +1,47 @@
+************
+Introduction
+************
+
+Crowbar: the good parts of C, with a little bit extra.
+
+**This is entirely a work-in-progress, and should not be relied upon to be stable (or even true) in any way.**
+
+Crowbar is a language that is derived from (and, wherever possible, interoperable with) C, and aims to remove as many `footguns`_ and as much needless complexity from C as possible while still being familiar to C developers.
+
+.. _footguns: https://en.wiktionary.org/wiki/footgun
+
+Ideally, a typical C codebase should be straightforward to rewrite in Crowbar, and any atypical C constructions not supported by Crowbar can be left as C.
+
+Motivation
+==========
+
+* `Rust is not a good C replacement <https://drewdevault.com/2019/03/25/Rust-is-not-a-good-C-replacement.html>`_
+
+Journal
+=======
+
+* `Crowbar: Defining a good C replacement <https://www.boringcactus.com/2020/09/28/crowbar-1-defining-a-c-replacement.html>`_
+* `Crowbar: Simplifying C's type names <https://www.boringcactus.com/2020/10/13/crowbar-2-simplifying-c-type-names.html>`_
+* `Crowbar: Turns out, language development is hard <https://www.boringcactus.com/2020/10/19/crowbar-3-this-is-tough.html>`_
+
+Comparison with C
+=================
+
+The :doc:`/vs-c` is an informal overview of the places where Crowbar and C diverge.
+
+Syntax
+======
+
+:doc:`/syntax`
+
+Semantics
+=========
+
+TODO
+
+Discuss
+=======
+
+* `announcement mailing list <https://lists.sr.ht/~boringcactus/crowbar-lang-announce>`_
+* `permanent discussion mailing list <https://lists.sr.ht/~boringcactus/crowbar-lang-devel>`_
+* ephemeral discussions via IRC: #crowbar-lang on freenode (`join via irc <ircs://chat.freenode.net/#crowbar-lang>`_, `join via web <https://webchat.freenode.net/#crowbar-lang>`_)
diff --git a/make.bat b/make.bat
new file mode 100644
index 0000000..2119f51
--- /dev/null
+++ b/make.bat
@@ -0,0 +1,35 @@
+@ECHO OFF
+
+pushd %~dp0
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+ set SPHINXBUILD=sphinx-build
+)
+set SOURCEDIR=.
+set BUILDDIR=_build
+
+if "%1" == "" goto help
+
+%SPHINXBUILD% >NUL 2>NUL
+if errorlevel 9009 (
+ echo.
+ echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
+ echo.installed, then set the SPHINXBUILD environment variable to point
+ echo.to the full path of the 'sphinx-build' executable. Alternatively you
+ echo.may add the Sphinx directory to PATH.
+ echo.
+ echo.If you don't have Sphinx installed, grab it from
+ echo.http://sphinx-doc.org/
+ exit /b 1
+)
+
+%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
+goto end
+
+:help
+%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
+
+:end
+popd
diff --git a/safety.md b/safety.md
index 2918806..c50a06a 100644
--- a/safety.md
+++ b/safety.md
@@ -1,6 +1,4 @@
----
-title: Memory Safety
----
+# Memory Safety
Each item in Wikipedia's [list of types of memory errors](https://en.wikipedia.org/wiki/Memory_safety#Types_of_memory_errors) and what Crowbar does to prevent them.
@@ -8,9 +6,9 @@ In general, Crowbar does its best to ensure that code will not exhibit any of th
However, sometimes the compiler knows less than the programmer, and so code that looks dangerous is actually fine.
Crowbar allows programmers to suspend the memory safety checks with the `fragile` keyword.
-# Access errors
+## Access errors
-## Buffer overflow
+### Buffer overflow
Crowbar addresses buffer overflow with bounds checking.
In C, the type `char *` can point to a single character, a null-terminated string of unknown length, a buffer of fixed size, or nothing at all.
@@ -40,57 +38,57 @@ Note as well that the type of `argv` is complicated.
This is because the elements of `argv` have unconstrained size.
TODO figure out if that's the right way to handle that
-## Buffer over-read
+### Buffer over-read
bounds checking again
-## Race condition
+### Race condition
-uhhhhh 🤷‍♀️
+uhhhhh idk
-## Page fault
+### Page fault
bounds checking, dubious-pointer checking
-## Use after free
+### Use after free
`free(x);` not followed by `x = NULL;` is a compiler error.
`owned` and `borrowed` keywords
-# Uninitialized variables
+## Uninitialized variables
forbid them in syntax
-## Null pointer dereference
+### Null pointer dereference
dubious-pointer checking
-## Wild pointers
+### Wild pointers
dubious-pointer checking
-# Memory leak
+## Memory leak
-## Stack exhaustion
+### Stack exhaustion
-uhhhhhh 🤷‍♀️
+uhhhhhh idk
-## Heap exhaustion
+### Heap exhaustion
that counts as error handling, just the `malloc`-shaped kind
-## Double free
+### Double free
this is just use-after-free but the use is calling free on it
-## Invalid free
+### Invalid free
don't do that
-## Mismatched free
+### Mismatched free
how does that even happen
-## Unwanted aliasing
+### Unwanted aliasing
uhhh don't do that?
diff --git a/syntax.md b/syntax.md
index bf0d3f1..0ca25b3 100644
--- a/syntax.md
+++ b/syntax.md
@@ -1,10 +1,8 @@
----
-title: Syntax
----
+# Syntax
The syntax of Crowbar mostly matches the syntax of C, with fewer obscure/advanced/edge case features.
-# Source Files
+## Source Files
A Crowbar source file is UTF-8.
Crowbar source files can come in two varieties, an *implementation file* and a *header file*.
@@ -12,7 +10,7 @@ An implementation file conventionally has a `.cro` extension, and a header file
A Crowbar source file is read into memory in two phases: *scanning* (which converts text into an unstructured sequence of tokens) and *parsing* (which converts an unstructured sequence of tokens into a parse tree).
-# Scanning
+## Scanning
A *token* is one of the following kinds of token:
@@ -24,7 +22,7 @@ A *token* is one of the following kinds of token:
Tokens are separated by either *whitespace* or a *comment*.
-## Keywords
+### Keywords
A *keyword* is one of the following literal words:
@@ -59,7 +57,7 @@ A *keyword* is one of the following literal words:
- `void`
- `while`
-## Identifiers
+### Identifiers
An *identifier* is a sequence of one or more characters having Unicode categories within a legal set.
@@ -80,7 +78,7 @@ Subsequent characters may have any of the above-listed Unicode categories, or on
- `Nl` Letter Number (e.g. `Ⅳ`, U+2163 Roman Numeral Four)
- `No` Other Number (e.g. `¼`, U+00BC Vulgar Fraction One Quarter)
-## Constants
+### Constants
A *constant* can have one of six types:
@@ -94,7 +92,7 @@ A *constant* can have one of six types:
- or a `.` followed by a decimal constant followed by either an `e` or `E` followed by a decimal constant;
- or a *character constant*, a `'` followed by either a single character or an *escape sequence* followed by another `'`.
-### Escape Sequences
+#### Escape Sequences
The following sequences of characters are *escape sequences*:
@@ -109,13 +107,13 @@ The following sequences of characters are *escape sequences*:
- `\u` followed by four characters drawn from the set {`0`, `1`, `2`, `3`, `4`, `5`, `6`, `7`, `8`, `9`, `A`, `a`, `B`, `b`, `C`, `c`, `D`, `d`, `E`, `e`, `F`, `f`}
- `\U` followed by eight characters drawn from the set {`0`, `1`, `2`, `3`, `4`, `5`, `6`, `7`, `8`, `9`, `A`, `a`, `B`, `b`, `C`, `c`, `D`, `d`, `E`, `e`, `F`, `f`}
-## String Literals
+### String Literals
A *string literal* begins with a `"`.
It then contains a sequence where each element is either an escape sequence or a character that is neither `"` nor `\`.
It then ends with a `"`.
-## Punctuators
+### Punctuators
The following sequences of characters form *punctuators*:
@@ -161,11 +159,11 @@ The following sequences of characters form *punctuators*:
- `|=`
- `^=`
-## Whitespace
+### Whitespace
A nonempty sequence of characters is considered to be *whitespace* if each character in it has a Unicode class of either Space Separator or Control Other.
-## Comments
+### Comments
A *comment* can be either a *line comment* or a *block comment*.
@@ -173,11 +171,11 @@ A *line comment* begins with the characters `//` if they occur outside of a stri
A *block comment* begins with the characters `/*` if they occur outside of a string literal or comment, and ends with the characters `*/`.
-# Parsing
+## Parsing
The syntax of Crowbar is given as a [parsing expression grammar](https://en.wikipedia.org/wiki/Parsing_expression_grammar):
-## Entry points
+### Entry points
```
HeaderFile ← HeaderFileElement+
@@ -190,7 +188,7 @@ ImplementationFileElement ← HeaderFileElement /
FunctionDefinition
```
-## Top-level elements
+### Top-level elements
```
IncludeStatement ← 'include' string-literal ';'
@@ -211,7 +209,7 @@ SignatureArguments ← Type identifier ',' SignatureArguments /
Type identifier ','?
```
-## Statements
+### Statements
```
Block ← '{' Statement* '}'
@@ -263,7 +261,7 @@ AssignmentStatementBody ← AssignmentTargetExpression '=' Expression /
ExpressionStatement ← Expression ';'
```
-## Types
+### Types
```
Type ← 'const' BasicType /
@@ -288,7 +286,7 @@ IntegerType ← 'char' /
'long'
```
-## Expressions
+### Expressions
```
AssignmentTargetExpression ← identifier ATEElementSuffix*
diff --git a/tagged-unions.md b/tagged-unions.md
index 0083fff..256eebd 100644
--- a/tagged-unions.md
+++ b/tagged-unions.md
@@ -1,5 +1,3 @@
----
-title: Tagged Unions
----
+# Tagged Unions
TODO
diff --git a/types.md b/types.md
index 549cf0a..a86d937 100644
--- a/types.md
+++ b/types.md
@@ -1,5 +1,3 @@
----
-title: Types
----
+# Types
TODO
diff --git a/vs-c.md b/vs-c.md
index 926973c..116870a 100644
--- a/vs-c.md
+++ b/vs-c.md
@@ -1,14 +1,12 @@
----
-title: Comparison to C
----
+# Comparison to C
What differentiates Crowbar from C?
-# Removals
+## Removals
Some of the footguns and complexity in C come from misfeatures that can simply not be used.
-## Footguns
+### Footguns
Some constructs in C are almost always the wrong thing.
@@ -30,7 +28,7 @@ Some constructs in C exhibit implicit behavior that should instead be made expli
- The conditional operator `?:`
- Preprocessor macros (but constants are fine)
-## Needless Complexity
+### Needless Complexity
Some type modifiers in C exist solely for the purpose of enabling optimizations which most compilers can do already.
@@ -43,7 +41,7 @@ Some type modifiers in C only apply in very specific circumstances and so aren't
- `volatile`
- `_Imaginary`
-# Adjustments
+## Adjustments
Some C features are footguns by default, so Crowbar ensures that they are only used correctly.
@@ -60,15 +58,15 @@ However, sometimes it just sucks, and in those cases Crowbar makes changes.
- All string literals, char literals, etc are UTF-8
- Octal literals have a `0o` prefix (never `0O` because that looks nasty)
-# Additions
+## Additions
-## Anti-Footguns
+### Anti-Footguns
- C is generous with memory in ways that are unreliable by default.
Crowbar adds [memory safety conventions](safety.md) to make correctness the default behavior.
- C's conventions for error handling are unreliable by default.
Crowbar adds [error propagation](errors.md) to make correctness the default behavior.
-## Trivial Room For Improvement
+### Trivial Room For Improvement
- Binary literals, prefixed with `0b`/`0B`