cycpp

The cyclus preprocessor.

cycpp is a 3-pass preprocessor which adds reflection-like semantics to cyclus agents. This is needed to provide a high-level, user-facing API to cyclus. Code that uses cycpp is entirely valid C++ code and will compile normally even without first running it through the cycpp. This is because cycpp relies on custom #pragma decoration to annotate or inject into the code. These pragmas are skipped - by definition - by the C preprocessor and the C/C++ compiler.

The three passes of cycpp are:

  1. run cpp normally to canonize all other preprocessor directives,
  2. accumulate annotations for agents and state variables, and
  3. generate code based on annotations.

All decorators have the following form:

#pragma cyclus <decorator name> [args]

The #pragma cyclus portion is a flag so that only cycpp consumes this #directive. This is followed by the actual <decorator name> which tells cycpp what to do with this pragma. Lastly, optional arguments may be passed to this decorator but all options must be on the same logical line as the directive. How the arguments are interpreted is a function of the decorators themselves. Most of them are simple Python statements or expressions. See the following handy table!

Decorator Arguments:

var:Add the following C++ statement as an Agent’s state variable. There is one argument which must be a Python expression that evaluates to a dictionary or other Mapping.
exec:Executes arbitrary python code that is passed in as the arguments and loads this into the context. This is useful for importing handy modules, declaring variables for later use, or any of the other things that Python is great for. Any variables defined here are kept in a separate namespace from the classes. Since this gives you direct access to the Python interpreter, try to be a little careful.
note:Merges the argument (which like with var must evalutae to a dict) with the current class level annotations. Enrties here overwrite previous entries.

cycpp is implemented entirely in this file and with tools from the Python standard library. It requires Python 2.7+ or Python 3.3+ to run.

cycpp.escape_xml(s, ind=' ')

Escapes xml string s, prettifies it and puts in c++ string lit form.

cycpp.prepare_type(cpptype, othertype)

Updates othertype to conform to the length of cpptype using None’s.

cycpp.preprocess_file(filename, includes=(), cpp_path='cpp', cpp_args=('-xc++', '-pipe', '-E', '-DCYCPP'))

Preprocess a file using cpp.

Parameters:

filename : str

Name of the file you want to preprocess.

includes : list

A list of all include directories to tell the preprocessor about

cpp_path : str, optional

cpp_args : str, optional

Refer to the documentation of parse_file for the meaning of these arguments.

Notes

This was forked from pycparser: https://github.com/eliben/pycparser

class cycpp.Filter(machine=None, *args, **kwargs)

A basic, no-op filter.

isvalid(statement)

Checks if a statement is valid for this fliter.

transform(statement, sep)

Performs a transformation given this.

revert(statement, sep)

Reverts state transformation.

class cycpp.LinemarkerFilter(machine=None, *args, **kwargs)

Filter for computing the current source code line from preprocessor line marker directives.

# linenum filename [flags]

This is useful for debugging. See the cpp for more info: http://gcc.gnu.org/onlinedocs/cpp/Preprocessor-Output.html

class cycpp.AliasFilter(machine=None, *args, **kwargs)

Filter for managing alias (de-)scoping.

class cycpp.TypedefFilter(machine=None, *args, **kwargs)

Filter for handling typedef as aliases. Note that in-line compound typedefs of structs and unions are not supported.

class cycpp.UsingFilter(machine=None, *args, **kwargs)

Filter for accumumating using aliases.

class cycpp.NamespaceFilter(machine=None, *args, **kwargs)

Filter for accumumating namespace encapsulations.

class cycpp.UsingNamespaceFilter(machine=None, *args, **kwargs)

Filter for accumumating using namespace statement.

class cycpp.NamespaceAliasFilter(machine=None, *args, **kwargs)

Filter for accumumating namespace renames.

class cycpp.ClassFilter(machine=None, *args, **kwargs)

Filter for picking out class names.

class cycpp.ClassAndSuperclassFilter(machine=None, *args, **kwargs)

This accumulates superclass information as well as class information.

class cycpp.AccessFilter(machine=None, *args, **kwargs)

Filter for setting the current access control flag.

class cycpp.PragmaCyclusErrorFilter(machine=None, *args, **kwargs)

Filter for handling invalid #pragma cyclus. This should be the last filter.

isvalid(statement)

Checks if a statement is valid for this fliter.

class cycpp.DecorationFilter(machine=None, *args, **kwargs)

Abstract class for annotation accumulation.

class cycpp.VarDecorationFilter(machine=None, *args, **kwargs)

Filter for handling state variable decoration of the form:

#pragma cyclus var <dict>

This evals the contents of dict and puts them in state.var_annotations, to be consumed by the next match with VarDeclarationFilter.

class cycpp.VarDeclarationFilter(machine=None, *args, **kwargs)

State varible declaration. Only operates if state.var_annotations is not None. Access for member variable must be public.

canonize_alias(t, name, alias=None)

Computes the default alias structure for a C++ type for with the given state variable name.

canonize_tooltip(t, name, tooltip=None)

Computes the default tooltip structure for a C++ type for with the given state variable name.

canonize_uilabel(t, name, uilabel=None)

Computes the default uilabel structure for a C++ type for with the given state variable name.

class cycpp.ExecFilter(machine=None, *args, **kwargs)

Filter for executing arbitrary python code in the exec pragma and adding the results to the context. This pragma has the form:

#pragma cyclus exec <code>

Any Python statement(s) are valid as part of the code block. Be a little careful when using this pragma :).

class cycpp.NoteDecorationFilter(machine=None, *args, **kwargs)

Filter for handling annotation decoration of the form:

