Overview
Declarative level of Xreate

Transcend is a compilation phase and a process of reasoning about a program in order to influence final compilation results.

First, the compiler extracts annotations from a source code as well as other logic facts from a number of different sources. Second, logic facts are coupled with logic rules, that describe how to process input data, to form a complete logic program. Finally, a solver processes the logic program and produces decisions that affect and control compilation in a number of ways. Crucial difference of annotations from language keywords is that they do not have any predefined meaning and semantic; only custom developer provided rules make them matter.

Currently, an external logic solver Clasp is used to perform Transcend tasks. Hence, logic rules are written(and annotations are converted to) in the ASP format: one of standard first order logic notations.

Reasoning Solutions

Transcend prepares solutions to verify, control and guide compilation process. For each uncertain situation the compiler consults reasoning solutions to know how to proceed. Thus, many compilation aspects are delegated to Transcend and are ultimately exposed to a software developer. Transcend solution are used in a number of ways as follows:

  • Direct connection via the query built-in function. A program can request and explicitly process received data from Transcend as it sees fit.
  • Function level polymorphism. This is the principal way for Transcend to interfere in compilation. Polymorphism is based on a possibility for a function to have several specializations. Each time the function is invoked in a client code, Transcend decides which exactly specialization to call. This gives a deep control over final program behaviour.
  • Module level polymorphism. Transcend decides which modules to choose that satisfy a client code's requirements.
  • The compiler allows Transcend to add hidden parameters every time specific functions are invoked. This is implemented to support the Context concept.
  • Diagnostics. Transcend is able to validate different aspects of a program and print diagnostic messages to signal found inconsistencies.

As an example, suppose we want to control functions visibility and want to separate the visibility(private) functions from the rest of a program:

tests/transcend.cpp: Transcend.Doc_Diagnostics1
sum = function(a:: int, b:: int) ::      int; visibility(private)
{ 
  a + b
}

calculate = function(a:: int, b:: int):: int; visibility(pub_interface)
{
  sum(a, b)
}

test = function(a:: int, b:: int) ::     int; entry
{
   sum(a, b)       // we may not invoke this directly
}

Transcend converts the code above to logic facts as follows(the relevant part is shown):

function(sum)
function(calculate)
function(test)

bind_func(sum,visibility(private))
bind_func(calculate,visibility(pub_interface))
bind_func(test,entry)

cfa_parent(0,function(sum))
cfa_parent(1,function(calculate))
cfa_parent(2,function(test))

cfa_call(1,sum)
cfa_call(2,calculate)

At this point all the annotations are completely unknown to the compiler. Next, we need to write rules to check that the visibility(private) functions are called either by another visibility(private) ones or by the visibility(pub_interface) functions which are intended to act as a contact point, the only allowed gate between the private part and the rest of a program:

tests/transcend.cpp: Transcend.Doc_Diagnostics1
% Define which functiones are allowed to invoke private ones
allowed(
  visibility(private);
  visibility(pub_interface)
).

% Check every invocation for violations:
warning("Visibility violation", FuncFrom, FuncTo):-
  cfa_call(ScopeFrom, FuncTo); 
  bind_func(FuncTo, visibility(private));
  scope_func_dict(ScopeFrom, FuncFrom);
  { bind_func(FuncFrom, Visibility): allowed(Visibility) } 0.

Given the rules Transcend goes through all the invocations to check are there any possible visibility violations. For this example Transcend generates a diagnostic message: warning("Visibility violation",test,sum).

This way it is possible to validate and guide compilation process by analysing program properties employing provided processing rules.

Annotations' Syntax

Xreate's annotations comprise optional supplementary information to be processed by the compiler along with a source code proper with an end goal being to affect a compilation process. Annotations are special expressions in the following form:

LiteralsStrings, numbers. Example: 5, "success"
AtomsAtoms have zero or more arguments. Example: final(), status(broken), version("12.0.3", unstable)
NegationExample: -i12n, -access(allowed)
KeysExamples: `rev = `unstable("12.0.3")

Various Xreate's entities can be annotated. At the time following entities are supported:

Expressions

SYNTAX: expression :: type; annotation-list.
  • type The expression's type
  • annotation-list one or more annotations attached to the expression. Annotations are delimited by semicolon.

An example:

