From 8868b5fa2e8b9f40a31035c51519cce40e73f079 Mon Sep 17 00:00:00 2001 From: Melody Horn Date: Mon, 2 Nov 2020 13:37:32 -0700 Subject: define compile-time vs runtime behavior --- .editorconfig | 1 + _ext/crowbar_domain.py | 2 +- _ext/gemtext_builder.py | 30 ++++++++--------- index.rst | 2 +- language/functions.rst | 30 +++++++++++++---- language/include.rst | 7 +++- language/index.rst | 3 +- language/scanning.rst | 24 +++++++------- language/source-file.rst | 4 +-- language/statements/index.rst | 23 +++++++++++++ language/statements/structure.rst | 21 ++++++++++++ language/statements/variables.rst | 24 ++++++++++++++ language/type-definition.rst | 12 +++++-- make.bat | 70 +++++++++++++++++++-------------------- safety.rst | 2 +- syntax.md | 20 ++--------- vs-c.rst | 2 +- 17 files changed, 181 insertions(+), 96 deletions(-) create mode 100644 language/statements/index.rst create mode 100644 language/statements/structure.rst create mode 100644 language/statements/variables.rst diff --git a/.editorconfig b/.editorconfig index f4dfbaa..f7a7f0f 100644 --- a/.editorconfig +++ b/.editorconfig @@ -6,6 +6,7 @@ insert_final_newline = true indent_style = space indent_size = 4 charset = utf-8 +trim_trailing_whitespace = true [Makefile] indent_style = tab diff --git a/_ext/crowbar_domain.py b/_ext/crowbar_domain.py index 619487d..673f756 100644 --- a/_ext/crowbar_domain.py +++ b/_ext/crowbar_domain.py @@ -52,7 +52,7 @@ class ElementDirective(ObjectDescription): else: peg_rule += addnodes.desc_sig_operator('', '', nodes.literal(text=token)) return element - + def add_target_and_index(self, name, sig, signode): signode['ids'].append('element' + '-' + name) if 'noindex' not in self.options: diff --git a/_ext/gemtext_builder.py b/_ext/gemtext_builder.py index c26b053..9c7326d 100644 --- a/_ext/gemtext_builder.py +++ b/_ext/gemtext_builder.py @@ -14,7 +14,7 @@ class GemtextWriter(writers.Writer): def __init__(self, builder): super().__init__() self.builder = builder - + def translate(self): visitor = self.builder.create_translator(self.document, self.builder) self.document.walkabout(visitor) @@ -33,25 +33,25 @@ class GemtextTranslator(SphinxTranslator): if self.current_line != '': self.body.append(self.current_line) self.current_line = '' - + def visit_document(self, node: nodes.document): self.heading_level = 1 self.current_line = '' self.body = [] self.literal = False self.pending_links = [] - + def depart_document(self, node: nodes.document): self._finish_line() - + def visit_section(self, node: nodes.section): self.heading_level += 1 if len(self.body) > 0 and self.body[-1] != '': self.body.append('') - + def depart_section(self, node: nodes.section): self.heading_level -= 1 - + def visit_title(self, node: nodes.title): pass @@ -65,7 +65,7 @@ class GemtextTranslator(SphinxTranslator): if not self.literal: text = text.replace('\n', ' ') self.current_line += text - + def depart_Text(self, node: nodes.Text): pass @@ -95,7 +95,7 @@ class GemtextTranslator(SphinxTranslator): self.body.append('=> {} {}'.format(node.attributes['uri'], node.attributes['alt'])) else: raise NotImplementedError('inline images') - + def depart_image(self, node: nodes.image): pass @@ -104,12 +104,12 @@ class GemtextTranslator(SphinxTranslator): def visit_strong(self, node: nodes.strong): self.current_line += '**' - + depart_strong = visit_strong def visit_emphasis(self, node: nodes.emphasis): self.current_line += '_' - + depart_emphasis = visit_emphasis def visit_target(self, node: nodes.target): @@ -165,16 +165,16 @@ class GemtextTranslator(SphinxTranslator): self.body.append('```') self.body.append('') self.literal = False - + def visit_index(self, node: nodes.Node): pass - + def depart_index(self, node: nodes.Node): pass def visit_desc(self, node: nodes.Node): pass - + def depart_desc(self, node: nodes.Node): pass @@ -250,10 +250,10 @@ class GemtextBuilder(Builder): def get_outdated_docs(self): yield from self.env.found_docs # can't be fucked to implement this right yield 'genindex' - + def get_target_uri(self, docname: str, typ: str = None): return docname + '.gmi' - + def prepare_writing(self, docnames: Set[str]): self.writer = GemtextWriter(self) diff --git a/index.rst b/index.rst index 92e9a4d..8155b3c 100644 --- a/index.rst +++ b/index.rst @@ -48,7 +48,7 @@ Chapters ======== .. toctree:: - :maxdepth: 1 + :maxdepth: 2 :numbered: vs-c diff --git a/language/functions.rst b/language/functions.rst index 86d1144..22a61a3 100644 --- a/language/functions.rst +++ b/language/functions.rst @@ -3,18 +3,36 @@ Functions .. crowbar:element:: FunctionDeclaration <- FunctionSignature ';' - A function declaration defines the return type, name, and arguments of a function without specifying its behavior. - It is generally used as part of an API boundary. + Compile-time Behavior: + + Provides a declaration of a function with the name, return type, and arguments specified by the signature, but does not specify any behavior. + This is generally used as part of an API boundary. + + Runtime Behavior: + + A function declaration has no runtime behavior. .. crowbar:element:: FunctionDefinition <- FunctionSignature Block - A function definition provides the actual behavior of a function, which may have been declared previously or may not. + Compile-time Behavior: + + Provides the actual behavior of a function, which may have been declared previously or may not. + If the function was declared in some ``.hro`` file which was :crowbar:ref:`include `\ d, the function must be exported and available for external use in the compiler's output. + Otherwise, the function should not be exported. + + If the function signature specifies a return type other than ``void``, but there are paths through the block that do not execute a :crowbar:ref:`ReturnStatement`, the compiler must give an error. - .. todo:: + Runtime Behavior: - define function linkage/exportedness + When the function is called, the arguments must be populated and the block must be executed. .. crowbar:element:: FunctionSignature <- Type identifier '(' SignatureArguments? ')' SignatureArguments <- Type identifier (',' Type identifier)* ','? - + + Compile-time Behavior: + A function signature specifies the return type, name, and arguments of a function. + + Runtime Behavior: + + A function signature has no runtime behavior. diff --git a/language/include.rst b/language/include.rst index cc2964a..4667a49 100644 --- a/language/include.rst +++ b/language/include.rst @@ -3,5 +3,10 @@ Including Headers .. crowbar:element:: IncludeStatement <- 'include' string-literal ';' + Compile-time Behavior: + When encountering this statement at the beginning of a file, the compiler should interpret the string literal as a relative file path, look up the corresponding file in an implementation-defined way, and load the definitions from the given :crowbar:ref:`HeaderFile`. - This statement has no runtime effect. + + Runtime Behavior: + + This statement has no runtime behavior. diff --git a/language/index.rst b/language/index.rst index 66492a9..e1e2b01 100644 --- a/language/index.rst +++ b/language/index.rst @@ -13,9 +13,10 @@ Syntax elements in this document are given in the form of `parsing expression gr .. toctree:: :maxdepth: 1 - + scanning source-file include type-definition functions + statements/index diff --git a/language/scanning.rst b/language/scanning.rst index 3ed9bfe..a141b41 100644 --- a/language/scanning.rst +++ b/language/scanning.rst @@ -13,18 +13,18 @@ Scanning keyword One of the literal words ``bool``, ``break``, ``case``, ``char``, ``const``, ``continue``, ``default``, ``do``, ``double``, - ``else``, ``enum``, ``extern``, ``float``, ``for``, ``fragile``, + ``else``, ``enum``, ``extern``, ``false``, ``float``, ``for``, ``fragile``, ``function``, ``if``, :crowbar:ref:`include `, ``int``, ``long``, ``opaque``, ``return``, - ``short``, ``signed``, ``sizeof``, ``struct``, ``switch``, ``union``, + ``short``, ``signed``, ``sizeof``, ``struct``, ``switch``, ``true``, ``union``, ``unsigned``, ``void``, or ``while``. - + identifier A nonempty sequence of characters blah blah blah .. todo:: figure out https://www.unicode.org/reports/tr31/tr31-33.html - + constant A numeric (or numeric-equivalent) value specified directly within the code. May be a :term:`decimal constant`, a :term:`binary constant` , an :term:`octal constant`, @@ -50,12 +50,12 @@ Scanning floating-point constant A sequence of characters matching the regular expression ``[0-9_]+\.[0-9_]+([eE][+-]?[0-9_]+)?``. - + .. note:: Unlike in C and many other languages, ``6e3`` in Crowbar is not a valid floating-point constant. The Crowbar-compatible spelling is ``6.0e3``. - + Denotes the numeric value of the given decimal number, optionally expressed in scientific notation. That is, ``XeY`` denotes :math:`X * 10^Y`. @@ -63,12 +63,12 @@ Scanning A sequence of characters matching the regular expression ``0(fx|FX)[0-9a-fA-F_]+\.[0-9a-fA-F_]+[pP][+-]?[0-9_]+``. Denotes the numeric value of the given hexadecimal number expressed in binary scientific notation. That is, ``XpY`` denotes :math:`X * 2^Y`. - + character constant A pair of single quotes ``'`` surrounding either a single character or an :term:`escape sequence`. The single character may not be a single quote or a backslash ``\``. Denotes the Unicode scalar value for either the single surrounded character or the character denoted by the escape sequence. - + escape sequence One of the following pairs of characters: @@ -79,7 +79,7 @@ Scanning * ``\n``, denoting the line feed, or newline (U+000A) * ``\t``, denoting the (horizontal) tab (U+0009) * ``\0``, denoting a null character (U+0000) - + Or a sequence of characters matching one of the following regular expressions: * ``\\x[0-9a-fA-F]{2}``, denoting the numeric value of the given two hexadecimal digits @@ -101,13 +101,13 @@ Scanning whitespace A nonempty sequence of characters that each has a Unicode general category of either Control (``Cc``) or Separator (``Z``). Separates tokens. - + comment Text that the compiler should ignore. May be a :term:`line comment` or a :term:`block comment`. - + line comment A sequence of characters beginning with the characters ``//`` (outside of a :term:`string literal` or :term:`comment`) and ending with a newline character U+000A. - + block comment A sequence of characters beginning with the characters ``/*`` (outside of a :term:`string literal` or :term:`comment`) and ending with the characters ``*/``. diff --git a/language/source-file.rst b/language/source-file.rst index 2fc3ba0..162bb88 100644 --- a/language/source-file.rst +++ b/language/source-file.rst @@ -2,14 +2,14 @@ Source Files ------------ .. crowbar:element:: HeaderFile <- IncludeStatement* HeaderFileElement+ -.. crowbar:element:: HeaderFileElement <- TypeDefinition / FunctionDeclaration / ConstantDefinition / VariableDeclaration + HeaderFileElement <- TypeDefinition / FunctionDeclaration / ConstantDefinition / VariableDeclaration A Crowbar header file defines an API boundary, either at the surface of a library or between pieces of a library or application. :crowbar:ref:`IncludeStatement`\ s can only appear at the beginning of the header file, and header files cannot define behavior directly. Conventionally, a header file has a ``.hro`` file extension. .. crowbar:element:: ImplementationFile <- IncludeStatement* ImplementationFileElement+ -.. crowbar:element:: ImplementationFileElement <- TypeDefinition / VariableDefinition / FunctionDefinition + ImplementationFileElement <- TypeDefinition / VariableDefinition / FunctionDefinition A Crowbar implementation file defines the actual behavior of some piece of a library or application. It can also define internal types, functions, and variables. diff --git a/language/statements/index.rst b/language/statements/index.rst new file mode 100644 index 0000000..38bfbb1 --- /dev/null +++ b/language/statements/index.rst @@ -0,0 +1,23 @@ +Statements +---------- + +.. crowbar:element:: Block <- '{' Statement* '}' + + Compile-time Behavior: + + A block is a possibly-empty sequence of statements surrounded by curly braces. + Any declaration or definition within the block must not be visible outside of the block. + + Runtime Behavior: + + When a block is executed, each of the containing statements, in linear order, is executed. + +.. crowbar:element:: Statement <- VariableDefinition / StructureStatement / FlowControlStatement / AssignmentStatement / FragileStatement / ExpressionStatement + + Crowbar has many different types of statement. + +.. toctree:: + :maxdepth: 1 + + variables + structure diff --git a/language/statements/structure.rst b/language/statements/structure.rst new file mode 100644 index 0000000..9330bf6 --- /dev/null +++ b/language/statements/structure.rst @@ -0,0 +1,21 @@ +Structure Statements +^^^^^^^^^^^^^^^^^^^^ + +.. crowbar:element:: StructureStatement <- IfStatement / SwitchStatement / WhileStatement / DoWhileStatement / ForStatement + + A structure statement creates some nonlinear control structure. + There are several types of these structures. + +.. crowbar:element:: IfStatement <- 'if' '(' Expression ')' Block ('else' Block)? + + An if statement allows some action to be performed only sometimes, based on the value of the expression. + + Compile-time Behavior: + + If the expression does not have type bool, the compiler must emit an error. + + Runtime Behavior: + + First, the expression is evaluated. + If the expression evaluates to a ``bool`` value of ``true``, then the first block will be executed. + If the expression evaluates to a ``bool`` value of ``false``, either the second block is executed or nothing is executed. diff --git a/language/statements/variables.rst b/language/statements/variables.rst new file mode 100644 index 0000000..6bc1a6f --- /dev/null +++ b/language/statements/variables.rst @@ -0,0 +1,24 @@ +Variables +^^^^^^^^^ + +.. crowbar:element:: VariableDeclaration <- Type identifier ';' + + Compile-time Behavior: + + A variable declaration specifies the type and name of a variable but not its initial value. + This is only used in :crowbar:ref:`HeaderFile`\ s as part of API boundaries. + + Runtime Behavior: + + A variable declaration has no runtime behavior. + +.. crowbar:element:: VariableDefinition <- Type identifier '=' Expression ';' + + Compile-time Behavior: + + A variable definition specifies the type, name, and initial value of a variable. + If the expression has a type which is not the type specified for the variable, an error must be emitted. + + Runtime Behavior: + + When a variable definition is executed, the expression is evaluated, and its result is made available with the given name. diff --git a/language/type-definition.rst b/language/type-definition.rst index b596d0a..9e3d7c4 100644 --- a/language/type-definition.rst +++ b/language/type-definition.rst @@ -5,6 +5,14 @@ Defining Types Crowbar has three different kinds of user-defined types. + Compile-time Behavior: + + When a type is defined, the compiler must then allow that type to be used. + + Runtime Behavior: + + The definition of a type has no runtime behavior. + .. crowbar:element:: StructDefinition <- NormalStructDefinition / OpaqueStructDefinition NormalStructDefinition <- 'struct' identifier '{' VariableDeclaration+ '}' @@ -25,7 +33,7 @@ Defining Types An ``enum`` defines a type which can take one of several specified values. .. todo:: - + define enum value assignment, type-related behavior .. crowbar:element:: UnionDefinition <- RobustUnionDefinition / FragileUnionDefinition @@ -65,7 +73,7 @@ Defining Types case Whitespace: ; } } - + defines a ``union Token`` type, where the ``type`` field controls which of the other fields in the union is valid. .. todo:: diff --git a/make.bat b/make.bat index 2119f51..922152e 100644 --- a/make.bat +++ b/make.bat @@ -1,35 +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 +@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.rst b/safety.rst index 61cca97..6a73b85 100644 --- a/safety.rst +++ b/safety.rst @@ -58,7 +58,7 @@ Use after free -------------- ``free(&x);`` will set ``x = NULL;`` -``owned`` and ``borrowed`` keywords +``owned`` and ``borrowed`` keywords Uninitialized variables ======================= diff --git a/syntax.md b/syntax.md index e6ec9f1..b8e4554 100644 --- a/syntax.md +++ b/syntax.md @@ -3,31 +3,15 @@ ### Statements ```PEG -Block ← '{' Statement* '}' - -Statement ← VariableDefinition / - VariableDeclaration / - IfStatement / - SwitchStatement / - WhileStatement / - DoWhileStatement / - ForStatement / - FlowControlStatement / - AssignmentStatement / - ExpressionStatement - -VariableDefinition ← Type identifier '=' Expression ';' -VariableDeclaration ← Type identifier ';' - IfStatement ← 'if' Expression Block 'else' Block / 'if' Expression Block - + SwitchStatement ← 'switch' Expression '{' SwitchCase+ '}' SwitchCase ← CaseSpecifier Block / 'default' Block CaseSpecifier ← 'case' Expression ',' CaseSpecifier / 'case' Expression ','? - + WhileStatement ← 'while' Expression Block DoWhileStatement ← 'do' Block 'while' Expression ';' ForStatement ← 'for' VariableDefinition? ';' Expression ';' AssignmentStatementBody? Block diff --git a/vs-c.rst b/vs-c.rst index 8317155..42f8a38 100644 --- a/vs-c.rst +++ b/vs-c.rst @@ -70,7 +70,7 @@ Additions Anti-Footguns ------------- -* C is generous with memory in ways that are unreliable by default. +* C is generous with memory in ways that are unreliable by default. Crowbar adds :doc:`memory safety conventions ` to make correctness the default behavior. * C's conventions for error handling are unreliable by default. Crowbar adds :doc:`error propagation ` to make correctness the default behavior. -- cgit v1.2.3