AST API

In order to reason about program, code model is translated into form suited for processing by Transcend. Translation details are described below.

Expression Annotations: 'bind'

SYNTAX: bind(symbol-ref, annotation)
  • symbol-ref reference to the expression or identifier
  • annotation expression's annotation

Declares expression's annotations.

Example:

tests/transcend-ast.cpp: ASTCorrespondence.Doc_BasicTests
test = function:: int 
{
  x = 5::         int; expected(even_number).

  x
}

gets translated into:

bind(s(1,-2,0),expected(even_number))

Code Block: 'scope'

SYNTAX: scope(scope-ref)
  • scope-ref reference to the code block

Declares code block under its unique reference identifier.

Example:

tests/transcend-ast.cpp: ASTCorrespondence.Doc_BasicTests
test = function:: float
{
  x = 3::       float.
  y = 8::       float. 

  x + y 
}

Translation result: scope(0)

Code Block Annotations: 'bind_scope'

WARNING: Pending syntax changes
SYNTAX: bind_scope(scope-ref, annotation, strong) (1) bind_scope(scope-ref, annotation, weak(..)) (2)
  • scope-ref child block's reference
  • annotation code block's annotation

Declares code block's annotations called context. There are two forms for different context' type:

  • strong context known at compile time
  • weak possible context, can't be decided for sure at compile time

Example:

tests/transcend-ast.cpp: ASTCorrespondence.Doc_BasicTests
test = function:: float
{
  context::       arithmetic(fast).

  x = 3::         float.
  y = 8::         float. 

  x + y 
}

Translation's result:

bind_scope(0,arithmetic(fast),strong)

Code Block Bindings: 'ast_scope_binding'

SYNTAX: ast_scope_binding(scope-ref, binding-id, binding-alias)
  • scope-ref code block's reference
  • binding-id number of code block's binding
  • binding-alias name of a binding

Code blocks have zero or more bindings, i.e. Identifiers that have special meaning within the block. Predicate declares such code block's bindings. Bindings organized into ordered list. Order is conveyed by specifying binding-id for each binding-alias.

Example:

tests/transcend-ast.cpp: ASTCorrespondence.Doc_BasicTests
test = function::     int
{
  loop ( 0 -> acc ):: int 
  {
    if(acc > 10):: int {acc:: int; final} else {acc + 1}
  }
}

Translation result: ast_scope_binding(1,0,"acc")

Code Block Parents: 'cfa_parent'

SYNTAX: cfa_parent(scope-ref, scope(scope-parent-ref))
  • scope-ref child block's reference
  • scope-parent-ref parent block's reference

Represents nested code blocks structure in terms of child-parent relation.

Example:

tests/transcend-ast.cpp: ASTCorrespondence.Doc_BasicTests
test = function:: int
{
  x = 19::        int.

  if (x>5):: int {x + 1} else {x - 1}
}

Translation's result:

cfa_parent(1, scope(0)).
cfa_parent(2, scope(0)).

Function: 'function'

SYNTAX: function(fn-name)
  • fn-name function name

Declares function identified by its name.

Example:

tests/transcend-ast.cpp: ASTCorrespondence.Doc_BasicTests
test = function:: int {0}

Translation's result: function("test")

Function's Annotations: 'bind_func'

SYNTAX: bind_func(fn-name, annotation)
  • fn-name function's name

Declares function's annotations.

Example:

tests/transcend-ast.cpp: ASTCorrespondence.Doc_BasicTests
test = function:: int; status(obsolete) {0}

Translation's result: bind_func("test",status(obsolete))

Function's Specialization: 'cfa_function_specializations'

SYNTAX: cfa_function_specializations(fn-name, guard)
  • fn-name name of function
  • guard specialization guard

There is a possibility to have several functions with the same name called specializations. Each specialization is uniquely determined by annotation of special kind called guard.

Example:

tests/transcend-ast.cpp: ASTCorrespondence.Doc_BasicTests
guard::             arch(amd64) 
{
  test = function:: i64 {0}
}

Translation's result: cfa_function_specializations("test",arch(amd64))

NOTE: See also specializations syntax

Function's Entry: 'cfa_parent'

SYNTAX: cfa_parent(scope-entry-ref, functon(fn-name))
  • scope-entry-ref function's entry code block reference
  • fn-name function's name

Each function has a single entry code block and is declared in terms of child-parent relation between entry block(which is top-level in blocks hierarchy of the given function) and the function itself.

Example:

tests/transcend-ast.cpp: ASTCorrespondence.Doc_BasicTests
test = function:: int {0}

Translation's result: cfa_parent(0,function("test"))

Function's Result: 'dfa_fnret'

SYNTAX: dfa_fnret(fn-name, symbol-ret-ref)
  • symbol-ret-ref reference to a function's return expression

Specifies which expression is used to compute function's return value.

Example:

tests/transcend-ast.cpp: ASTCorrespondence.Doc_BasicTests
test = function:: int {0}

Translation's result: dfa_fnret("test",s(0,-2,0))

Operations. Invocation: 'cfa_call', 'dfa_callfn', 'dfa_callargs'

SYNTAX: cfa_call(scope-caller-ref, fn-callee-name) (1) dfa_callfn(symbol-ref, fn-callee-name) (2) dfa_callargs(symbol-ref, arg-formal-name, arg-actual-ref) (3) weak(dfa_callargs(symbol-ref, arg-formal-name, arg-actual-ref)) (4)
  • scope-caller-ref caller's code block's reference
  • fn-callee-name callee function name
  • symbol-ref invocation operation reference
  • arg-formal-name function's formal argument
  • arg-actual-ref actual argument reference

Each function invocation is transformed into several transcend facts as explained below:

(1) cfa_callSpecifies caller's code block and callee function name
(2) dfa_callfnDeclares unique reference to a particular invocation site.The reference used by other facts to supply additional information
(3) dfa_callargsDeclares assignment relations between actual arguments and formal arguments
(4) weak(dfa_callargs)The same as form (3). Weak relation used in cases when there is no enough information at compile time. One such case is when several function specializations exist and it's impossible to say which exactly specialization is called

Example:

tests/transcend-ast.cpp: ASTCorrespondence.Doc_BasicTests
inc  = function (x::int)::  int 
{
  x + 1
}

main = function::           int 
{
  arg = 10::                int.
  inc(arg)
}

After translation following transcend facts are present:

cfa_call(1,"inc")
dfa_callfn(s(0,-2,1),"inc")
weak(dfa_callargs(s(0,-2,1),s(1,-2,0),s(1,-2,1)))
dfa_callargs(s(0,-2,1),s(1,-2,0),s(1,-2,1))

Operations. Loops

ast_op_map(symbol-result-ref, symbol-source-ref, loop-body-ref) ast_op_fold(symbol-result-ref, symbol-source-ref, symbol-acc-ref, loop-body-ref)
  • symbol-source-ref input list reference
  • symbol-acc-ref accumulator reference
  • symbol-result-ref result list reference
  • loop-body-ref refers to a loop body expression

Facts declare loop operations.

Example:

tests/transcend-ast.cpp: ASTCorrespondence.Doc_BasicTests
test = function::       int; entry 
{
  singles = {1, 2, 3}:: [int].
  doubles = loop map(singles->element:: int)::[int] {2 * element}.
  doubles[0]
}

produces fact: ast_op_map(s(2,-2,0),s(1,-2,0),s(0,-2,1))