tests/transcend.cpp: Transcend.Doc_Expressions1
test = function:: int; entry
{
  x = 5:: int; arithmetic(fast).                           //an annotation applied to an identifier
  y = ((x - 8):: int; arithm_optimization(off)) * 2:: int. //an annotation applied to a nested expression
  
  x+y
}

For readability's sake compound statements(e.g. loops) have slightly different syntax for annotations. See particular statement's syntax for details.

NOTE: A current limitation is that expression's annotations are always preceded by a type, hence to annotate nested expressions it is necessary to duplicate the expression's type.

Code Blocks and Context

SYNTAX: context :: annotations-list.
  • annotations-list A list of annotations delimited by semicolon

Code block annotations are called context. The keyword context is reserved to declare annotations within an enclosing code block.

An example:

tests/transcend.cpp: Transcend.Doc_Codeblocks1
test = function:: int
{
  context:: arithm_optimization(off).

  x = 10 :: int.
  2 * x - 16
}

Special Annotations

Despite of "annotations do not have any predefined meaning" being a rule of thumb, still there are deviations in Xreate; few annotation that have special meaning are:

entrySpecifies the entry point of a program. See Function Syntax.
finalSpecifies the fixed point of loops. See Loops.

Annotations and Reasoning

Annotations is a mechanism to express additional pieces of information and can occur in a source code or accompanying files. They are of declarative nature in a sense that they express specific properties of and relations between different entities, such as: identifiers and expressions, statements, code blocks, functions, modules or even a whole program.

Annotations are explicit factsabout a source code provided by a code writer in an explicit form. Beside annotations, there are other sources of information, in other words, implicit facts that are automatically inferred by various analysis phases to express useful insights regarding an analysed code. Such pieces aren't exposed directly to a developer but accessed and used internally at the reasoning phase along with annotations. All types of input are summed up below:

Explicit annotationsAnnotations provided by a code writer in order to explicitly affect compilation.
Code analysisDifferent code analyses provide information implicitly inferred from a source code.
SupervisionExternal facts that reflect a hardware and/or an environment where compilation takes place or where a program is supposed to work. There are many supervision layers possible, from custom compiler's mode, to OS- or computer- or even network-wide levels. In other words, supervision covers local or client supplied annotations, e.g. prohibits web cam usage, or external network resources access.
AuditThird party supplied external information that reflects additional software properties, e.g. results of security audit.
Reasoning rulesReasoning infers additional facts from a pool of previously gathered information. It is done by using resoning rules that govern reasoning process.

Why Annotations Matter

This section goes through differences that annotations have over traditional statements.

Extensible

Annotations are not a part of language syntax and there is no predefined set of allowed annotations. A developer is free to define and use custom annotations to express desired properties without prior changes to the compiler.

Indicative Nature

Unlike language statements that have well defined compilation output, annotation do not. They are rather of suggestive nature and actual impact depends on many factors. Annotations comprise only an input for a reasoning procedure that ultimately decides how exactly to influence compilation.

Cooperation

Annotations are gathered from different sources enabling annotations to complement each other. The compiler blends in annotations originated from various sources seamlessly to improve decisions quality.

External Sources and Adaptability

Annotations can be used not only to express properties of a program itself but also properties of a local environment(OS, computer, local network) where the program is supposed to run. Thus, in fact, the compiler operates by information that is usually inaccessible during software development and can't be reflected in a program code otherwise. In essence, it is postcompilation - a process of adjustments to a particular environment and functioning mode.

Feedback

Traditionally software has a rigid strictly defined hierarchical structure of interaction between components. For example, let us focus on a client-service model. A service works the same regardless of a particular client in order to be compatible with as wide set of different clients as possible. However clients may use only small subset of service functionality or use it in a specific and predictable order. Generally speaking, the service in case of having additional information about a particular client is able to serve requests more efficiently in many situations.

It can be conceptualized as a feedback from a client. Annotations is a good candidate to express feedback to improve interaction quality.

Resiliency

As a program grows and goes through multiple reworks and rewrites many initial assumptions about the code and relation between different parts invalidated. Some implementation details and approaches became outdated and code quality deteriorates. A dIfferent picture is if the code uses annotations to express important properties. Any changes in an underlying code lead to a restarting of a reasoning procedure which adjust implementation decisions to be as optimal in a changed environment as before.