7.7
Fulmar
1 standard-chunk
The standard chunks are intended to be the useful high-level forms available to
end users of Fulmar. They come for free when you use #lang fulmar.
1.1 empty*?
(: empty*? (Any -> Boolean))
Mostly a helper for other standard chunks. Takes anything as its input. If the
input is an empty list or a list of nested lists that are all empty, returns #t.
For ANY OTHER INPUT, returns #f.
1.2 if-empty
Macro of the form: (if-empty given then else)
Returns then, if given is null (or a list that flattens to null).
Returns else, otherwise.
1.3 surround
(: surround (Chunk Chunk -> Chunk))
Surrounds the second given chunk with copies of the first.
Useful if you need to make sure the President is always guarded by the Secret
Service:
(surround "SS" "president") => "SSpresidentSS"
1.4 blank-lines
(: blank-lines (Integer * -> Chunk))
Adds n blank lines.
Actually, you’ll notice that this function accepts any number of integers.
If you provide more than one, the numbers will be added together to produce
the number of blank lines that will be emitted. This might be useful if, for
example, you know you want 2 blank lines, then n more.
1.5 blank-line
Adds one blank line
1.6 sur-paren
(: sur-paren (Chunk * -> Chunk))
Surround a chunk in parenthesis. No, really! See:
(sur-paren "chunk") => "(chunk)"
It even works with multiple chunks:
(sur-paren "A" "chunk") => "(Achunk)"
1.7 sur-crbr
(: sur-crbr (Chunk * -> Chunk))
Surround a chunk in curly brackets. Same as sur-paren, but with these: {}
1.8 sur-anbr
(: sur-anbr (Chunk * -> Chunk))
Surround a chunk in angle brackets. Same as sur-paren, but with these: <>
If you need to surround a template list in pointy brackets, use
sur-anbr-template instead.
1.9 sur-anbr-template
(: sur-anbr-template (Chunk * -> Chunk))
Surround a chunk in angle brackets, carefully avoiding C++ parser problems.
This function is designed to avoid producing a ">>" at the end of the list.
Since the predominant use of an anble bracketed list in C++ is for templates,
and foo<bar<baz>> is a compiler error, this function works hard to produce
foo<bar<baz> > instead. If this is not what you need, consider using sur-anbr
instead.
1.10 sur-sqbr
(: sur-sqbr (Chunk * -> Chunk))
Surround a chunk in square brackets. Same as sur-paren, but with these: []
1.11 attach-list-separator
(: attach-list-separator (Chunk NestofChunks * -> (Listof Chunk)))
Takes a list separator chunk, and a list of chunks. Takes each chunk in the
list except the last and appends a copy of the separator chunk to it. The
result is a list of chunks with list separators. Before you consider using this
function directly, be sure you wouldn’t rather use between/attach.
(attach-list-separator ", " ‘(a b c d e)) => "a, b, c, d, e"
You can also give this function its list as a rest argument. It will take any
arguments after the first to be chunks that need separators:
(attach-list-separator ", " ‘a ’b ’c ’d ’e) => "a, b, c, d, e"
Note: This function flattens. So (attach-list-separator ’x ’(a b) ’c ’d) will
give "axbxcxd", NOT "abxcxd".
1.12 between
(: between (Chunk NestofChunks * -> Chunk))
Takes an add-between chunk, and a list of chunks. Concatenates given chunks
with add-between between each of the given chunks. Operates similarly to
attach-list-separator, but does not assume you want to keep the add-between
chunk paired with the preceding list chunk.
1.13 between/attach
(: between/attach (Chunk Chunk NestofChunks * -> Chunk))
Combines between and attach functionality to give a convenient way of making
multi-line lists or function bodies in an intelligent way. Takes a to-attach
chunk, an add-between chunk, and then a list of chunks to build into the list.
It then attaches the to-attach chunk to each chunk in the list using
attach-list-separator. Finally, it uses the between function to insert the
add-between chunk after each to-attach.
This function will work hard to do the Right Thing™ with lists or function
bodies. It tries, for example, to keep commas on the same line as the preceding
list element.
Assuming line-length was parameterized to a value of 10:
(between/attach "," space (range 8))
=>
"0, 1, 2, 3,"
"4, 5, 6, 7"
1.14 arg-list
(: arg-list ((Chunk -> Chunk) Chunk NestofChunks * -> Chunk))
Argument list chunk
Attempts to put chunks on a single line with a space between each chunk.
If that fails, puts chunks on their own lines. Commonly useful for lists and
arguments to functions. Handier than rolling something for this purpose by
hand.
1.15 paren-list
(: paren-list (NestofChunks * -> Chunk))
Parenthesis argument list chunk
Takes any list of chunks, separates them with commas, and surrounds the whole
list with parenthesis.
1.16 template-list
(: template-list (NestofChunks * -> Chunk))
Template argument list chunk
Takes any list of chunks, separates them with commas, and surrounds the whole
list with angle brackets.
1.17 body-list
(: body-list (Chunk NestofChunks * -> Chunk))
Takes a separator chunk and a list of chunks, separates the chunks with the
separator, and surrounds the whole thing with curly braces.
1.18 top-list
(: top-list (NestofChunks * -> Chunk))
Takes any number of chunks as arguments and inserts a blank line between each.
1.19 internal-smt-list
(: internal-smt-list (Chunk NestofChunks * -> Chunk))
List of statement chunks without final semi-colon.
Takes a spacing chunk and any number of chunks, adds spacing between each chunk
and attaches a semi-colon to the end of each chunk (except the last).
(internal-smt-list space ’a ’b ’c) => "a; b; c"
1.20 smt-list
(: smt-list (Chunk NestofChunks * -> Chunk))
Takes a spacing chunk and any number of chunks, adds spacing added between each
chunk and attaches a semi-colon to the end of each chunk.
(smt-list space ’a ’b ’c) => "a; b; c;"
1.21 constructor-assignment-list
(: constructor-assignment-list (NestofChunks * -> Chunk))
Constructor assignment list chunk
Creates an initializer list for a class constructor.
Each assignment is separated by a comma - first line is indented 2 spaces and
begun with a colon.
(constructor-assignment-list "a(other.a)" "b(other.b)" "c(other.c)" => " : a(other.a), b(other.b), c(other.c)"
(constructor-assignment-list (constructor-assignment ’a ’other.a)) => " : a(other.a)"
1.22 general-body
(: general-body (Boolean NestofChunks * -> Chunk))
General body chunk
Takes a boolean (use-semi-colons) and any number of chunks.
Surrounds chunks with curly brackets
- adds a semi-colon after each chunk, if use-semi-colons is true
- attempts to put chunks on a single line with a space between each chunk
- if that fails, puts chunks on their own lines with indented
This version places the open curly bracket immediately on current line and the
close curly bracket on its own line. This roughly corresponds to Java or
Google style, with attached brackets. The indent level is 3 spaces. This is not
currently user-configurable.
1.23 body
(: body (NestofChunks * -> Chunk))
Body with semicolons
Basically a shortcut for (general-body #true ...)
Surrounds chunks with curly brackets
- adds a semi-colon after each chunk
- attempts to put chunks on a single line with a space between each chunk
- if that fails, puts chunks on their own lines with indented
Style is the same as with general-body above.
1.24 class-body
(: class-body (NestofChunks * -> Chunk))
Body without semicolons
Basically a shortcut for (general-body #false ...)
Surrounds chunks with curly brackets
- does NOT add semi-colons after each chunk
- attempts to put chunks on a single line with a space between each chunk
- if that fails, puts chunks on their own lines with indented
Style is the same as with general-body above.
1.25 pp-define
(: pp-define (Chunk -> Chunk))
Preprocessor define chunk
Accepts one argument, a name. Produces:
#define <name>
1.26 pp-include
(: pp-include (Chunk -> Chunk))
Preprocessor include chunk
Accepts one argument, a header filename. Produces:
#include <<filename>>
Where the outer pointy brackets are literal.
1.27 pp-alt-include
(: pp-alt-include (Chunk -> Chunk))
Alternate preprocessor include chunk
Accepts one argument, a header filename. Produces:
#include "<filename>"
1.28 pp-includes
(: pp-includes (Chunk * -> Chunk))
Multiple includes
Accepts any number of arguments and produces an include directive for each.
1.29 pp-ifdef
(: pp-ifdef (Chunk -> Chunk))
Preprocessor if-defined chunk
Accepts one argument, a preprocessor ifdef condition, and makes an ifdef line.
1.30 pp-ifndef
(: pp-ifndef (Chunk -> Chunk))
Preprocessor if-not-defined chunk
Makes an ifndef preprocessor directive.
1.31 pp-else
Preprocessor else chunk
Makes an else preprocessor directive. Constant value, should not be called.
1.32 pp-endif
(: pp-endif (Chunk -> Chunk))
Preprocessor endif chunk
Makes an endif preprocessor directive. The argument will end up in a comment
on the same line as the endif, and can be used to specify what condition is
being endifed.
1.33 pp-conditional
(: pp-conditional (case-> [Chunk Chunk Chunk -> Chunk] [Chunk Chunk Chunk (U Chunk False) -> Chunk]))
Preprocessor conditional chunk
General preprocessor conditional block in a single handy package. Accepts 3
required arguments and one optional argument: directive, condition, then, else.
directive - the preprocessor command that comes right after the #.
condition - argument to the directive, following on the same line.
then - Chunk of code to be placed before the endif.
else - if present, chunk of code to go after an else, between then and endif.
Example: (pp-conditional ’ifdef ARM64 "do_arm64();" "reticulate_splines();")
1.34 pp-conditional-ifdef
(: pp-conditional-ifdef (case-> [Chunk Chunk -> Chunk] [Chunk Chunk (U False Chunk) -> Chunk]))
Preprocessor conditional ifdef chunk
Basically a shortcut for (pp-conditional ’ifdef ...)
Makes a preprocessor ifdef line with then and optional else bodies. Its 2
required arguments are the name of the define to check, and the ’then’ body.
The optional argument is an ’else’ body.
1.35 pp-conditional-ifndef
(: pp-conditional-ifndef (case-> [Chunk Chunk -> Chunk] [Chunk Chunk (U False Chunk) -> Chunk]))
Preprocessor conditional ifndef chunk
Basically a shortcut for (pp-conditional ’ifndef ...)
Makes a preprocessor ifndef line with then and optional else bodies. Its 2
required arguments are the name of the define to check, and the ’then’ body.
The optional argument is an ’else’ body.
1.36 pp-header-file
(: pp-header-file (Chunk NestofChunks * -> Chunk))
Preprocessor include guard / header file wrapper chunk
This is a pretty standard #include guard. Takes at least 1 argument: a name to
define (usually something like ’MY_HEADER_H). Further arguments will become the
body of the header file.
Example:
(pp-header-file ’FOO_STRUCT_H "struct foo { int member; };")
Produces:
#ifndef FOO_STRUCT_H
#define FOO_STRUCT_H
struct foo { int member; };
#endif
/* FOO_STRUCT_H */
1.37 macro-define
(: macro-define (Chunk NestofChunks Chunk -> Chunk))
Macro defintion chunk
General macro definition. Accepts at least one argument. The first will be the
name of the macro. Following arguments will become the definition of the macro.
Be careful, as it’s quite easy to create invalid code if your definition
contains newlines.
1.38 namespace-define
(: namespace-define (Chunk NestofChunks * -> Chunk))
Declare a namespace for a block of code.
Accepts a name and any number of further arguments. The name goes after the
namespace keyword, and the remaining arguments get put into a body which goes
in the namespace block. After the code block, a comment containing the name is
added to clarify what is being ended. Example:
(namespace-define ’foo "bar()") =>
namespace foo { bar(); } /* foo */
1.39 described-smts
(: described-smts (Chunk NestofChunks * -> Chunk))
Described statements chunk
Accepts a comment and any number of other chunks. Puts the comment into a
comment environment (surrounds it with /* */) and then places the remaining
arguments normally, after a newline. Example:
(described-smts "Automatically synchronize cardinal grammaters" "encabulate();") =>
/* Automatically synchronize cardinal grammaters */
encabulate();
1.40 constize
(: constize (Chunk -> Chunk))
Make constant
To be used with types or identifiers. Takes a type, identifier, or any chunk,
and appends const to the end of it.
(constize "int a") =>
int a const
1.41 template-define
(: template-define (NestofChunks Chunk -> Chunk))
Make a template with given template parameters
Takes two arguments: a list of parameters, and a name. Produces a template
declaration (sans the final semicolon).
Example:
(template-define ’(p1 p2 p3) ’MyTemplate) =>
template<p1, p2, p3>
MyTemplate
1.42 template-use
(: template-use (NestofChunks NestofChunks * -> Chunk))
Make use of a template
Takes a name and any number of template arguments. Produces a reference to the
given template with the given arguments. If only a name is given, no pointy
brackets are produced.
Example:
(template-use ’foo ’bar ’baaz) =>
foo<bar, baaz>
1.43 general-function-declare
(: general-function-declare (Chunk Chunk NestofChunks * -> Chunk))
General function declaration
Takes a name, a return type, and any number of additional arguments.
Example:
(general-function-declare ’foo ’bar "int baaz" "float quux") =>
bar foo(int baaz, float quux)
1.44 function-declare
(: function-declare (Chunk Chunk NestofChunks * -> Chunk))
Declares an inline function
This is exactly the same as general-function-declare except it makes the
declared function inline.
Example:
(function-declare ’foo ’bar "int baaz" "float quux") =>
inline bar foo(int baaz, float quux)
1.45 static-function-declare
(: static-function-declare (Chunk Chunk NestofChunks * -> Chunk))
Exactly the same as function-declare, but additionally declares the function
static.
Example:
(static-function-declare ’foo ’bar "int baaz" "float quux") =>
static inline bar foo(int baaz, float quux)
1.46 void-function-declare
(: void-function-declare (Chunk NestofChunks -> Chunk))
Declares an inline void function
Example:
(void-function-declare ’foo "int baaz") =>
inline void foo(int baaz)
1.47 function-define
(: function-define (Chunk NestofChunks * -> Chunk))
Takes a function signature, and any number of other chunks. Produces a function
definition consisting of the given signature, followed by a body with the
given chunks.
1.48 void-function-define
(: void-function-define (Chunk NestofChunks NestofChunks * -> Chunk))
Defines a void inline function. This is essentially a shortcut for using
function-define with a void-function-declare.
1.49 returning-function-define
(: returning-function-define (Chunk NestofChunks Chunk -> Chunk))
Takes a signature, a body, and a return expression. Produces a function
definition with the given signature and body. Appends a return statement with
the given return expression to the body.
Example:
(returning-function-define (function-declare ’id ’int "int x") ’() ’x) =>
inline int id(int x) { return x; }
1.50 constructor-assignment
(: constructor-assignment (Chunk NestofChunks * -> Chunk))
Creates an initializer (part of an initializer list) for a constructor.
The first argument is the variable to assign or the name of the constructor to
call, and successive arguments go in the parenthesis.
1.51 constructor
(: constructor (Chunk NestofChunks NestofChunks NestofChunks * -> Chunk))
Takes a name, a list of parameters, a list of constructor assignments, and any
number of other arguments and produces a constructor for a class.
Example:
(constructor ’foo ’("int bar" "float baaz")
(list (constructor-assignment ’qux ’bar)
(constructor-assignment ’quux ’bar ’baaz)) "x = qux + quux")
=>
foo(int bar, float baaz)
: qux(bar), quux(baaz)
{ x = qux + quux; }
1.52 struct-declare
(: struct-declare (Chunk -> Chunk))
Declare a struct with the given name. This is ONLY a declaration, and is not
intended to define the content of a struct.
Example:
(struct-declare ’foo)
=>
struct foo
1.53 template-struct-declare
(: template-struct-declare (Chunk NestofChunks NestofChunks * -> Chunk))
Declares a templated struct. Useful for making generic structs or partially
instantiated struct templates.
Example:
(template-struct-declare ’a ’(b c d) ’e ’f)
=>
template<b, c, d>
struct a<e, f>
1.54 section-define
(: section-define (Chunk NestofChunks * -> Chunk))
Produces a section definition, such as those used in class definitions to mark
groups of variables and methods as private, public, or protected.
Example:
(section-define ’private (smt-list new-line "int foo" "float bar"))
=>
private:
int foo;
float bar;
1.55 public-section
(: public-section (NestofChunks * -> Chunk))
A public section definition. The arguments are placed under a public: line.
(public-section c ...) can be thought of as a shortcut for (section-define
’public c ...)
1.56 private-section
(: private-section (NestofChunks * -> Chunk))
A private section definition. The arguments are placed under a private: line.
(private-section c ...) can be thought of as a shortcut for (section-define
’private c ...)
1.57 protected-section
(: protected-section (NestofChunks * -> Chunk))
A protected section definition. The arguments are placed under a protected: line.
(protected-section c ...) can be thought of as a shortcut for (section-define
’protected c ...)
1.58 struct-define
(: struct-define (Chunk NestofChunks * -> Chunk))
Takes a signature (which can come from struct-declare or
template-struct-declare) and any number of other chunks, and produces a struct
definition. The signature will become the type signature of the struct, while
the remaining arguments will become the body of the struct.
Example:
(struct-define (struct-declare ’foo) "int a;" "float b;")
struct foo {
int a;
float b;
}
1.59 template-struct-define
(: template-struct-define (Chunk NestofChunks NestofChunks NestofChunks * -> Chunk))
1.60 scope-resolution-operator
(: scope-resolution-operator (Chunk Chunk -> Chunk))
Takes a scope and an identifier and produces a chunk that will reference that
identifier in the context of that given scope.
Example:
(scope-resolution-operator ’std ’endl)
=>
std::endl
1.61 typedef-smt
(: typedef-smt (Chunk Chunk -> Chunk))
Typedef chunk. Accepts two chunks, lhs and rhs, and produces a typedef,
assigning rhs to be an equivalent type to lhs.
Example:
(typedef-smt ’FieldType ’Result)
=>
FieldType typedef Result
1.62 function-call
(: function-call (Chunk NestofChunks * -> Chunk))
Function call. Accepts the name of a function and any number of arguments to be
passed to it and produces a function call.
Example:
(function-call ’Ackermann 3 4)
=>
Ackermann(3, 4)
1.63 member-function-call
(: member-function-call (Chunk Chunk NestofChunks * -> Chunk))
Object member function call. Accepts some object, the name of a member function
in its class, and any number of arguments. Produces a member function call.
Example:
(member-function-call ’my-square ’scale 20 3)
=>
my-square.scale(20, 3)
Example 2:
(member-function-call (function-call ’getObject 6) ’id)
=>
getObject(6).id()
1.64 array-access
(: array-access (Chunk Chunk * -> Chunk))
Array access chunk. Accepts an array and any number of other arguments.
Produces an access to the array with the given arguments.
Example:
(array-access ’fib 5)
=>
fib[5]
2 type-decls
2.1 between-spaces
(: between-spaces ((Listof Chunk) -> Chunk))
2.2 NDBoolean
(define-type NDBoolean (U Boolean 'unspecified))
2.3 C++-base-type
(define-type C++-base-type (U C++-pointable-type Symbol))
2.4 C++-type-size
(define-type C++-type-size (U 'long 'short 'longlong))
2.5 C++-type-signedness
(define-type C++-type-signedness (U 'signed 'unsigned))
2.6 C++-type-qualifier
(define-type C++-type-qualifier (U 'const 'volatile))
2.7 C++-float-type
(define-type C++-float-type (U 'float 'double 'longdouble))
2.8 C++-type
(struct: C++-type ([base : C++-base-type]) #:transparent)
2.9 C++-qualified-type
(struct: C++-qualified-type C++-type ([qualifiers : (Listof C++-type-qualifier)]) #:transparent)
2.10 C++-pointable-type
(struct: C++-pointable-type C++-qualified-type () #:transparent)
2.11 C++-reference-type
(struct: C++-reference-type C++-qualified-type () #:transparent)
2.12 C++-pointer-type
(struct: C++-pointer-type C++-pointable-type () #:transparent)
2.13 C++-array-type
(struct: C++-array-type C++-pointable-type ([length : Chunk]) #:transparent)
2.14 C++-sizable-type
(struct: C++-sizable-type C++-pointable-type ([size : (Maybe C++-type-size)]) #:transparent)
2.15 C++-integer-type
(struct: C++-integer-type C++-sizable-type ([signedness : (Maybe C++-type-signedness)]) #:transparent)
2.16 C++-templated-type
(struct: C++-templated-type C++-pointable-type ([parameters : (Listof C++-type)]) #:transparent)
2.17 typ-float
(: typ-float (C++-type-qualifier * -> C++-pointable-type))
2.18 typ-double
(: typ-double (C++-type-qualifier * -> C++-pointable-type))
2.19 typ-long-double
(: typ-long-double (C++-type-qualifier * -> C++-sizable-type))
2.20 typ-int
(: typ-int ([#:size (U Null C++-type-size)] [#:sign (U Null C++-type-signedness)] C++-type-qualifier * -> C++-integer-type))
2.21 typ-char
(: typ-char ([#:sign (U Null C++-type-signedness)] C++-type-qualifier * -> C++-integer-type))
2.22 typ-pointer
(: typ-pointer (C++-pointable-type C++-type-qualifier * -> C++-pointer-type))
2.23 typ-reference
(: typ-reference (C++-pointable-type C++-type-qualifier * -> C++-reference-type))
2.24 typ-array
(: typ-array (C++-pointable-type Integer C++-type-qualifier * -> C++-array-type))
2.25 typ-template-type
(: typ-template-type (C++-base-type (U C++-type C++-type-qualifier) * -> C++-templated-type))
2.26 render-base-type
(: render-base-type (C++-base-type -> Chunk))
2.27 render-simple-type
(: render-simple-type (C++-qualified-type -> Chunk))
2.28 dcl-variable
(: dcl-variable ((U C++-type C++-base-type) Chunk -> Chunk))
2.29 dcl-type
(: dcl-type ((U C++-type C++-base-type) -> Chunk))
3 verify
4 fulmar-core
4.1 S-chunk
(struct: S-chunk () #:transparent)
4.2 Chunk
(define-type Chunk (U String Symbol Integer S-chunk))
4.3 NestofChunks
(define-type NestofChunks (Rec T (U (Listof T) Chunk)))
4.4 Newline
(struct: Newline S-chunk () #:transparent)
4.5 Space
(struct: Space S-chunk () #:transparent)
4.6 Immediate
(struct: Immediate S-chunk ([body : Chunk]) #:transparent)
4.7 Position-indent
(struct: Position-indent S-chunk ([body : Chunk]) #:transparent)
4.8 Concat
(struct: Concat S-chunk ([chunks : (Listof Chunk)]) #:transparent)
4.9 Comment
(struct: Comment S-chunk ([body : Chunk] [init-char : Char]) #:transparent)
4.10 Indent
(struct: Indent S-chunk ([body : Chunk] [length : Integer]) #:transparent)
4.11 Speculative
(struct: Speculative S-chunk ([attempt : Chunk] [success? : ((Listof String) -> Boolean)] [backup : Chunk]) #:transparent)
4.12 flatten*
(: flatten* (NestofChunks * -> (Listof Chunk)))
4.13 in-comment?
(: in-comment? (Parameterof Boolean))
4.14 make-whitespace
(: make-whitespace (Integer -> String))
4.15 remove-whitespace
(: remove-whitespace (String -> String))
4.16 is-whitespace?
(: is-whitespace? (String -> Boolean))
4.17 finish-line
(: finish-line (String -> String))
4.18 add-literal
(: add-literal (String String -> (Listof String)))
4.19 add-space
(: add-space (String -> (Listof String)))
4.20 add-concatenated
(: add-concatenated ((Listof Chunk) String -> (Listof String)))
4.21 add-speculative
(: add-speculative ((List Chunk ((Listof String) -> Boolean) Chunk) String -> (Listof String)))
4.22 write-chunk
(: write-chunk (case-> [Chunk -> (Listof String)] [Chunk String -> (Listof String)]))