-
Notifications
You must be signed in to change notification settings - Fork 5
Cpp Generator
The C++ Generator transforms typed terms into a C++ AST.
The main challenges are:
- a soundness theory - to refuse to generate invalid C++ programs (see Funarg Problem and other safety issues)
- a semantic theory - to establish a correspondense between C++ idioms and terms (hard parts are IO, assignments, imperative control, resource management including RAII, class members)
- an equational theory of terms - some terms can start generating invalid programs after seemingly equivalent transformations.
The easier but stil non-trivial to implement parts are:
- an idiomatic encoding of HOFs, local functions and polymorphism
- design of C++ AST
- design of actual encoding algorithm
Fortunately, the easier parts are already implemented.
Here are some ideas of how HN constructs are translated into C++ constructs:
Scopes -> Scopes or structures.
Function arguments -> Function arguments
Type variables -> Template typenames
Parametrized data types -> Template structures.
Top-level functions -> free functions.
Local functions -> static or non-static member functions.
Local variables -> non-static members or local variables.
Functions with free variables -> non-static member functions
Functions without free variables -> top-level functions or static member functions.
Polymorphic functions -> template functions.
We determine an encoding for each identifier, and then use the encoding both when identifier is declared and when it's used.
For definitions, identifier type is encoded in different fields of CppFunctionDef
(see Bar.ag
).
Conversion of identifier type into text is done in the pretty printer.
For expressions, each identifier is converted according to its type by an attribute grammar
during code generation phase (see AG\ExpressionBuilder.ag
, AG\Qualifiers.ag
,
CPP.Intermediate.CppQualifiers
and CPP.BackendTools
).
The pretty printer only assembles pieces of text instead of proper AST in case of expressions,
so the design should be improved at this place: more work should be moved to the pretty printer.
C++ AST is represented using CPP.Intermediate.CppDefinition
data type
data CppDefinition
= CppFunctionDef
{
functionLevel :: Int
, functionTemplateArgs :: [String]
, functionIsStatic :: Bool
, functionContext :: Maybe CppContext
, functionReturnType :: CppType
, functionName :: String
, functionArgs :: [CppVarDecl]
, functionLocalVars :: [CppLocalVarDef]
, functionRetExpr :: CppExpression
}
Here, functionLevel
is an indentation level used for pretty printing.
functionTemplateArgs
are formal template arguments for function templates. If the list
is empty, a definition is either a non-template function or a variable.
functionIsStatic
is only meaningful for defintions which are non-toplevel functions. It means
whether a function is static or non-static.
'a context' means 'a closure environment'. Implemented using the *_impl structure.
functionContext
contains the _impl struct
. May be present or not.
functionReturnType
is variable type for variables and function return type for functions.
functionName
is self-descriptive. Valid for both functions and variables.
functionArgs
contain function formal arguments. If empty, it means that the definition is
a variable.
functionLocalVars
mean local vars which are represented by C++ local variables. Some HN
local variables are represented by members of the context structure.
functionRetExpr
is self-descriptive.
data CppContext
= CppContext
{
contextLevel :: Int
, contextTemplateArgs :: [String]
, contextTypeName :: String
, contextVars :: [CppLocalVarDef]
, contextMethods :: CppProgram
, contextDeclareSelf :: Bool
, contextParent :: Maybe String
}
contextLevel
is same as functionLevel
contextTemplateArgs
means formal (and by coincidense actual) template arguments for the _impl structure.
contextTypeName
is the name of the struct (e.g. "foo_impl")
contextVars
are data members of the struct
contextMethods
are a list of methods of the struct
contextDeclareSelf
means whether typedef foo_impl self;
type declaration in the structure is necessary. It
is necessary if any method calls a static method.
contextParent
may contain a name of the parent _impl struct. It is not used yet, as the
"parent" functionality is the only place that is not yet complete. It should be used if a
context method calls a static method of a parent context.