diff options
-rw-r--r-- | .build.yml | 27 | ||||
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | LICENSE.md | 4 | ||||
-rw-r--r-- | Makefile | 52 | ||||
-rw-r--r-- | conf.py | 59 | ||||
-rw-r--r-- | errors.md | 4 | ||||
-rw-r--r-- | etc/gemtext.lua | 297 | ||||
-rw-r--r-- | etc/md.yml | 20 | ||||
-rw-r--r-- | etc/pdf.yml | 15 | ||||
-rw-r--r-- | etc/process-md.lua | 12 | ||||
-rw-r--r-- | etc/process-pdf.lua | 0 | ||||
-rw-r--r-- | etc/template.gmi | 1 | ||||
-rw-r--r-- | etc/template.html | 153 | ||||
-rw-r--r-- | index.md | 39 | ||||
-rw-r--r-- | index.rst | 30 | ||||
-rw-r--r-- | intro.rst | 47 | ||||
-rw-r--r-- | make.bat | 35 | ||||
-rw-r--r-- | safety.md | 40 | ||||
-rw-r--r-- | syntax.md | 36 | ||||
-rw-r--r-- | tagged-unions.md | 4 | ||||
-rw-r--r-- | types.md | 4 | ||||
-rw-r--r-- | vs-c.md | 18 |
22 files changed, 255 insertions, 643 deletions
@@ -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 @@ -1,3 +1,4 @@ /*.html /*.gmi /spec.pdf +/_build @@ -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/). @@ -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 @@ -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, +} @@ -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
@@ -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? @@ -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 @@ -1,5 +1,3 @@ ---- -title: Types ---- +# Types TODO @@ -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` |