diff --git a/documentation-tools/doc-converter/doctl b/documentation-tools/doc-converter/doctl index 1de5c7d..b236c91 100755 --- a/documentation-tools/doc-converter/doctl +++ b/documentation-tools/doc-converter/doctl @@ -1,61 +1,62 @@ #!/bin/bash PANDOC=/opt/pandoc/dist-newstyle/build/x86_64-linux/ghc-8.6.4/pandoc-2.7.1/x/pandoc/build/pandoc/pandoc REMOTE='xreate@xreate.bigserver' DOC_CONTENT=( 'documentation/Transcend/transcend.xml' 'documentation/Transcend/ast-api.xml' 'documentation/Transcend/latetranscend.xml' 'documentation/Transcend/modules-api.xml' 'documentation/Transcend/latex-api.xml' 'documentation/Concepts/interpretation.xml' 'documentation/Concepts/containers.xml' 'documentation/Concepts/polymorphism.xml' 'documentation/Concepts/context.xml' 'documentation/Syntax/syntax.xml' 'documentation/Syntax/modules.xml' 'documentation/virtualization.xml' 'documentation/exploitation.xml' 'documentation/communication.xml' 'documentation/index.xml' + 'documentation/build.xml' ) PWD=`pwd` Filename=`realpath $0` upload () { convert_all /tmp/docs2 rsync -e 'ssh -p24' -rtvz $Filename $REMOTE:/opt/doctl rsync -e 'ssh -p24' -rtvz /tmp/docs2/ $REMOTE:/opt/documentation/ rsync -e 'ssh -p24' -rtvz $PWD/documentation/manual.json $REMOTE:/opt/documentation/ } convert (){ SOURCE_FILE=$1 DEST_FOLDER=$2 Name=$(basename $SOURCE_FILE) sed -e '// d' -e 's///g' $SOURCE_FILE | \ $PANDOC \ -f docbook \ -t $PWD/documentation-tools/doc-converter/remarkup.lua \ -o $DEST_FOLDER/$Name.remarkup } convert_all (){ DEST_FOLDER=$1 mkdir -p $DEST_FOLDER for Chapter in ${DOC_CONTENT[@]}; do convert $PWD/$Chapter $DEST_FOLDER done } case $1 in convert) convert $2 $3 ;; convert-all) convert_all $2 ;; upload) upload $2 ;; *) echo "usage: $0 convert | convert-all | upload";; esac diff --git a/documentation/Concepts/context.xml b/documentation/Concepts/context.xml index 020b673..16a26ec 100644 --- a/documentation/Concepts/context.xml +++ b/documentation/Concepts/context.xml @@ -1,304 +1,304 @@ <?xxe-sn 2ahi4rjnvuo 2?>Context Computer program, its internal states and transitions between them can be looked at from two different points of view: control flow and data flow. In order to express and employ control flow related program's properties Xreate supports mechanism called context — ability to assign transcend data to a code blocks in a way that related blocks in the CFG have related contexts. Code block's context is exhaustingly defined as follows: Block's place within the code in terms of hierarchy of all its respective parents. Historical data determined by previous visited code blocks in terms of "caller-callee" relation graph. Block level annotations are used to define context and reason about it. See syntax. + xlink:href="/d/transcend/#code-blocks-and-context">syntax.
<?xxe-sn 2ahi4rjnvuo e?>Examples of Context Usage: Suggestions and Requirements //someStringFn = function:: string {...} main = function:: string; entry { context:: env(utf8). someStringFn() } In this example the annotation env(utf8) conveys some information about the block thus distinguishing it from the others, which allows to apply specific compilation rules for this block. Suppose someStringFn has different specializations for different environments. Now it's possible to invoke specialization tailored for UTF8 environment. In this case context can be viewed as a suggestion to pick up appropriate specialization. Also there is possibility to define expected context properties: name - "...." guard:: safe { crucialOperation = function:: int {0} } main = function:: int; entry { context:: env(safe). crucialOperation() } Function crucialOperation has only one specialization safe in the example. If the context does not provide required environment env(safe)compiler can't find appropriate specialization and reports compilation error. This is a way for function to express requirements or contract to a context it works within.
<?xxe-sn 2ahi4rjnvuo r?>Context Propagation Context propagation means that contexts of different blocks are connected reflecting control flow. Context of a particular code block is gathered from following sources: Local context — annotations that are defined within the block Parent context. Block's context inherits context of its parent reflecting block's place within a program. Client context. Blocks context also includes caller's context reflecting control flow. It allows taking into account in which context a given code is used. Example below name = "..." //requires 'safe' context guard:: safe { crucialOperation = function(a:: int, b::int):: int { 0 } } test = function:: int; entry { //blockA context:: env(safe). range = [1..10]:: [int]. loop fold(range->x::int, 0->acc):: int { //blockB crucialOperation(x, acc) // In the nested scope env(safe) context still accessible } } demonstrates context propagation to a nested block which is exhibited by availability of a env(safe) annotation in the context of the nested block blockB despite being defined in the blockA. Another case is propagation from caller to a callee. It means context propagates through "caller/callee" relation — callee inherits caller context. The example below demonstrates this: name = "..." toSI = function(x:: int):: int { 0 } calculate = function(x:: int):: int { y = toSI(x):: int. y } test = function:: int; entry { context:: units(mm). calculate(10) } Suppose calculate()works with values measured in different units. It normalizes each value by invoking toSI() conversion. One approach is to keep unit information for each variable independently. But if we know that entire program or a part of it works only with specific unit we can register it in a context, units(mm)in this example, letting functions calculate() and its callees inherit context allowing compiler to generate code tailored for specific units only.
<?xxe-sn 2ahi4rjnvuo 1n?>Latex (Late Context) Static(compile-time) context reasoning is weak since it's able to infer only partial context, consisting of properties that are true for all possible paths leading in a CFG to a given block. Beyond that are entries that depend on exact path in CFG. Such uncertainty is possible to resolve during runtime once it's known which path exactly is chosen. To solve this problem late context is introduced - embedding into compiled code certain instructions to gathered data on relevant occasion at runtime to determine exact or strong, context. Latex approach can be described as follows: Set of all possible context facts for the given block is computed during compile time. Each such fact is associated with code paths it holds for. During execution the information is gathered which facts are hold depending on actual code path. Information stored in the late parameters. To convey late context data the latex parameter is injected into function signature as hidden parameter. Late parameter is used as guard for late transcend facts context consists of. name = "..." import raw ("core/control-context.lp"). compute = function:: int { 0 } computeFast = function:: int { context:: computation(fast). compute() } computePrecisely = function:: int { context:: computation(precise). compute() } test = function(cmnd:: int):: int; entry { context:: arithmetic(iee754). if (cmnd > 0)::int {computePrecisely()} else {computeFast()} } Static scope name = "..." import raw ("core/control-context.lp") case context:: computation(fast) { compute = function:: num { 0 } } case context:: computation(precise) { compute = function:: num { 0 } } executeComputation= function:: num { compute() } test = function(cmnd:: num):: num; entry { if (cmnd > 0)::num { context:: computation(fast). executeComputation() } else { context:: computation(precise). executeComputation() } } To sum it up, context consists of two complements parts: on the one hand static(early) context, that denotes compile time inference's result and on the other hand, late(dynamic) context denotes annotations decided upon at runtime.
diff --git a/documentation/Concepts/polymorphism.xml b/documentation/Concepts/polymorphism.xml index ccc0819..05619d8 100644 --- a/documentation/Concepts/polymorphism.xml +++ b/documentation/Concepts/polymorphism.xml @@ -1,272 +1,272 @@ <?xxe-sn 26n42fz1reo 2?>Polymorphism See function + xlink:href="/d/syntax/#function-specializations">function specializations for syntax. Polymorphism is an umbrella term to denote a number of techniques across different programing paradigms. They all share the same intention to provide the ability to easily recombine software components in a different way with as little manual work on developer's side as possible. It serves two major goals: specialization, which purports that software initially designed to support a wide range of use cases is being configured for a specific case, and extension – adapting software to an environment and conditions it was not specifically designed for. In course of software engineering evolution, a number of polymorphism techniques was proposed and experimented with, all suited for different use-cases. Xreate presents a generalized and elegant approach that exhaustively covers the wide landscape of polymorphism variations. Polymorphism in Xreate can be applied on two levels: Functions level. Function in Xreate can have multiple specializations, and polymorphism is compiler's ability to decide which exactly specialization to use depending on various factors Modules level. Multiple modules can provide the same service for users. Modules + xlink:href="/d/syntax/modules/#modules-resolution">Modules Resolution is a process to decide which exactly module to use. По поводу Modules Resolution: кажется в предыдущем файле я внес несколько исправлений, добавив апостроф после Modules. По грамматическим правилам это верно, но если Modules Resolution это устоявшийся термин в твоей документации, то возможно лучше без апострофа.
<?xxe-sn 26n42fz1reo j?>Function Level Polymorphism Basic idea is to allow developer to define several functions with the same name or, in other words, several specializations. Caller code then invokes the necessary function by its shared name, but cannot specify a particular specialization directly. The exact specialization to be invoked is decided later by a decision process called polymorphism resolution carried out by Transcend. This indirect invocation approach gives enough flexibility to use or replace different specializations depending on various conditions during compile time as well as at runtime. Each specialization must have unique guard (among all specializations with the same name) to be discernible from others. To summarize, function invocation is a two-layered process, where the client code specifies the callee function's shared name, while polymorphism resolution specifies specialization guard, if needed. For example, let us assume that we have been developing a software program to operate under specified time constraints. To model an implementation suitable for real time environment, one specialization of crucialOperation is defined with env(realtime) guard, i.e. it satisfies some fixed execution time constraints. Caller main specifies just a function name crucialOperation thus delegating the decision in respect of guard to polymorphism resolution done elsewhere, based on the environment's constraints the code is executed in. name="tests/polymorph.cpp: Polymorphs.Doc_FnLvlPoly_1" guard:: env(realtime) { crucialOperation = function:: int { 0 } } main = function:: int; entry { crucialOperation() }
<?xxe-sn 26n42fz1reo x?>Polymorphism Resolution SYNTAX: **dfa_callguard**(//call-site-ref//, //guard//) call-site-ref reference to a call site in AST guard resolved function specialization guard When compiler encounters function invocation that has several specializations it refers to the table dfa_callguard to find out which specialization to call. It must have an entry with appropriate guard for every invocation site call-site-ref of a polymorphic function. Polymorphism resolution is a process of filling out dfa_callguard for the compiler based on custom Transcend rules reflecting one or another polymorphism strategy.
<?xxe-sn 26n42fz1reo 1c?>Late Polymorphism Late Polymorphism is an extension to allow polymorphism resolution to be based on data known only at runtime, i.e. resolve function specializations dynamically. The Idea is to use Late Transcend to access runtime data. See Late + xlink:href="/d/transcend/latetranscend/">Late Transcend for details. Example below demonstrates test invoking polymorphic function compute: name="tests/polymorph.cpp: Polymorphs.Doc_LatePoly_1" Strategy = type variant {fast, precise}. guard:: fast { compute = function:: int {0} } guard:: precise { compute = function:: int {1} } test = function(s:: Strategy; alias(strategy)):: int; entry { switch late (s):: int { compute():: int; guardalias(strategy) } } Function compute has two specializations, fast and precise. We see that test gets parameter s that dictates exact strategy to use. Clearly, resolution should work dynamically to deal with cases like this, for not only the value of the parameter s is unknown at the compile time, but also it can change with each test execution. Operation switch late is compiled into several branches, two in this case, each branch executing appropriate compute specialization. The correct branch is executed depending on the current s value. Custom annotations alias(Alias) and guardalias(Alias) are used to assign an alias in order to specify which parameter to use as basis for resolution.
<?xxe-sn 26n42fz1reo 1x?>Auto Expansion of Late Parameters In the previous example, operation switch late was used to facilitate calling of a polymorphic function with late polymorphism resolution. It is not that convenient to wrap each invocation using switch late whenever we need to call a late polymorphic function. Compiler uses the late parameter auto expansion technique in order to specifically handle cases like this. If compiler discovers that late(dfa_callguard()) entry exists for current invocation, and it does not have enclosing switch late already, compiler automatically generates different branches that invoke relevant specializations and transfers control to a branch depending on the late parameter's value. In other words, invocation is implicitly wrapped into switch late if needed.
\ No newline at end of file +?> diff --git a/documentation/Syntax/modules.xml b/documentation/Syntax/modules.xml index 6fee31f..e4d93f2 100644 --- a/documentation/Syntax/modules.xml +++ b/documentation/Syntax/modules.xml @@ -1,408 +1,408 @@ <?xxe-sn 26n42fz1reo 22?>Modules Xreate offers modules as a way to organize and reuse source code. For simplicity's sake, it is implemented as one file — one module, with one to one correspondence. Modules often require prior compilation of other modules for correct work. This leads to a problem of resolution where the required module is located, determine exact module's filename, especially as modern software products tend to incorporate a complicated and volatile file structure depending on configuration and platform to build. The common practice is to rely on build configuration tools to provide exact path to each module. Не вполне понимаю смысл фразы "a resolution where the required module is located". Принятие решения о том, где будет располагаться какой модуль? Тогда может лучше будет так: "This leads to a problem of resolution where to locate which module". Как в этом примере: "Therefore tools for choosing where to locate which types of production like this method will become increasingly useful". Или выяснение того, где находится нужный модуль? For this reason Xreate interferes as little as possible with the resolution. The language does not allow for a module to specify a path directly, be it a relative or an absolute path in respect to other required modules. Also the compiler does not search for modules in any predefined list of directories, and does not assume anything about project's file structure. It expects the resolution information to have been already fully predefined before the start of the compilation process. 1. Если resolution - это процесс, то перед словами обозначающими какой-либо процесс, как правило, артикли не ставятся (исключение - если речь идет о каком-то конкретном процессе, например, "Dune2: The building of a dynasty"). А неопределенный артикль совершенно исключен в этом случае. 2. "The language does not support for a module" - возможные варианты замены: "The language offers no instruments allowing a module to...", "The language has no means allowing a module to...". 3. "Does not search for modules in some..." - в вопросительных предложениях и при отрицании употребляется местоимение "any" вместо "some". However, the compiler features some optional built-in functionality to facilitate resolution. It is the very type of a problem the transcend level is excellently suited for. It is modeled after a supply and demand approach and lets modules to declare what they provide and what they require, expressed by annotations. Compiler then tries to satisfy the requirements and find a match. Alternatively, external tools can always be used.
<?xxe-sn 26n42fz1reo 2d?>Module Headers SYNTAX: **module** [:: //annotations-list// ] (Full form) { //module-statement//... } **module** :: //annotations-list// . (Simplified form) //module-statement// ::= | **require** ( //annotation// ). (1) | **discover** ( //path// ). (2) | **controller** (//path//). (3) annotations-list List of annotations delimited by semicolon annotation Any valid transcend expression path Absolute or relative path to controller Xreate recognizes a number of module management statements. Those statements should be located in a specific section module {...} of a source code which is called module header. Module can have several headers. All headers gathered from a single file are combined into one before actual processing. Modules' processing happens before compilation. This means that any data produced in course of compilation is inaccessible at this stage
<?xxe-sn 26n42fz1reo 2x?>Requesting Modules Statement require(..) expresses which modules are required for correct compilation. name="tests/modules.cpp: Modules.Doc_Requesting_Modules_1" module { require(logger). } In this example a module in question requires some other module that provides a feature called logger. There is no way to specify the direct location of the external module. Instead, the "main" module expresses a requirement in an abstract form as a propositional expression which is later used by the resolution to find the exact match. name="tests/modules.cpp: Modules.Doc_Requesting_Modules_2" module{require(stringslib).} processString = function(a:: string):: string { someStrFunc(a) } module{require(mathlib).} processNumber = function(a:: num):: num { someMathFunc(a) } The above example demonstrates usage of several headers in one file. It is particularly useful in situations where a developer finds it convenient to place requirements beside the actual code that uses them. This way one can easily spot the requirements that are no more needed. After all, code locality improves readability.
<?xxe-sn 26n42fz1reo 37?>Module Annotations A module can declare an additional information for various uses. This is expressed by annotations located in the header. They are called 'module annotations'. For instance, module annotations can be used by module resolution to find modules that satisfy requirements of other modules. name="tests/modules.cpp: Modules.Doc_ModuleAnnotations_1" module:: status(obsolete). The example shows a module that declares its status. It can be used by resolution to select the most appropriate module out of a number of candidates. One way to view annotations used by resolution is to treat them as something that module provides. There are no predefined module annotations, and developers can place arbitrary information there.
<?xxe-sn 26n42fz1reo 3f?>Modules Resolution Modules resolution is a process to find exact modules' locations that match requests. Compiler does not perform a search of modules in any predefined directories, and it does not assume anything about project's file structure. Compiler, in order to allow a developer to determine it independently, refers to two transcend tables: Вот я и дошел до ответа что такое resolution :) Оставляю предыдущие комменты для истории. SYNTAX: **modules_resolution**(//request//, //module-resolved//). (1) **modules_resolution**(//request//, //module-resolved//, //module-context//). (2) request annotation used in statement request(...) module-resolved Path or identifier of a module that matches request module-context Path or identifier of a module that requires other module These tables contain resolved modules for all possible requests. Form (1) contains requests that should always be resolved to the same module regardless of where module is requested. Form (2) contains such requests for which resolution depends on requester module-context. In other words, difference between forms (1) and (2) is that form (2) takes into account not only what(parameter request) is requested but also where from(parameter module-context) it is requested. name="tests/modules.cpp: Modules.Doc_ModulesResolution_1" modules_resolution(numlib, "/path/to/numlib"). modules_resolution(strings, "/path/to/ansi-lib", "moduleA"). modules_resolution(strings, "/path/to/utf8-lib", "moduleB"). In the above example, compiler would always resolve a path to numerical lib(numlib) as "/path/to/numlib" (line 1). However, strings library would be resolved as "/path/to/ansi-lib" if requested in moduleA (line 2) and as "/path/to/utf8-lib" if requested in moduleB (line 3). When compiler encounters a module request, it looks up a modules_resolution table (either the first or the second one) to find the path to the requested module. Tables can be populated by any means, be it transcend reasoning or any external tools. There is no defined order or priority or fall back behavior while looking into tables. If the same request occurs in both tables they are considered to be ill-formed
<?xxe-sn 26n42fz1reo 46?>Advanced Modules' Resolution Xreate provides an additional layer – an optional helper, to simplify modules management. It introduces two more built-in statements that can be used in the module's header: Discover Statement and Controller Statement. Discover Statement is presented in the form discover (path). It allows to specify a directory within which compiler would recursively search for all Xreate files and extract module header annotations. It gathers information about all found source files. Controller Statement is presented in the form controller (path) and specifies a path to the modules' resolution controller. Controller is a file that contains transcend rules in order to process data gathered by discovery and populate resolution tables as a result of its work. The below example shows 3 modules: name="tests/modules.cpp: Modules.Doc_AdvModRes_1" //First Module module:: name(testA); provide(superService); status(needToTestEvenMore). //Second Module module:: name(testB); provide(superService); status(needToTest). //Third Module module { require(superService). discover("/modules/path/"). controller("/path/to/controller"). } Two of the modules offer the same feature provide(superSerivce). The third module requires it and specifies a directory in which to look for needed files. The controller's task is to populate the resolution table if the necessary module is found, and also to choose the appropriate candidate, if more than one module offer this service. One way to decide what to choose in this example is to look at the status of both modules. Let a score be assigned to each possible status, e.g. 0 for status(needToTestEvenMore) and 1 for status(needToTest). The controller would then proceed with best scoring module – Second Module in this case.
<?xxe-sn 26n42fz1reo 4w?>See Also Transcend: Modules + xlink:href="/d/transcend/modules-api/">Modules API
\ No newline at end of file +?> diff --git a/documentation/Syntax/syntax.xml b/documentation/Syntax/syntax.xml index 209abbb..2f3e370 100644 --- a/documentation/Syntax/syntax.xml +++ b/documentation/Syntax/syntax.xml @@ -1,959 +1,959 @@ <?xxe-sn 26yv439af40 5a?>Syntax Literals, Expressions, Basic Statements Annotations Intrinsics: query Identifiers, Code Blocks Branch Statements Interfaces: Extern-C Functions Loops Other: Transcend, Versions Types Variants There are number of principles Xreate syntax based on: Follows SSA form: each identifier is defined only once and no redefinitions allowed Order in which identifiers are defined does not influence computation order. Identifiers are computed in order based on dependencies between expressions. Order in which identifiers are defines reflects personal preferences and what is convenient for a developer.
<?xxe-sn 26yv439af40 62?>Literals and expressions Xreate expressions have a form: SYNTAX: //expression// [:: //type//; //annotations-list// ] annotation-list is a list of annotations delimited by semicolon. Expressions consist of literals and various operations as follows: Literals numbers, strings: 5, "Nimefurahi kukujua" Lists, records Record is a collection of elements of different types — {year = 1934, month = "april"}. List is a collection of elements of the same type without keys — {16, 8, 3}. Range of elements — [1..18]. Arithmetic operations Basic arithmetic operations: +, -, *, / Relations ==, !=, <>, <, <=, >, >=. Both !=, <> mean not equal relation. Examples: 8>=3, "Blue" <> "Green" List and struct operations index operation to access individual elements of a list or a record. Example: colors = {"Green", "Blue"}::[string]. color = colors[0]:: string. Record's element access: date = {year = 1934, month = "april"}. year = date["year"] Identifiers Example: a - b Functions Example: result = isOdd(6).
<?xxe-sn 26yv439af40 7c?>Code Blocks Block is a list of expressions delimited by period. It has a body - main expression and optionally some identifier definitions. SYNTAX: { [//ident// = //expression// . | //body-expression// . ].. } Code block consists of body expression and optional set of assignments to define identifiers used in body expression. Block's computation is defined as a result of associated body expression's computation. Identifiers are computed before expressions they are used in. name="tests/ast.cpp: AST.Doc_CodeBlocks1" test = function:: int { a = 10:: int. b = 2:: int. a + b:: int } Above is an example of code block which have a+b as a body expression. In this case body depends on identifiers a, b so compiler computes both of them beforehand. Computation order depends only on dependencies between expressions. This approach has properties as follows: Mutually independent identifiers can be evaluated in any order Identifier gets computed only if it's required(even transitively) by block's body expression.
<?xxe-sn 26yv439af40 7u?>Functions SYNTAX: //function-name// = **function** ([//argument//:: //type//[; //annotation-list//]]...):: //return-type// [; //annotations//]... //function-block// function-name name of function argument formal parameter. Arguments are delimited by comma. type, return-type formal parameter and returning value types function-block code block that acts as a function's definition annotations list of annotations delimited by semicolon Below is an example of a function sum. It takes two arguments and returns their sum. Also it defines several annotations. First annotation entry has a special meaning — it depicts entry point or main function in a program. Second annotation status(needs_review) is a demonstration that developers can annotate function using custom annotations to express different properties. name="tests/ast.cpp: AST.Doc_Functions1" sum = function(x:: int, y:: int):: int; entry; status(needs_review) { x+y }
<?xxe-sn 26yv439af40 8j?>Function Specializations SYNTAX: **guard**:: //annotation// { //functions-list// } annotation Guard expressed by annotation functions-list one or more function that share the same guard Xreate allows several functions to share the same name. In which case they are called specializations. This is syntactic foundation for function level polymorphism, i.e. ability for compiler to decide which exactly function is called out of several options. Polymorphism resolution can happen during compilation or at run-time. Functions with the same name, i.e. different specializations should have additional unique identifiers called guards. When function is actually called it's expected that resolution is already done at some point before and supplies correct guard to uniquely specify which exactly specialization to call. Example: name="tests/ast.cpp: AST.Doc_FunctionSpecializations1" guard:: safe_enviroment { sum = function (a::int, b::int) :: int { a + b } } See API + xlink:href="/d/transcend/ast-api/#function-s-specializatio">API to get more information on how guards are processed
<?xxe-sn 26yv439af40 93?>Branch Statements
<?xxe-sn 26yv439af40 95?>IF Statement SYNTAX: **if** (//condition//):: //type// [; //annotations// ].. //block-true// **else** //block-false// IF statement executes block-true or block-false depending on condition evaluation result. Example: name="tests/ast.cpp: AST.Doc_BranchStatements" answer = if (question == "Favorite color?"):: string {"Yellow"} else {"Don't know"}.
<?xxe-sn 26yv439af40 9e?>SWITCH Statement SYNTAX: **switch** ( //condition// ) :: //type// [; //annotations//].. [**case** ( //guard// ) code-block].. **case default** //default-code-block// condition's result is used to decide which branch to execute next guard value to match against condition default-code-block executed if no appropriate case found SWITCH statement evaluation's result is that of branch whose guard matches condition. Example: name="tests/ast.cpp: AST.Doc_BranchStatements" monthName = switch(monthNum) :: string case (1) {"Jan"} case (2) {"Feb"} case default {"Strange.. Don't know this month"}.
<?xxe-sn 26yv439af40 9x?>Loop Statements
<?xxe-sn 26yv439af40 9z?>LOOP Statement SYNTAX: **loop** ( //init-value// -> //accumulator// ):: //type// [; //annotations//] //loop-body// init-value initial value loop starts from accumulator identifier which holds loop's result after each iteration For each iteration accumulator assumes result of previous iteration or init-value during first iteration. Result of the loop-body evaluation is used as accumulator's next iteration value and as overall loop statement result after the last iteration. This notation does not have termination condition. Compiler relies on loop body's fixed point in order to decide when to interrupt loop. Let's consider example: COUNTEREXAMPLE, name="tests/ast.cpp: AST.Doc_LoopStatements" //infinite loop answer = loop (2->x) :: int { if(IsPerfect(x)):: int {x} else {x+1} }. The example tests numbers for being perfect(sum of all proper divisors equals to the number itself). While iterating accumulator x assumes values as follows: 2, 3, 4, 5, 6, 6 ... After it founds first perfect number any further iteration do not change result anymore since there is no increment and it continues to test the same number again and again. Obviously, x=6 is a fixed point in this example. There is no point to continue going through further iterations once fixed point is evaluated and hence loop can be safely interrupted. Compiler relies on manually provided annotations to recognize when fixed point is reached. There is special annotation final to specify fixed point for loops. Once expression marked as final gets evaluated it's assumed to be a fixed point or in other words compiler knows it's the very last iteration after which loop ends. Correct code for the example above is: name="tests/ast.cpp: AST.Doc_LoopStatements" //loop exits after first perfect number is found answer2 = loop (2->x) :: int { if(IsPerfect(x))::int {x:: int; final} else {x+1} }. In this case compiler able to recognize when fixed point is reached to exit loop. After loops is done answer is 6.
<?xxe-sn 26yv439af40 aq?>LOOP FOLD Statement SYNTAX: **loop fold** (//list// **->** //element//:: //type// [; //annotations//], //init-value// **->** //accumulator//):: //type// [; //annotations//] //loop-body// list to iterate through element identifier that assumes value of currently processed list element type, annotations expression types and optional annotations delimited by semicolon init-value accumulator's initial value loop starts with accumulator identifier assumes loop-body evaluation result after each iteration Iterates over list in order to accumulate result by applying loop-body transformation to each element and intermediate accumulator. Overall loop value is a accumulator's value after the last iteration. If fixed point is found an execution terminates earlier. Example shows code excerpt that looks for a minimal element in the given list(and less then initial value 10). name="tests/ast.cpp: AST.Doc_LoopStatements" numbers = {4, 8, 7, 1, 5}:: [int]. min = loop fold(numbers->x:: int, 10->acc):: int { if (acc > x):: int {x} else {acc} }.
<?xxe-sn 26yv439af40 bi?>LOOP MAP Statement SYNTAX: **loop map** (//list// **->** //element// :: //type// [; //annotations// ] ) :: //type// [; //annotations// ] //loop-body// list to iterate through element identifier that assumes value of currently processed list element type, annotations type and optional annotations delimited by semicolon. loop-body Iterates over input list and applies loop-body transformation to each element. Result is a list that consists of all transformed elements. name="tests/ast.cpp: AST.Doc_LoopStatements" odd_numbers = {1, 3, 5}:: [int]. even_numbers = loop map(odd_numbers->number::int) :: [int] { 2 * number }. Example demonstrates creating even_number list by multiplying by 2 every element of odd_numbers.
<?xxe-sn 26yv439af40 c6?>Types Primitive Types num i32 alias. Reserved as a placeholder for auto detected appropriate either integral of floating-point type int i32 alias. Reserved as a placeholder for auto detected appropriate integral type float Double precision floating-point number bool Boolean type i8, i32, i64 Signed integers. 8, 32, 64 bit wide respectively string Pointer to a null terminated ANSI char string. Reserved for auto detected most appropriate string type. * Unspecified type. Example x = {amount=200, currency="USD"}::*. Compound types: [ element-type ] List of elements of the same type element-type. Example: [int] - list of int's {key:: type, ...} List of elements of different type possibly with named keys. Examples: {int, string}, {name::string, age::int} variant {option :: (type, ...}, ...} Holds a single element of type of one out of number of options. Examples: variant {FullAddress:: {string, string, string}, ShortAddress:: {string}} slave identifier Type determined by Transcend. Example: slave unit_test compound-type [ key ] Accessing elements of compound type. Example: Bio = type {birth_year:: int, name:: string}. Year = type Bio[birth_year]. New types defined as: SYNTAX: //type-name// = **type** (//parameters//...) //type-definition// . Example: name="tests/ast.cpp: AST.Doc_Types" Tuple = type {string, int}. Int = type Tuple[1]. //accessing by index
<?xxe-sn 26yv439af40 ej?>Variants and SWITCH VARIANT Instruction SYNTAX: **switch variant** ( //condition// [-> //alias// ] [:: //type// [; //annotations//... ] ] ) :: type [; annotations... ] [ **case** ( //guard// ) //case-branch// ]... condition expression of variant type alias identifier to denote unwrapped content of condition withing case branches. guard name of variant to match against actual condition's variant case-branch block of code to execute in case of matched variant. Content is accessible by using alias Within the branch . Sometimes it is useful for a variable to have value of different types depending on some conditions, in other words it has variant type. Let's consider example with variable month of variant type Month: name="tests/ast.cpp: AST.Doc_Variants" Month = type variant { MonName :: {string}, MonNumber:: {int} }. test = function:: Month { month = MonName("April"):: Month. month } Variable month holds value of either string or int type. Value is not accessible directly. It should be unwrapped before using. Xreate supports switch variant instruction for this operation. As an example below is function nextMonth's definition: nextMonth = function(month:: Month):: Month { switch variant(month):: Month case (MonName) { // } case (MonNumber) }
\ No newline at end of file +?> diff --git a/documentation/Transcend/ast-api.xml b/documentation/Transcend/ast-api.xml index 5fae63b..c757ee2 100644 --- a/documentation/Transcend/ast-api.xml +++ b/documentation/Transcend/ast-api.xml @@ -1,495 +1,495 @@ 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: name="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: name="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' 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: name="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: name="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: name="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: name="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: name="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: name="tests/transcend-ast.cpp: ASTCorrespondence.Doc_BasicTests" guard:: arch(amd64) { test = function:: i64 {0} } Translation's result: cfa_function_specializations(test,arch(amd64)) See also specializations + xlink:href="/d/syntax/#function-specializations">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: name="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: name="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_call Specifies caller's code block and callee function name (2) dfa_callfn Declares unique reference to a particular invocation site.The reference used by other facts to supply additional information (3) dfa_callargs Declares 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: name="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: name="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))
diff --git a/documentation/Transcend/modules-api.xml b/documentation/Transcend/modules-api.xml index dc2d68e..215808b 100644 --- a/documentation/Transcend/modules-api.xml +++ b/documentation/Transcend/modules-api.xml @@ -1,156 +1,156 @@ <?xxe-sn 2ahy8s1pw5c 7g?>Modules API Modules Resolution is a process of finding out which modules should be preloaded for a correct compilation of a given module. Resolution expected to use bind_module, modules_require as an input and produce results in form of modules_resolution data table.
<?xxe-sn 2ahy8s1pw5c 7n?>Module Annotations: 'bind_module' SYNTAX: **bind_module**(//module-ref//, //annotation//) module-ref module's path Declares module annotations. Example: name="tests/modules.cpp: Modules_API.Doc_ModAnn_1" module:: status(obsolete). Produced fact: bind_module("/path/to/module",status(obsolete))
<?xxe-sn 2ahy8s1pw5c 7z?>Requesting Modules: 'modules_require' SYNTAX: **modules_require**(//module-ref//, //request//) module-ref module's path request expressed by annotation Module can request other modules necessary for correct work. Declared requests can be processed to find a resolution. Example: name="tests/modules.cpp: Modules_API.Doc_ReqMod_1" module { require(logger). } Produced declaration: modules_require("/path/to/module", logger)
<?xxe-sn 2ahy8s1pw5c 8e?>Modules Resolution: 'modules_resolution' SYNTAX: **modules_resolution**(//request//, //module-resolved-ref//) (1) **modules_resolution**(//request//, //module-resolved-ref//, //module-context-ref//) (2) request expressed by annotation module-resolved-ref resolved module's path module-context-ref context module's path Xreate uses the data table to find correspondent modules for each request. Form (1) assigns resolved module to a request and assumes that assignment is valid in all cases, i.e. whenever compiler encounters request it loads associated module. Form (2) assigns resolution valid only in a specific context. Compiler uses particular resolution only for requests that came from a module specified in a context. In other words, form (2) allows to resolve the same request differently for different modules depending on resolution strategy, thus implementing polymorphism on module level.
<?xxe-sn 2ahy8s1pw5c 8v?>See Also Syntax: Modules + xlink:href="/d/syntax/modules/">Modules
diff --git a/documentation/Transcend/transcend.xml b/documentation/Transcend/transcend.xml index ad02e52..9ca00af 100644 --- a/documentation/Transcend/transcend.xml +++ b/documentation/Transcend/transcend.xml @@ -1,443 +1,443 @@ <?xxe-sn 2ajela3ur5s 7r?>Transcend Transcend is a compilation phase and process of reasoning about program in order to influence compilation. First, compiler extracts annotations from source code and other facts from number of sources to form a complete logic program. Then, solver processes logic program and outputs decisions that affect and control compilation process in a number of ways.
<?xxe-sn 2ajela3ur5s 7x?>Annotations' Syntax Xreate's annotations comprise optional supplementary information that is processed by compiler along with a source code proper and able to affect compilation process. Annotations have form of expressions that consist of following elements: Literals Strings, numbers. Example: 5, "success" Predicates Predicates have zero or more arguments. Example: final, status(broken), version("12.0.3", unstable) Negation Example: -i12n, -access(allowed) Various Xreate's entities can be annotated. At the time following entities are supported: Expressions and Identifiers Code blocks and context Functions - and Function + xlink:href="/d/syntax/#functions">Functions + and Function Guards Modules + xlink:href="/d/syntax/modules/#module-annotations">Modules
<?xxe-sn 2ajela3ur5s 8v?>Expression and Identifiers SYNTAX: //expression// **::** //type//**;** //annotation-list//. type expression's type annotation-list one or more annotation attached to the expression. Annotations are delimited by semicolon Example: name="tests/transcend.cpp: Transcend.Doc_Expressions1" test = function:: int { x = 5:: int; arithmetic(fast). //annotation applied to an identifier y = (x - 8:: int; arithm_optimization(off)) * 2:: float. //annotation applied to a nested expression x+y } For readability sake compound - statements(e.g. loops) + statements(e.g. loops) have different syntax for an annotations. See particular statement's - syntax + syntax for details
<?xxe-sn 2ajela3ur5s 9b?>Code Blocks and Context SYNTAX: **context** :: //annotations-list//. annotations-list List of annotation delimited by semicolon Code block annotations called context. Keyword context used to declare annotation within enclosing code block. Example: name="tests/transcend.cpp: Transcend.Doc_Codeblocks1" test = function:: int { context:: arithm_optimization(off). x = 10 :: int. 2 * x - 16 }
<?xxe-sn 2ajela3ur5s 9n?>Special Annotations There are some annotations in Xreate that have special meaning entry Specifies entry point of a - program. See Function + program. See Function Syntax final Specifies fixed point of loop statements. See Loop + xlink:href="/d/syntax/#loop-statement">Loop Statement
<?xxe-sn 2ajela3ur5s a5?>Annotations and Reasoning Annotations is a mechanism to express an additional pieces of information and can occur in 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, statements, code blocks, functions, modules or even a whole program. Annotations are facts about source code provided by developer in explicit form. Beside annotations there are other sources of information, e.g. implicit facts that are automatically inferred by various analysis phases to express useful insights regarding analysed code. Such pieces aren't exposed directly to a developer but accessed and used internally at reasoning phase along with annotations. All types of input are summed up below: Explicit annotations in source files Annotations provided by developer in order to explicitly affect compilation Code Analysis Different code analyses during compilation provide information implicitly inferred from source code Supervision External facts that reflect requirements, describe hardware and/or environment where compilation takes place or program is supposed to work. There are many supervision layers possible, from custom compiler's mode, to OS- or computer- or even network-wide level. On other words, supervision covers local or client supplied annotations Audit Third party supplied external information that reflect additional software properties, e.g. results of security audit Reasoning rules Reasoning infers additional facts from pool of previously gathered information. It is done by using resoning rules that govern reasoning process
<?xxe-sn 2ajela3ur5s av?>Why Annotations Matter This section goes through differences that annotations have over traditional statements.
<?xxe-sn 2ajela3ur5s ay?>Extensible Annotations are not a part of language syntax and there is no predefined set of allowed annotations. Developer is free to define and use custom annotations to express desired properties without prior changes to compiler. Yet there are several reserved annotations that have specific meaning in Xreate. See special annotations for details.
<?xxe-sn 2ajela3ur5s b4?>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 an input for a reasoning procedure that ultimately determines how exactly influence compilation.
<?xxe-sn 2ajela3ur5s b7?>Cooperation Annotations are gathered from different sources and this enables annotations to complement themselves. Compiler blends in annotations originated from various sources seamlessly and this allows to improve decisions quality.
<?xxe-sn 2ajela3ur5s ba?>External Sources and Adaptability Annotations able to express not only properties of program itself but also properties of local environment(OS, computer, local network) where program is supposed to run. Thus compiler operates information inaccessible during software development and can't be reflected in the code otherwise. Compilation can be adjusted to a particular environment and functioning mode.
<?xxe-sn 2ajela3ur5s bd?>Feedback Traditionally software has a rigid strictly defined hierarchical structure and interaction between components. More precisely, let's look at client-service code model. Service is done independently in order to work well with as wide as possible set of different clients. Thus service is unaware of exact characteristics of particular client code it works with. All burden of complying with interaction specification lies on a client. However client may use only small subset of service functionality or use it in specific and predictable order. Generally speaking, service by having additional information on particular client able to serve requests more efficiently in many cases. It can be conceptualized as a feedback from a client. Annotations is good candidate to express feedback to improve interaction quality.
<?xxe-sn 2ajela3ur5s bj?>Resiliency As code grows and goes through multiple reworks and rewrites many initial assumptions about the code and relation between different parts change accordingly. Some implementation details and approaches became outdated and code quality deteriorates. DIfferent picture in case if code uses annotations to express important properties. Any changes in underlying code lead to a restart of reasoning procedure which adjust implementation decisions to be still optimal in changed environment.
diff --git a/documentation/build.xml b/documentation/build.xml new file mode 100644 index 0000000..0b10cee --- /dev/null +++ b/documentation/build.xml @@ -0,0 +1,154 @@ + + + + + <?xxe-sn 2ckdfwgr1fk 2?>Installation + +
+ + + <?xxe-sn 2ckdfwgr1fk 7?>Build on Linux + + Major dependencies: + + + + + + + + gcc 7 + + + + + + llvm 5, clang 5 + + + + + + boost 1.66 + + + + + + coco + + + + + + clingo + + + + Building tested on OpenSuse Leap 15. Please + change commands accordingly if using other distributions. + + Pull sources directly from + repository: + + git clone --recursive https://pgess@bitbucket.org/pgess/xreate.git + + Enter into the source directory and run the + following script to prepare building environment. Script will install the + required system packages as well as Coco and Clingo from sources: + + "Enter into source directory" - тут перед + directory явно нужен артикль. Гугл говорит, что определенный - + the + + + + + Carefully inspect scripts before + run + + + On OpenSuse + Leap 15: + + ./installation/prepare-opensuse-leap15 + + That was one time operation to prepare + environment. After that enter into build + directory and start actual tests building: + + "build directory": здесь ты все-таки + вначале указываешь имя объекта (build), и лишь потом родовое название + (directory) + + cd build +make + + After successful build you can run xreate + tests: + + cd .. +./build/tests/xreate-tests + + + + + Please pay attention that the working + directory should be the repository root + + + For consequent rebuilds after updates etc + invoke cmake as follows: + + #working dir build +cmake -DCMAKE_BUILD_TYPE=Debug \ + -DBUILD_XREATE_TESTS=1 \ + -DCOCO_EXECUTABLE=<FILE> \ + -DCLINGO_PATH=<DIR> \ + -DCOCO_FRAMES_PATH=../vendors/coco/generator/ \ + -DCMAKE_CXX_COMPILER=g++ ../cpp +make + + Cmake's selected parameters: + + + + + + + + BUILD_XREATE_TESTS Determines whether + to build tests + + + + + + COCO_EXECUTABLE Full filename of Coco + executable + + + + + + CLINGO_PATH Installed Clingo + directory + + "Directory of Clingo installation": + может, with Clingo installation? (это если речь идет о папке, где + хранятся инсталляционные файлы) Если наоборот, куда будет + устанавливаться - тогда Directory for installing Clingo. Оригинальный + вариант ("of Clingo installation") немного сбивает с толку. + + +
+
diff --git a/documentation/exploitation.xml b/documentation/exploitation.xml index 39bd002..299281a 100644 --- a/documentation/exploitation.xml +++ b/documentation/exploitation.xml @@ -1,490 +1,490 @@ <?xxe-sn 26yv439af40 2?>Exploitation This chapter discusses exploiting external resources, such as files, as a particular instance of a side effects problem that inevitably stems from an interaction with the outside world. Unlike virtualization, + xlink:href="/d/virtualization/">virtualization, an another documentation's topic that tackles I/O, exploitation approaches subject from a different angle — it is concerned with an order of operations, sequence in which different clients jointly use the same resource and it deals with corresponding difficulties, e.g. ensures proper resource initialization before actual usage.
<?xxe-sn 29je46abuev -wunr7fl0rw8u?>Syntax
<?xxe-sn 29je46abuev -wunr7fl0rw8r?>Annotations SYNTAX: **use**(//resource-id//) **init**(//resource-id//) resource-id — user-defined resource identifier Annotates function or code block as such that exploits resource resource-id.
<?xxe-sn 29je46abuev -wunr7fl0rw8i?>Guards SYNTAX: **exploitation(init)** **exploitation(none)** Specializations that are recognized by exploitation reasoning. Each specialization corresponds to an initialization strategy: exploitation(init) is expected to perform actual resource initialization. exploitation(none) is expected to do nothing as initialization isn't necessary or done elsewhere.
<?xxe-sn 26yv439af40 4?>Background In software engineering, the idea to avoid side effects have received considerable traction. Indeed, side effects is something that is hard to take into account and thus programs that have side effects are inherently unsafe, thus best coding practices are rightfully suggest to isolate side effects producing code as much as possible. It's so called pure functional languages whose philosophy goes even further and frames side effects as something opposite of "pure", and everything is built around effectless computations to the point that some languages' design itself includes side effects producing constructs, such as I/O, as an afterthought, as something almost unnecessary. However, in reality the opposite is true, most applications' sole responsibility is to communicate with "outside world", reacting to the external events and change "world state" accordingly. As a consequence, side effects usually are the only important effects the program produce and surely deserve first class support from a programming language and justify efforts to develop approach to alleviate related safety and performance concerns.
<?xxe-sn 26yv439af40 10?>Exploitation Plan One complexity of taking side effects into account is the fact that final result depends on an exact operations order. This harshly impacts both performance and safety, for many techniques, e.g. caching, parallelization can neither be automatically performed nor validated since they are based on various degrees of reordering or deal with possibly undetermined beforehand order of execution. In this chapter, it is assumed, that final effects of execution fully defined by exploitation path — for a particular code path that can occur during execution, it is its part consisting of only relevant code blocks., i.e. those that deal with an exploited resource. Other code blocks do not influence exploitation effects and so are excluded from consideration. Thus reasoning about effects is reduced to considering all possible exploitation paths, checking do they meet certain requirements that define valid exploitation and making corrections if needed and possible. Result of the reasoning is called exploitation plan — specification that defines exact order and strategy of using a given resource in order to comply with imposed requirements. With all above said, the discussed approach can be presented as follows: Annotations are used to express some aspects of side effects to enable further reasoning. They indicate code blocks that deal with resource as well as provide additional information about how exactly it is exploited, e.g. use, initialize or deinitialize resource. Existing code paths, extracted during source code processing, coupled with relevant annotations is enough to construct all possible exploitation paths and analyze them. Analysis determines possible(weak) paths that can occur or not during particular execution as well as certain paths(strong) that occur always no matter what. Also it checks are exploitation paths valid against certain rules, e.g. initialization occurs always before actual usage and is it possible to correct invalid paths. Reasoning's result is an exploitation plan that dictates order and strategy of exploitation is presented in form of appropriate specialization for polymorphic functions that deal with resources in order to ensure safe exploitation to the extent based on provided annotations. Exploitation related side effects are viewed as a set of additional restrictions over operations order. Only subset of possible reorders is still valid w.r.t. side effects. Transcend's task is to find out refined set of valid orders. Thus techniques that rely on reordering enjoy additional information to make safe optimizations. ... and it serves three major goals: Safety. Validates existing exploitation plan or is it possible to safely exploit given resource at all. Compiler signals error if a given exploitation plan is invalid, i.e. does not satisfy requirements w.r.t. side effects as expressed by annotations. Regression Resilience. When it comes to using external resources, some spurious dependencies usually occur between otherwise isolated, independent components of a program. Sometimes refactoring and other code changes break those dependencies inevitably introducing regressions. Exploitation catches this sort of regressions and automatically regenerates exploitation plan suited for a changed conditions. Performance. Generated exploitation plans are optimal in a sense that they cut off superfluous operations, for example, removing resource initialization in several places if it can be done safely in a single one, thus reducing overall overhead.
<?xxe-sn 27ay8x1a5mo 2?>Domination Analysis When it comes to a reasoning about order of execution flow and possible code paths, crucial vehicle for that is domination analysis producing dominator tree as an output. Unlike the usual function-bounded domination analysis, when separate domination tree is produced for each function defined in a program, Exploitation requires program bound analysis, that is to take into account control flow across all functions in a program. It is computationally intensive task to perform analysis over a whole program, however it is compensated by the fact that Exploitation only takes into account code blocks that deal with, or in other words, exploit external resources. Thus there is no necessity to build full dominator tree, only the relevant parts are constructed, just enough to make sound exploitation plan decisions.
<?xxe-sn 28h47d43thc j?>Empty Exploitation Plan. Effect Free Computations Validation of exploitation path is done against some predefined constraints. Depending on complexity of a constraints, i.e. number of different exploitation events that are seeking for in each path, reasoning goals categorized into several groups: Zero Order Exploitation. Meaning that all paths are checked in terms is there exploitation at all or no, is there at least a single exploitation event along the path. First Order Exploitation. Deals with a situations when it's enough to check only two different exploitation event occur in a required order. It can be useful for example, to check whether all resource uses occur after it is initialized. Higher Order Exploitation. Expresses constraints involving several(more than two) exploitation events and relations between them. Empty Exploitation is an important instance of zero order constraint. It useful mechanism for developer to annotate function or part of a program as effect free in terms of exploitation. Thus, efectless, clean or pure code can be clearly separated from effectful part and compiler raises compilation error in case of accidental mixing or using "wrong" type of code in non appropriate environment.
<?xxe-sn 26yv439af40 v?>Resource Initialization One important problem related to an exploitation order is to ensure that a given resource is properly initialized before its first usage and additionally it is not initialized more then once during exploitation session. This is instance of first order exploitation since in a validation mode it is enough to check exploitation plan to ensure that every resource usage preceded by resource initialization at some point in the past, i.e. previously in the exploitation path. For planning mode, the problem is addressed as follows: Central idea of the algorithm is to consider candidates for initialization only among code blocks that dominate given usage site. Obviously, initialization in dominating block precedes usage for any possible code path. One or more dominator blocks are chosen for actual initialization in such way that they are cover all found usage sites. For code blocks chosen for initialization specialization exploitation(init) is set, for the rest specialization exploitation(none) is used. Look at the example below: name="tests/exploitation.cpp: Doc_ResourceInit_1", lines=15 import raw("scripts/cfa/payload.lp"). import raw("scripts/exploitation/exploitation.lp"). //exploitation reasoning import raw("scripts/exploitation/test1.assembly.lp"). guard:: exploitation(init) { openFile = function(filePrev:: FILE_P):: FILE_P; init(file) { fopen("/tmp/test", "w")::FILE_P } } guard:: exploitation(none) { openFile = function(filePrev:: FILE_P):: FILE_P { filePrev::int } } test = function:: int; entry { seq { f0 = undef:: FILE_P. f0 } { //Scope #1: f1 = openFile(f0):: FILE_P. f1 } { //Scope #2: f2 = openFile(f1):: FILE_P. f2 } { //Scope #3: sizeWritten = fwrite("Attempt to write..", 12, 1, f2):: int; use(file). sizeWritten } { //Scope #4: fclose(f2):: int; use(file) } { sizeWritten :: int} } There is the function test that executes sequentially next commands: open a file(scopes #1, #2), write some text(scope #3) and finally, close the file(scope #4). It represents simple work flow with an external resource. In order to connect the code to the exploitation the functions fwrite and fclose in scopes #3 and #4 respectively are annotated with annotation use(file). This information is used by reasoning to look whether it is possible to initialize given resource before actual usage as well as where and when exactly to initialize it. Function openFile is annotated as init(file) meaning it can initialize depending on chosen strategy. The function is invoked both in scope #1 and scope #2. Both scopes are executed strictly before scopes #3, #4. Thus it is indeed possible to initialize resource before usage. Next task for exploitation is to choose correct exploitation plan, i.e. to assign strategies for all possible initialization places in the effort to initialize resource only once. Here, it means that only one invocation of openFile is assigned with exploitation(init) to actually initialize the file. Other one is automatically marked with exploitation(none) to invoke different specialization of openFile that does nothing since the file is already initialized.
\ No newline at end of file +?> diff --git a/documentation/index.xml b/documentation/index.xml index d359a74..5033a93 100644 --- a/documentation/index.xml +++ b/documentation/index.xml @@ -1,356 +1,216 @@ <?xxe-sn 2b06cb2u4g0 2?>Xreate Manual Xreate is an open source general purpose high level programming language designed to write efficient and safe computer programs. Here "high level" has very specific meaning, implying an ability to easily write, read, as well as adapt software to a constantly changing environment or business goals. In this respect, any software product can be evaluated on the basis of the three dimensions: efficiency, safety, and adaptability. Unfortunately, those properties are proved to be largely contradictory, for it is manageable to write either efficient (yet unsafe) or safe (yet impractical) code, but not both. Thus, the ultimate goal of the language is to allow developers to produce code that would have all these properties at the same time. Xreate's design principles allow to adopt any programming technique as long as it does not improve one dimension at the expense of another. To achieve the aforementioned design goals, Xreate employs three distinctive layers: - Brute. + Brute. The lowest layer is called Brute — this is code that is intended to be actually compiled. Code on this level implements actual software functionality. It resembles the usual imperative languages' apparatus and consists of executable instructions such as arithmetic, branching, input/output, etc. - Transcend. + Transcend. Brute level alone is not enough to constitute a full-fledged language since code requires various non-executable metadata to express developer's intents, check correctness, validity and perform other types of analyses. In Xreate everything of this sort belongs to a layer called Transcend. Transcend due to its declarative nature is appropriate to do management-type work — it analyzes, oversees and controls brute by guiding compilation process. Everything on this level — logic or transcend facts and rules — is gathered and sent to an external logic solver to make solutions that are brought back in order to guide compilation. Interpretation. + xlink:href="/d/concepts/interpretation/">Interpretation. There is also Interpretation — the intermediate level resembling dynamically typed languages that is used as a contact point and interpreter between brute and transcend and their respective low level and high level constructs and structures. On a syntactic level, Xreate is a procedural language with extensive use of annotations + xlink:href="/d/transcend/">annotations — arbitrary unconstrained metadata that software developer can attach to different language constructs, variables and code blocks. Annotations are completely invisible for the compiler proper and used by transcend more as a suggestion conveying additional information. "a different language constructs": если подразумевается "конструкции разных языков", тогда лучше "different languages' constructs". Если конструкции языка, в целом, то тогда артикль a не нужен Most severe and hard to resolve problems in software development stem from interaction of different components on different levels. Each individual component often is thoroughly tested and works reliably. But combining them when building end-user software for which purpose complex interaction and extensive IO is enabled usually leads to a range of runtime errors, security vulnerabilities and performance degradation. Thus Xreate places key emphasis on domain-specific component level improvements and joint use of external resources. This aspect is covered in exploitation - and containers + xlink:href="/d/exploitation/">exploitation + and containers chapters. Unlike academic languages, Xreate targets safe and reliable usage of effectful computations - such as IO covered in virtualization - and exploitation + such as IO covered in virtualization + and exploitation chapters, and mutable structures covered in communication. + xlink:href="/d/communication/">communication.
<?xxe-sn 2b06cb2u4g0 4?>Basic Example To demonstrate what Xreate is all about, basic example is given below: name="tests/introduction.cpp: Introduction.Doc_Example_1", lines=15 guard:: iAmVeryFast { div = function(a:: float, b:: float):: float { a / b } } guard:: iAmVerySafe { div = function(a:: float, b:: float):: float { if ( b == (0::float)):: float {0::float} else {a / b} } } test = function:: float; entry; iAmVerySecure { div(10, 5) } Here entry point of the program is a function test recognized so by compiler because of annotation entry in its signature. There are also two functions div called specializations. Each specialization has a guard that defines a condition that has to be met in order to invoke this particular specialization. In the example, specializations of div have iAmVeryFast and iAmVerySafe guards, respectively. Let's say that developer specifies two specializations where the first one is a very fast division implementation, while the second one is a very safe division implementation since it checks division by zero, although it is unacceptably slow due to an extra check instruction. This is a basis of - polymorphism + polymorphism — client's code test is able to work with any specialization, and compiler must decide which one to invoke with the only hint it has — annotation iAmVerySecure in the function test's signature. "provides two specializations" - возможно, лучший вариант "designates/assigns/allocates two specializations". Или даже просто specifies/indicates. (PS заменил на specifies) "unbearably slow" - я бы заменил на более нейтральное "too slow". Unbearable - это скорее об ощущениях человека. Или, если под "unbearably" имеется в виду "недопустимо медленный", тогда - unacceptably slow. All annotations (except entry) are custom defined by developer itself. This is when transcend comes into play. By adding a transcend rule as shown below it is possible to associate annotation iAmVerySecure with invocation of specialization guarded by iAmVerySafe: name="tests/introduction.cpp: Introduction.Doc_Example_1", lines=15 dfa_callguard(SiteInv, iAmVerySafe):- dfa_callfn(SiteInv, div); SiteInv = s(_, _, ScopeInv); cfa_parent(ScopeInv, function(FnInv)); bind_func(FnInv, iAmVerySecure). Transcend rules are written in ASP syntax — common syntax to write logic programs. This particular rule reads that for any function annotated with iAmVerySecure, certain specialization iAmVerySafe is chosen for div invocation. In this example an appropriate specialization is statically resolved, so the other specialization isn't even compiled. the, потому что их всего две. By providing custom rules it is possible to implement any polymorphism strategy, be it performed statically or dynamically. The example demonstrates basic workflow: transcend gathers available information about a program such as annotations and using custom rules makes a decision to guide compilation process, particularly by selecting appropriate specializations as in the above example.
- -
- - - <?xxe-sn 2ba2e84701s 2?>Build and Run on Linux - - Major dependencies: - - - - - - - - gcc 7 - - - - - - llvm 5, clang 5 - - - - - - boost 1.66 - - - - - - coco - - - - - - clingo - - - - Building tested on OpenSuse Leap 15. Please - change commands accordingly if using other distributions. - - Pull sources directly from - repository: - - git clone --recursive https://pgess@bitbucket.org/pgess/xreate.git - - Enter into the source directory and run the - following script to prepare building environment. Script will install the - required system packages as well as Coco and Clingo from sources: - - "Enter into source directory" - - тут перед directory явно нужен артикль. Гугл говорит, что определенный - - the - - - - - Carefully inspect scripts before - run - - - On OpenSuse - Leap 15: - - ./installation/prepare-opensuse-leap15 - - That was one time operation to prepare - environment. After that enter into build - directory and start actual tests building: - - "build directory": здесь ты - все-таки вначале указываешь имя объекта (build), и лишь потом родовое - название (directory) - - cd build -make - - After successful build you can run xreate - tests: - - cd .. -./build/tests/xreate-tests - - - - - Please pay attention that the working - directory should be the repository root - - - For consequent rebuilds after updates etc - invoke cmake as follows: - - #working dir build -cmake -DCMAKE_BUILD_TYPE=Debug \ - -DBUILD_XREATE_TESTS=1 \ - -DCOCO_EXECUTABLE=<FILE> \ - -DCLINGO_PATH=<DIR> \ - -DCOCO_FRAMES_PATH=../vendors/coco/generator/ \ - -DCMAKE_CXX_COMPILER=g++ ../cpp -make - - Cmake's selected parameters: - - - - - - - - BUILD_XREATE_TESTS Determines whether - to build tests - - - - - - COCO_EXECUTABLE Full filename of Coco - executable - - - - - - CLINGO_PATH Installed Clingo - directory - - "Directory of Clingo - installation": может, with Clingo installation? (это если речь идет о - папке, где хранятся инсталляционные файлы) Если наоборот, куда будет - устанавливаться - тогда Directory for installing Clingo. Оригинальный - вариант ("of Clingo installation") немного сбивает с толку. - - -
diff --git a/documentation/manual.json b/documentation/manual.json index f2ed4b0..8c9f315 100644 --- a/documentation/manual.json +++ b/documentation/manual.json @@ -1,35 +1,36 @@ { "book": "Xreate Manual", "pages": [ {"title": "Basics", "pages": [ {"title": "Introduction", "slug": "/", "filename": "index.xml.remarkup", "subtitle": "General information about Xreate"}, + {"title": "Build and Run", "slug": "build/", "filename": "build.xml.remarkup", "subtitle": "Getting started"}, {"title": "Syntax", "slug": "syntax/", "filename": "syntax.xml.remarkup", "subtitle": "Xreate syntax in detail"}, {"title": "Modules", "slug": "syntax/modules/", "filename": "modules.xml.remarkup", "subtitle": "How to reuse and combine existing code in Xreate"} ]}, {"title": "Transcend", "pages": [ - {"title": "Overview", "slug": "transcend/", "filename": "transcend.xml.remarkup", "subtitle": "Logic, declarative level of Xreate"}, - {"title": "Late Transcend", "slug": "transcend/late-transcend/", "filename": "latetranscend.xml.remarkup", "subtitle": "How reasoning is able to work at runtime"} + {"title": "Overview", "slug": "transcend/", "filename": "transcend.xml.remarkup", "subtitle": "Declarative level of Xreate"}, + {"title": "Late Transcend", "slug": "transcend/late-transcend/", "filename": "latetranscend.xml.remarkup", "subtitle": "Reasoning is able to work at runtime"} ]}, {"title": "Concepts", "pages": [ {"title": "Polymorphism", "slug": "concepts/polymorphism/", "filename": "polymorphism.xml.remarkup", "subtitle": "Let logic inference choose how program would behave at runtime"}, {"title": "Context", "slug": "concepts/context/", "filename": "context.xml.remarkup", "subtitle": "How to capture and use information about control flow and hierachy within program"}, - {"title": "Interpretation", "slug": "concepts/interpretation/", "filename": "interpretation.xml.remarkup", "subtitle": "Explains compile time computations and more"} + {"title": "Interpretation", "slug": "concepts/interpretation/", "filename": "interpretation.xml.remarkup", "subtitle": "Compile time computations and more"} ]}, - {"title": "Libraries", "pages": [ + {"title": "Extensions", "pages": [ {"title": "Containers", "slug": "concepts/containers/", "filename": "containers.xml.remarkup", "subtitle": "Automatic inference about the most apporpriate container implementation"}, {"title": "Communication", "slug": "communication/", "filename": "communication.xml.remarkup", "subtitle": "Safe usage of mutable as well as global variables"}, {"title": "Exploitation", "slug": "exploitation/", "filename": "exploitation.xml.remarkup", "subtitle": "Shared usage of the external resources - initialization and finalization"}, {"title": "Virtualization", "slug": "virtualization/", "filename": "virtualization.xml.remarkup", "subtitle": "Controls access to the external resources or different program's components"} ]}, {"title": "Transcend APIs", "pages": [ {"title": "AST API", "slug": "transcend/ast-api/", "filename": "ast-api.xml.remarkup", "subtitle": ""}, {"title": "Latex API", "slug": "transcend/latex-api/", "filename": "latex-api.xml.remarkup", "subtitle": ""}, {"title": "Modules API", "slug": "transcend/modules-api/", "filename": "modules-api.xml.remarkup", "subtitle": ""} ]} ] } diff --git a/documentation/virtualization.xml b/documentation/virtualization.xml index fea27c3..cafe5f1 100644 --- a/documentation/virtualization.xml +++ b/documentation/virtualization.xml @@ -1,541 +1,541 @@ <?xxe-sn 26yv439af40 1l?>Virtualization The chapter expands on the usage of context based polymorphism, in other words, reasoning over CFG, as a ground to implement application level virtualization. Желательно расшифровать аббревиатуру CFG, до этого она нигде не встречалась, и мне не ясно что она означает One way to approach the virtualization problem is to model it in terms of satisfying constraints imposed by environment over agents that operate within it, as presented below: sizo (distorted abbreviation for SEcurity ZOne): logical entity introduced to represent an environment and describe the desired virtualization outcome. zek (distorted abbreviation for SEcurity aGent): represents behaviour of the code in terms of virtualized resources access. По поводу длинных тире: насколько я знаю, они практически не используются в английском языке (как и наши «типографские» кавычки). Только короткие. Но эту информацию нужно проверить (PS: сегодня читал книгу на английском, и таки увидел там длинные тире). Basic idea is to automatically reason over information defined by sizos and zeks and produce virtualization plan as a solution that dictates which parts of code should be virtualized and how exactly. Such reasoning enables two features: Optimization. Allows choosing virtualization technique with the smallest performance penalty nevertheless satisfying necessary requirements. Safety. Validates manually chosen virtualization plan to ensure it is solid and operable by checking that it indeed satisfies requirements. Я бы вообще сократил: "to ensure it is solid, operable and satisfying the necessary requirements" In other words, context based reasoning provides improvements by virtualizing only necessary sections of code and only for necessary type of resources by employing as lightweight virtualization strategy as possible – just enough to comply with the safety and security requirements expressed by annotations in the code.
<?xxe-sn 26yv439af40 25?>Background Virtualization refers to abstracting code from the underlying resources used by it. Here the term 'resource' depicts any external entity such as a device, file, network connection etc, for which it is desirable to regulate access. Virtualization is a vast area and broad term that includes number of techniques on different levels to achieve several important goals such as: Shared access — allowing several clients to use the same resource while behaving as if each client were sole resource user, to simplify development and testing. Isolation — cornerstone of safety and behaviour repeatability achieved by minimizing influence of isolated clients between each other and external environment. Adaptation — allowing client application work in an unexpected environment it was not developed for, by emulating "native" familiar environment thus reducing adaptation and support costs. Due to the importance of goals achievable with virtualization, it is unavoidable in a long run. That being said, basic virtualization techniques have performance penalties arising from indirect and regulated access to underlying resources. Further discussion is concerned with what can be done to alleviate major virtualization inefficiencies by fine-grained control over what should be virtualized, when, and how.
<?xxe-sn 26yv439af40 2k?>Access Control A whole program can be broken down into one or more virtualization zones, each having different appropriate type of virtualization strategy. Such approach allows to model hybrid virtualization, i.e. different parts of a program are virtualized differently depending on certain conditions. To capture this concept, the term sizo is introduced, that refers to a logical entity that holds information about a particular zone necessary to find best suited virtualization strategy. Sizo is associated with context, + xlink:href="/d/concepts/context/">context, i.e. each zone spans over one or more code blocks. There is an annotation assign_sizo to specify sizo a code block is assigned to: SYNTAX: **assign_sizo**(//sizo-ref//). sizo-ref unique sizo's identifier Next thing is to specify which resources a particular sizo controls access to, as demonstrated below: SYNTAX: **assign_sizo_control**(//resource-type//). It indicates that the current sizo (sizo that spans over the code block wherein the annotation is located) regulates all access to resources of a given type, resource-type. Conversely, if for a particular environment there is no need to control e.g. file system access, no virtualization for file operations is applied. On the other hand, there is an annotation to mark a function that accesses one or another resource: SYNTAX: **assign_zek_access**(//resource-type//). Let's consider an example to demonstrate all the above: name="tests/virtualization.cpp: Virtualization.Doc_AccControl_1", lines=15 import raw ("scripts/cfa/context.lp"). //enable context reasoning import raw ("scripts/virtualization/virtualization.lp"). //enable virtualization reasoning guard:: strategy(direct) { openFile = function(filename::string):: int { printf("direct file access") } } guard:: strategy(common) { openFile = function(filename::string):: int; assign_zek_access(files) { printf("virtualized file access") } } main = function:: int; entry { context:: assign_sizo(zoneA); assign_sizo_control(files). openFile("/some/file") } The example outlines a dummy function openFile to model file system access. The function includes two specializations with the strategy(direct) guard to model direct access, and the strategy(common)guard to be invoked if virtualization is enabled. It is also annotated with assign_zek_access(files) to indicate that it accesses the file system. On the other hand, the context of the function main defines the zoneA sizo and enables control over file operations. Reasoning works with the provided information and decides whether it is necessary to enable virtualization. In this case, the answer is yes for zoneA, because of the fact that the sizo controls file operations and that there is actually a function within the sizo that requires file access. Consequently, the example outputs the following:virtualized file accessconfirming that specifically virtualized specialization of openFile was invoked.
<?xxe-sn 26yv439af40 3i?>Isolation As shown in the previous section, it is possible to enable (or disable) virtualization on a per resource basis. However, such functionality is limited in a sense that if several sizos allow access to the same resource they can interfere with each other. Thus, next step to consider is isolation, i.e. zeks in different sizos should not have the ability to access the same resource, but rather work with their own set of resources associated with a particular sizo. The following examples, just as the previous one, are focused on file operations as the most ubiquitous type of resources. One way to isolate file access is to associate a unique file prefix with each sizo. If virtualization is enabled, all filenames in the sizo are silently transformed on the fly by adding an assigned prefix. This way, all the file operations from one sizo are confined within a specific directory allocated solely for that particular sizo, or simply have a unique prefix if the same directory contains files belonging to a different sizo(s). name="tests/virtualization.cpp: Doc_Isolation_1", lines=15 main = function:: int; entry { seq { context:: assign_sizo(domainA); assign_sizo_control(files). openFile("test") } { context:: assign_sizo(domainA). openFile("test") } { context:: assign_sizo(domainB); assign_sizo_control(files). openFile("test") } } In this example, the file test is accessed from different sizos domainA and domanB. As several "competing" sizos are declared, they are isolated, and openFile resolves test to a different filename depending on which sizo it was called from. One possible way to implement the discussed strategy is shown below: name="tests/virtualization.cpp: Doc_Isolation_1", lines=15 import raw ("scripts/cfa/context.lp"). //enable context reasoning import raw ("scripts/virtualization/virtualization.lp"). //enable virtualization reasoning import raw ("scripts/virtualization/test-Isolation_1.assembly.lp"). //additional configuration DictSizo = type slave dict_sizo. Sizo = type slave virt_sizo. guard:: strategy(direct) { resolveFilename = function(filename:: string):: string; assign_zek_access(files) { filename } } guard:: strategy(prefix) { resolveFilename = function(filename:: string):: string; assign_zek_access(files) { dictSizo = intrinsic query("dict_sizo")::[DictSizo]. sizoId = intrinsic query late("sizo_current"->sizoCurrent:: Sizo):: int; demand(sizo) { loop fold(dictSizo->entry::DictSizo, 0->id):: int { if(entry[0] == sizoCurrent):: int { entry[1] } else { id } } }. buf = "00"::string. seq { sprintf(buf, "%d/%s", sizoId, filename) } { buf } } } openFile = function(filename:: string):: int { filenameReal = resolveFilename(filename):: string. printf("File opened: '%s'%c", filenameReal, 10) } Example outputs: File opened: '0/test' File opened: '0/test' File opened: '1/test' In this example, the function openFile calls resolveFilename to find out the real filename. It can be said that resolveFilename serves as hypervisor dereferencing file pseudonym into a real filename. For this purpose, resolveFilename consists of two specializations: specialization strategy(direct) serves the non-virtualized environment leaving the filename without any processing, while the other specialization strategy(prefix) implements the resolving strategy by adding a sizo-associated prefix to each file. More specifically, a unique index is assigned to each sizo, and resolveFilename uses the index as a file name prefix. Resolution function resolveFilename has only one parameter filename, deriving the required prefix from late context associated with a particular sizo. Client code has no way to influence resolving process and force it to use an unapproved prefix, thus accessing and interfering with files that belong to other sizos.
<?xxe-sn 26yv439af40 4c?>Isolation Categories Every optimization technique is applicable only if certain preconditions are met. Indeed, only a general approach can handle a general task. However, for practical instances some improvements are always possible by tailoring to a particular use case specifics and subtle details. In other words, the more information available, the more space there is for improvements. And the first step along this road is the very ability to express and reason about such additional information. As a demonstration, in order to improve reasoning to find out the optimal virtualization strategy for a particular use case, different sizo categories can be introduced, as below: Inward Isolation. The category describes sizo that prohibits access of other sizos to its internal resources, but is able to access external resources freely. For example, monitoring and supervision software may have been assigned this type of isolation, where it freely accesses subordinate zones but cannot be influenced from the outside. Outward isolation. The exact opposite of inward isolation. Allows access from external sizos, but is only allowed to use its own internal resources, so no influence over the outside world is possible. Appropriate for various sandboxes and testing environments to run a potentially insecure code. For file operations, inward isolation may be implemented as a virtualization strategy that requires from other sizos compulsory usage of file prefixes so that no other sizo could access internal data of inwardly isolated sizo. Conversely, outward isolation is compatible with the strategy that involves assigning a prefix for this very sizo, so it can in no way access any external data, being at the same time exposed to the outside world and any sizo that has a permission to know a unique assigned prefix able to access the internal data of the sizo in question. To put it simply, strategy for these types can be described with following points: Inward isolation — requires prefixes for other sizos. Outward isolation — requires a prefix for itself. There is an annotation introduced to declare a category for a current sizo: SYNTAX: **assign_sizo_category(inward)**. **assign_sizo_category(outward)**. Consider the example below: name="tests/virtualization.cpp: Doc_IsolationCat_1", lines=15 test = function:: int; entry { seq { context:: assign_sizo(zoneA); assign_sizo_control(files); assign_sizo_category(inward). openFile("test1") } { context:: assign_sizo(zoneB); assign_sizo_control(files); assign_sizo_category(outward). openFile("test1") } } There are two sizos declared in the code above. Using the reasoning apparatus developed in the previous sections, both sizos activate virtualization, for both of them control some file resources and both contain openFile that actually requires file access. However, this time additional bits of information are available, namely zoneA and zoneB are declared as inward and outward, respectively. According to the strategy outlined above, zoneA enables prefix based isolation strategy for zoneB, and zoneB enables isolation for itself as well. As a result, it is enough to virtualize only one zone (zoneB) leaving zoneA to enjoy a direct access to file resources. Example outputs are shown below, confirming that the direct file access is granted to zoneA: File opened: 'test1' File opened: '1/test1'
\ No newline at end of file +?>