#pragma cyclus note <dict>

This evals the contents of dict and merges them in as the class-level annotations dict.

update(old, new)

Updates the new annotations dictionary into the old one in-place recursively.

class cycpp.StateAccumulator

The StateAccumulator class is the pass 2 state machine.

This represents the state of the file as it is being traversed. At the end of the traversal this will have acquired all of the information needed for pass 2. It manages both the decorators and other needed bits of C++ syntax. It works by passing each statement through a sequence of filters, and builds up or destroys context as it goes.

This class also functions as a typesystem for the types it sees.

classname()

Returns the current, fully-expanded class name.

ensure_class_context(classname)

Ensures that the context for the class at heand is well-formed.

accumulate(statement, sep)

Modify the existing state by incoprorating the statement, which is partitioned from the next statement by sep.

includeloc(statement=None)

Current location of the file from includes as a string.

canonize_type(t, name='<member variable>', statement=None)

Returns the canonical form for a type given the current state. This should not be called for types other than state variables. The name argument here is provided for debugging & reporting purposes.

canonize_shape(ann_dict)

This canonizes a shape. We take a look at the current shape, and standardize its format if necessary. We append -1’s to the shape if its length does not match our expected length. Returns the new shape or raises an error if the given shape was longer than expected.

canonize_class(cls, _usens=True)

This canonizes a classname. The class name need not be the current class whose scope we are in, but may be any class whatsoever. Returns None if the class could not be canonized.

cycpp.accumulate_state(canon)

Takes a canonical C++ source file and separates it out into statements which are fed into a state accumulator. The state is returned.

class cycpp.CloneFilter(*args, **kwargs)

Filter for handling Clone() code generation: #pragma cyclus [def|decl|impl] clone [classname]

class cycpp.InitFromCopyFilter(*args, **kwargs)

Filter for handling copy-constructor-like InitFrom() code generation: #pragma cyclus [def|decl|impl] initfromcopy [classname]

class cycpp.InitFromDbFilter(*args, **kwargs)

Filter for handling db-constructor-like InitFrom() code generation: #pragma cyclus [def|decl|impl] initfromdb [classname]

class cycpp.InfileToDbFilter(*args, **kwargs)

Filter for handling InfileToDb() code generation: #pragma cyclus [def|decl|impl] infiletodb [classname]

class cycpp.SchemaFilter(*args, **kwargs)

Filter for handling schema() code generation: #pragma cyclus [def|decl|impl] schema [classname]

xml_from_ctx(ctx, ind=' ')

Creates an XML string for an agent.

class cycpp.AnnotationsFilter(*args, **kwargs)

Filter for handling annotations() code generation: #pragma cyclus [def|decl|impl] annotations [classname]

class cycpp.SnapshotFilter(*args, **kwargs)

Filter for handling copy-constructor-like InitFrom() code generation: #pragma cyclus [def|decl|impl] snapshot [classname]

class cycpp.SnapshotInvFilter(*args, **kwargs)

Filter for handling SnapshotInv() code generation: #pragma cyclus [def|decl|impl] snapshotinv [classname]

class cycpp.InitInvFilter(*args, **kwargs)

Filter for handling InitInv() code generation: #pragma cyclus [def|decl|impl] initinv [classname]

class cycpp.DefaultPragmaFilter(machine=None, *args, **kwargs)

Filter for handling default pragma code generation: #pragma cyclus [def|decl|impl]

class cycpp.CodeGenerator(context, superclasses, filename=None)

The CodeGenerator class is the pass 3 state machine.

This represents the file as code is being injected into it. At the end of the traversal this final stage it will built up a brand new file for pass 3. It manages both the code insertion pragmas and other bits of C++ syntax as needed to determine locality. It works by passing each statement through a sequence of filters, and injects code based on the directive and the state.

classname()

Returns the current, fully-expanded class name.

ensure_class_context(classname)

Ensures that the context for the class at heand is well-formed.

includeloc(statement=None)

Current location of the file from includes as a string.

generate(statement, sep)

Modify the existing statements list by incoprorating, modifying, or ignoring this statement, which is partitioned from the next statement by sep.

cycpp.generate_code(orig, context, superclasses)

Takes a canonical C++ source file and separates it out into statements which are fed into a code generator. The new file is returned.

class cycpp.Proxy(d)

A proxy object for scoping purposes.

cycpp.outter_split(s, open_brace='(', close_brace=')', separator=', ')

Takes a string and only split the outter most level.

cycpp.parse_template(s, open_brace='<', close_brace='>', separator=', ')

Takes a string – which may represent a template specialization – and returns the corresponding type.

It calls parse_arg to return the type(s) for any template arguments the type may have. For example:

>>> parse_template('std::map<int, double>')
['std::map', 'int', 'double']
>>> parse_template('std::map<int, std::map<int, std::map<int, int> > >')
['std::map', 'int', ['std::map', 'int', ['std::map', 'int', 'int']]]
cycpp.parse_arg(s, open_brace='<', close_brace='>', separator=', ')

Takes a string containing one or more c++ template args and returns a list of the argument types as strings.

This is called by parse_template to handle the inner portion of the template braces. For example:

>>> parse_arg('int, double')
['int', 'double']
>>> parse_arg('std::map<int, double>')
[['std::map', 'int', 'double']]
>>> parse_arg('int, std::map<int, double>')
['int', ['std::map', 'int', 'double']]
cycpp.parent_intersection(classname, queryset, superclasses)

Returns all elements in query_set which are parents of classname and not parents of any other class in query_set

cycpp.insert_line_directives(newfile, filename)

Inserts line directives based on diff of original file.