diff --git a/documentation/Concepts/interpretation.xml b/documentation/Concepts/interpretation.xml index e102841..e5e6ec3 100644 --- a/documentation/Concepts/interpretation.xml +++ b/documentation/Concepts/interpretation.xml @@ -1,869 +1,882 @@ <?xxe-sn 26cy4nalqsw pu35zrt1abya?>Interpretation Interpretation is a compiler's mode reserved to evaluate, expand and simplify parts of a given program based on information available in this mode. On the other hand, Interpretation is a middle man, or an intermediate level, between the Transcend and Brute levels, as it facilitates communication between those by means of interpreting data of respective layers. It can be further divided into Upper and Lower Interpretations depending on the interaction with the layer we are focused on at the moment. mode whereby - как это перевести? - это режим с помощью которого xreate интерпретирует? Авторский смысл: это режим(компилятора) В КОТОРОМ компилятор интерпретирует. Program: Речь идет о компьютерной программе, или может приложении для смартфона, или алгоритме? Тогда лучше употребить соответственно software ('piece of software') / app / algorithm. Вообще "наши" компьютерные программы - это у них software, а не programs - - ДА ТУТ СЛОВО PROGRAM ПОДХОДИТ, особенно в контексте обработки программы с какимито целями, как здесь, чтоб ее интерпретировать. name="tests/interpretation.cpp: Interpretation.Doc_Intr_1" main= function:: int; entry { x= "a":: string. y= if (x=="b"):: string; i12n(on) {1} else {0}. y } In this example, the identifier y has an attached annotation i12(on) which indicates that the compiler should use compile-time interpretation to evaluate y. Once the simplification process is over, the function returns 0, with neither memory allocations for the string variable x nor any computation at runtime. Annotation - может лучше value или parameter? - да Annotation подходит There are two annotations reserved to control the interpretation process: i12n(on) Forces compiler to interpret the annotated expression, function, or function argument. It yields error if the expression is impossible to interpret. i12n(off) Disables interpretation for the annotated expression.
<?xxe-sn 26cy4nalqsw pu35zrt1abyt?>Eligible Expressions Currently the compiler is able to interpret the following expressions: Atomic instructions: numbers, strings, identifiers. Relational and logic operators e.g. x==true, x!=0. if, switch statements. [[#late-interpretation-or-e|Statement expansion]] allowed. Loop statements. [[#late-interpretation-or-e|Statement expansion]] allowed. Functions. [[#function-interpretation|Function calls]], [[#partial-or-late-function|Partial function call interpretation]]. interpreta - это так и нужно, или неполное слово? - этот кусок текста на сайте превратится в ссылку, это адрес ссылки, такой должен быть Index operator e.g. x = {1, 2, 3}. y = x[0], info = {planet="Earth"}. x = info["planet"]. List operators e.g. x = [1..10]. y={"day", "night"}.
<?xxe-sn 26cy4nalqsw pu35zrt1abzi?>Function Interpretation The whole function body may be subject to interpretation if it consists of interpretable expressions only. name="tests/interpretation.cpp: Interpretation.Doc_FnIntr_1" unwrap = function(data::unknType, keys::unknType):: unknType; i12n(on) { loop fold(keys->key::string, data->record):: unknType { record[key] } } test = function:: bool; entry { book = unwrap({ Library = { Shelf = { Book = "Aristotle's Politics" }}}, {"Library", "Shelf", "Book"}):: unknType. book == "Aristotle's Politics" } The above example demonstrates the unwrap function which is intended to be fully interpretable, as indicated by the function header's annotation. Obviously, the interpretable function requires that all its arguments are also interpretable. In this case the compiler is able to calculate the function's result at compile time with no byte code produced. Here is what the compiled code looks like (which will be also optimized out during the consequent compilation phases): name="tests/interpretation.cpp: Interpretation.Doc_FnIntr_1" test = function:: bool; entry { book = "Aristotle's Politics":: string; i12n(on). book == "Aristotle's Politics" } The example also reveals a number of similarities with dynamically typed programming languages: number of similarities - тут точно нужен артикль, неопределенный (a) если в смысле "много схожестей", и определенный (the) - если речь идет о точном их количестве. a dynamically typed - неопределенный артикль никогда не употребляется при множественных объектах - OK Relaxed types. Notice unknType type which has not been defined. It's interpreted well because the compiler completely ignores the type system since everything can be checked at compile time anyway. The Interpretation mode is exactly the level where the relaxed type system is possible without any performance penalties or safety concerns. Introspection abilities. Notice how it is allowed to treat list fields as string keys, so functions like unwrap can get list field name as a parameter. Possible errors, such as the list not having the requested field are easily spotted by the compiler during interpretation and there are no concealed runtime bugs. In a sense, it is a fair trade off between introspection expressiveness and possible compilation errors. no hard to catch runtime bugs - не вполне ясно. В смысле, "легко заметить баги проявившиеся во время операции"? Тогда лучше "its is easy to see runtime bugs", или может "the runtime bugs are possible" (если смысл такой, что могут проявиться ошибки/баги"). It's и другие подобные сокращения: лучше употреблять полную форму - it is, так как it's это разговорный вариант - OK. Additional reason for the arbitrary undefined type unknType being used in the example is to ensure that no compilation occurs and everything is done at the interpretation mode. In simple cases interpretation analysis could determine that a function is subject to interpretation with no annotation hints provided. name="tests/interpretation.cpp: Interpretation.Doc_FnIntr_2" unwrap = function(data::unknType, keys::unknType):: unknType { loop fold(keys->key::string, data->record):: unknType { record[key] } } test = function:: bool; entry { book = unwrap({ Library = { Shelf = { Book = "Aristotle's Politics" }}}, {"Library", "Shelf", "Book"}):: unknType; i12n(on). book == "Aristotle's Politics" } The only difference from the example above is the lack of annotation hint for unwrap. It can be seen that interpretation of the variable book is required which in its turn depends on unwrap. In this case analysis is capable enough to determine that unwrap is indeed possible to interpret, so no errors occur. "Developer requires interpretation" - тут речь о разработчике-программисте? Не вполне понятен смысл, поэтому пока оставляю как есть. - да программист, исправил There are, however, more complicated cases for interpretation analysis: Direct recursion. Interpretation analysis is able to correctly determine whether a function involving direct recursion (where the function calls itself) is subject to interpretation or not. Indirect recursion. Currently, when processing the indirect recursion (where a function is called not by itself but rather by another function), the analysis usually fails and relies on manually provided annotation hints. Below is an example of a direct recursion: name="tests/interpretation.cpp: Interpretation.Doc_FnIntr_3" unwrap = function(data:: X):: bool { if (data[0] == "the-end"):: bool {true} else {unwrap(data[0])} } entry = function:: bool; entry { unwrap({{{{"the-end"}}}}):: bool; i12n(on) } Function unwrap unwraps the nested list until the desired value is found. No function level annotation is required.
<?xxe-sn 26cy4nalqsw pu35zrt1ac0j?>Late Interpretation or Expansion Late Interpretation can be conceptualized as a partial expansion, i.e. a simplification or elimination of interpretable parts of certain statements. name="tests/interpretation.cpp: Interpretation.Doc_LateIntr_1" test = function(x:: int):: int; entry { comm= "inc":: string; i12n(on). y= if (comm == "inc"):: int {x + 1} else {x}. y } In this example, computation of y depends on comm and x. On the one hand, comm has an annotation that requires interpretation, while on the other hand x is unknown at the compile-time and thus cannot be interpreted. In this case the only way to satisfy contradictory requirements is to expand the if statement, since it is only possible to interpret condition part of the statement, leaving conditional blocks unchanged. In other words, the if statement is expanded which results in only one of the child blocks being compiled, x+1 in this example, based on already known fact that the else block would never be executed. "to interpret condition part of the statement" - это не смог понять. - `if (...) {..} else {...}` is a statement. It consists of condition part `if (..)`, and two blocks - "if-true" block and "if-false" block Due to the fact that expansion, as opposed to "pure interpretation", leaves some portion of the code for subsequent compilation it can also be called late interpretation for the result depends on runtime information and has memory and performance footprint. as having runtime footprint - не понял. Что-то связанное с требованиями к памяти? Но это кажется о программах, а не о interpretation - переписал фразу Below is a more complex example of a loop expansion: name="tests/interpretation.cpp: Interpretation.Doc_LateIntr_2" main = function(x:: int):: int; entry { commands = {"inc", "double", "dec"}:: [string]; i12n(on). loop fold(commands->comm::string, x->operand):: int { switch(comm):: int case ("inc") {operand + 1} case ("dec") {operand - 1} case ("double") {operand * 2} } } Identifier commands contains a list of operations that need to be interpreted as indicated by the corresponding annotation. Operand x is assigned at runtime. This is the same situation as in previous example, and it triggers expansion as expected. The result after expansion looks as follows: name="tests/interpretation.cpp: Interpretation.Doc_LateIntr_2" main = function(x:: int):: int; entry { x{1} = x + 1:: int. x{2} = x{1} * 2:: int. x{3} = x{2} * 1:: int. x{3} } In other words, this mimics the well known loop unrolling technique by putting several copies of the loop body in a row, each one for every item in the list commands. As of now, the following statements support late interpretation: Branching statements: if, switch, switch variant, switch late. Loop statements: loop fold. Functions. Other operators: query late.
<?xxe-sn 26cy4nalqsw pu35zrt1ac1n?>Partial or Late Function Interpretation Xreate supports cases where a function has mixed arguments in terms of interpretation, some of which need to be interpreted, while others need to be compiled. name="tests/interpretation.cpp: Interpretation.Doc_LateFnIntr_1" evaluate= function(argument:: num, code:: string; i12n(on)):: num { switch(code):: num case ("inc") {argument + 1} case ("dec") {argument - 1} case ("double") {argument * 2} case default {argument} } main = function(init::int):: int; entry { commands= {"inc", "double", "dec"}:: [string]; i12n(on). loop fold(commands->comm::string, init->operand):: int { evaluate(operand, comm) } } Looking at the function evaluate's signature in this example we can see only one argument code that requires interpretation. This means that the function evaluate is subject to a partial interpretation or, in other words, late function interpretation. In general, to enable late interpretation for a function, at least one of its arguments should be annotated as i12n(on). What compiler does next is to generate a number of distinctive function specializations. Each unique combination of interpretable argument values corresponds to its own function specialization. This should be used with cautiousness, since compiler can generate large amounts of code in some cases. What compiler does next is to generate number - то же самое, что в примеч. ниже (a number - несколько, the number - конкретное число).To enable late interpretation for function - тут перед function обязательно нужен артикль - определенный (the), если речь идет о evaluate, или неопределенный (а) если речь идет о любой функции (я указал the) - OK Based on the above example, three different evaluate specializations are generated as follows: name="tests/interpretation.cpp: Interpretation.Doc_LateFnIntr_1" main= function(init::int):: int; entry { operand = init:: int. operand{1} = evaluate1(operand):: int. operand{2} = evaluate2(operand{1})::int. operand{3} = evaluate3(operand{2})::int. operand(3) }
- <?xxe-sn 2f6e093xhxc 2?>Transcend and Interpretation + <?xxe-sn 2f6e093xhxc 2?>Queries SYNTAX: **intrinsic query** (//predicate//):: type; [//annotations-list//] predicate Denotes a Transcend predicate. Represents the value of the Transcend predicate predicate in the format as follows: If a predicate has only one argument, returns a list of elements of an appropriate type: int, string, variant or tuple. in case of several arguments, the arguments comprise a record. The function returns a list of records. Predicates correspond to variants. Interpretation can be viewed as the middle ground between high level Transcend and low level Brute. In essence, the principal role of Interpretation is to serve as a link between them by interpreting data for Brute from Transcend. The special built-in function intrinsic query is provided to query data from Transcend allowing to process it further. As a short example, assume that we have Transcend facts as follows: person("Ben"). This data can be queried as below: Persons = type [string]. //we expect a list of strings persons = function:: Persons { intrinsic query("person"):: Persons } The persons function in this example returns a list of persons supplied by Transcend. The example can be slightly rewritten using slave types which are reserved to automatically identify an appropriate type for the returned value. The next excerpt is equivalent to the previous one: Person = type slave person. //equivalent to string Persons = type [Person] persons = function:: Persons { intrinsic query("person"):: Persons } +
+ +
+ - Querying allows to use powerful Transcend + <?xxe-sn 2fxwo1r89a8 3?>Querying Example: GUI + + Querying allows to use powerful Transcend capabilities to solve convoluted problems, consequently retrieving reasoning solutions by Brute for efficient processing. Consider a more complicated example dealing with a GUI. - First, let us start off defining more or - less semantically an application's GUI on Transcend level: + First, let us start off defining more or + less semantically an application's GUI on the Transcend level: - name="tests/association.cpp: Association.Doc_IntrinsicQuery_2", lines=15 + name="tests/association.cpp: Association.Doc_IntrinsicQuery_2", lines=15 %Layout consists of two blocks: block(my_content; my_nav). %Assign roles to the blocks: role(my_content, body). role(my_nav, navigation). %Navigation block can be in either an iconized or expanded form: form(none; expanded; iconized). allowed_form(my_nav, (expanded; iconized)). %Visual theme: background(my_content, color(blue)). background(my_nav, color(grey)). - Above we have described GUI consisting of + Above we have described GUI consisting of two blocks: main content and navigation blocks. The same application can - look differently depending on platform or viewport properties. Let us + look differently depending on a platform's or viewport properties. Let us define a platform: - name="tests/association.cpp: Association.Doc_IntrinsicQuery_2", lines=15 + name="tests/association.cpp: Association.Doc_IntrinsicQuery_2", lines=15 % The height is greater than the viewport's width: orientation(portrait). - Having an application's semantic description + Having an application's semantic description as well as a platform's description we can now combine them using additional rules to produce the final result: how the application should look like on the given platform. - name="tests/association.cpp: Association.Doc_IntrinsicQuery_2", lines=15 + name="tests/association.cpp: Association.Doc_IntrinsicQuery_2", lines=15 % Portrait orientation rules: %Determine appopriate navigation list's form: form(Nav, iconized):- orientation(portrait); allowed_form(Nav, iconized); role(Nav, navigation). %Determine blocks' layout: align(Nav, bottom_of(Body)):- orientation(portrait); role(Nav, navigation); role(Body, body). % Landscape orientation rules: form(Nav, expanded):- orientation(landscape); allowed_form(Nav, expanded); role(Nav, navigation). align(Nav, left_of(Body)):- orientation(landscape); role(Nav, navigation); role(Body, body). - In short, the rules above read that we - place the expanded navigation block my_nav - and the content block my_content in - a row for wide displays; conversely, my_content - and iconized my_nav on top of each + In short, the rules above read that we place + the expanded navigation block my_nav + and the content block my_content in a + row for wide displays; conversely, my_content + and iconized my_nav on top of each other for narrow displays. - After Transcend has decided actual forms - and blocks alignment, the next step is to retrieve solutions denoted by - the align and form + After Transcend has decided actual forms and + blocks alignment, the next step is to retrieve solutions denoted by the + align and form predicates and to actually draw GUI elements: - name="tests/association.cpp: Association.Doc_IntrinsicQuery_2", lines=15 + name="tests/association.cpp: Association.Doc_IntrinsicQuery_2", lines=15 //Define types: Block = type slave block. Role = type variant {body, navigation}. Alignment = type variant{ bottom_of:: Block, left_of::Block }. Layout = type {Role, Alignment}. //Determine role and form: drawBlock = function(block:: Block):: Drawing { forms = intrinsic query ("form"):: [Form]. formCurrent = getBlockForm(forms, block):: Form. roles = intrinsic query ("role"):: [Role]. roleCurrent = getBlockRole(block):: Role. switch variant (roleCurrent):: Drawing case (body) {drawBody(formCurrent)} case (navigation) {drawNavigation(formCurrent)} } //Determine layout draw = function:: Drawing; entry { layout = intrinsic query ("layout"):: Layout. blockA = layout[0]:: Block. switch variant (layout[1]->blockB):: Drawing case (bottom_of) {drawVerical(blockA, blockB)} case (left_of) {drawHorizontal(blockA, blockB)} } - Notice that the draw - and drawBlock functions work with + Notice that the draw + and drawBlock functions work with compile time data from Transcend, thus all this code after interpretation gets simplified into the following: - drawVertical(drawBody(none()), drawNavigation(iconized())). + drawVertical(drawBody(none()), drawNavigation(iconized())). - The example above demonstrates the - possibility to delegate to Transcend intelligent + The example above demonstrates the + possibility to delegate to Transcend intelligent tasks, such as adapting a GUI to a particular platform, and leaving Brute with efficient implementation matters.
<?xxe-sn 26cy4nalqsw pu35zrt1ac21?>Domain Specific Languages and Interpretation DSL is an idea of expressing various concepts in a lapidary and concise form. Xreate recognizes and acknowledges very successful and beneficial DSL usage in certain areas, primarily to express queries and configs, to name a few. It is possible to use interpretation abilities to emulate DSL. Developer can express the desired functionality in the form of nested lists of numbers, variants and strings which are then processed by a partially interpreted function. Such function in its turn transforms the input data into a set of low level compilation instructions so there is no runtime overhead.
<?xxe-sn 26cy4nalqsw pu35zrt1ac26?>On Interpretation Analysis Analysis follows classical type reconstruction algorithms to determine which expressions are subject to interpretation and check the correctness of reconstruction w.r.t. developer-provided annotations. Analysis consists of two general parts: Inference. Infers if it is possible to interpret an expression based on its already inferred argument's decisions. Unification. Assigns an appropriate decision w.r.t. previously inferred expectations and developer-provided hints as well.
\ No newline at end of file diff --git a/documentation/Transcend/transcend.xml b/documentation/Transcend/transcend.xml index 26d6895..757e703 100644 --- a/documentation/Transcend/transcend.xml +++ b/documentation/Transcend/transcend.xml @@ -1,578 +1,578 @@ <?xxe-sn 2ajela3ur5s 7r?>Transcend Transcend is a compilation phase and a process of reasoning about a program in order to influence final compilation results. First, the compiler extracts annotations from a source code as well as other logic facts from a number of different sources. Second, logic facts are coupled with logic rules, that describe how to process input data, to form a complete logic program. Finally, a solver processes the logic program and produces decisions that affect and control compilation in a number of ways. Crucial difference of annotations from language keywords is that they do not have any predefined meaning and semantic; only custom developer provided rules make them matter. Currently, an external logic solver Clasp is used to perform Transcend tasks. Hence, logic rules are written(and annotations are converted to) in the ASP format: one of standard first order logic notations.
<?xxe-sn 2f0cduzin5j -wunr7fl0rw84?>Reasoning Solutions Transcend prepares solutions to verify, control and guide compilation process. For each uncertain situation the compiler consults reasoning solutions to know how to proceed. Thus, many compilation aspects are delegated to Transcend and are ultimately exposed to a software developer. Transcend solution are used in a number of ways as follows: Direct + xlink:href="/d/concepts/interpretation/#queries">Direct connection via the query built-in function. A program can request and explicitly process received data from Transcend as it sees fit. Function level polymorphism. This is the principal way for Transcend to interfere in compilation. Polymorphism is based on a possibility for a function to have several specializations. Each time the function is invoked in a client code, Transcend decides which exactly specialization to call. This gives a deep control over final program behaviour. Module level polymorphism. Transcend decides which modules to choose that satisfy a client code's requirements. The compiler allows Transcend to add hidden parameters every time specific functions are invoked. This is implemented to support the Context concept. Diagnostics. Transcend is able to validate different aspects of a program and print diagnostic messages to signal found inconsistencies. As an example, suppose we want to control functions visibility and want to separate the visibility(private) functions from the rest of a program: name="tests/transcend.cpp: Transcend.Doc_Diagnostics1" sum = function(a:: int, b:: int) :: int; visibility(private) { a + b } calculate = function(a:: int, b:: int):: int; visibility(pub_interface) { sum(a, b) } test = function(a:: int, b:: int) :: int; entry { sum(a, b) // we may not invoke this directly } Transcend converts the code above to logic facts as follows(the relevant part is shown): function(sum) function(calculate) function(test) bind_func(sum,visibility(private)) bind_func(calculate,visibility(pub_interface)) bind_func(test,entry) cfa_parent(0,function(sum)) cfa_parent(1,function(calculate)) cfa_parent(2,function(test)) cfa_call(1,sum) cfa_call(2,calculate) At this point all the annotations are completely unknown to the compiler. Next, we need to write rules to check that the visibility(private) functions are called either by another visibility(private) ones or by the visibility(pub_interface) functions which are intended to act as a contact point, the only allowed gate between the private part and the rest of a program: name="tests/transcend.cpp: Transcend.Doc_Diagnostics1" % Define which functiones are allowed to invoke private ones allowed( visibility(private); visibility(pub_interface) ). % Check every invocation for violations: warning("Visibility violation", FuncFrom, FuncTo):- cfa_call(ScopeFrom, FuncTo); bind_func(FuncTo, visibility(private)); scope_func_dict(ScopeFrom, FuncFrom); { bind_func(FuncFrom, Visibility): allowed(Visibility) } 0. Given the rules Transcend goes through all the invocations to check are there any possible visibility violations. For this example Transcend generates a diagnostic message: warning("Visibility violation",test,sum). This way it is possible to validate and guide compilation process by analysing program properties employing provided processing rules.
<?xxe-sn 2ajela3ur5s 7x?>Annotations' Syntax Xreate's annotations comprise optional supplementary information to be processed by the compiler along with a source code proper with an end goal being to affect a compilation process. Annotations are special expressions in the following form: 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 Code blocks and context Functions and Function Guards Modules
<?xxe-sn 2ajela3ur5s 8v?>Expressions SYNTAX: //expression// **::** //type//**;** //annotation-list//. type The expression's type annotation-list one or more annotations attached to the expression. Annotations are delimited by semicolon. An example: name="tests/transcend.cpp: Transcend.Doc_Expressions1" test = function:: int; entry { x = 5:: int; arithmetic(fast). //an annotation applied to an identifier y = ((x - 8):: int; arithm_optimization(off)) * 2:: int. //an annotation applied to a nested expression x+y } For readability's sake compound statements(e.g. loops) have slightly different syntax for annotations. See particular statement's syntax for details. A current limitation is that expression's annotations are always preceded by a type, hence to annotate nested expressions it is necessary to duplicate the expression's type.
<?xxe-sn 2ajela3ur5s 9b?>Code Blocks and Context SYNTAX: **context** :: //annotations-list//. annotations-list A list of annotations delimited by semicolon Code block annotations are called context. The keyword context is reserved to declare annotations within an enclosing code block. An example: 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 Despite of "annotations do not have any predefined meaning" being a rule of thumb, still there are deviations in Xreate; few annotation that have special meaning are: entry Specifies the entry point of a program. See Function Syntax. final Specifies the fixed point of loops. See Loops.
<?xxe-sn 2ajela3ur5s a5?>Annotations and Reasoning Annotations is a mechanism to express additional pieces of information and can occur in a source code or accompanying files. They are of declarative nature in a sense that they express specific properties of and relations between different entities, such as: identifiers and expressions, statements, code blocks, functions, modules or even a whole program. Annotations are explicit facts about a source code provided by a code writer in an explicit form. Beside annotations, there are other sources of information, in other words, implicit facts that are automatically inferred by various analysis phases to express useful insights regarding an analysed code. Such pieces aren't exposed directly to a developer but accessed and used internally at the reasoning phase along with annotations. All types of input are summed up below: Explicit annotations Annotations provided by a code writer in order to explicitly affect compilation. Code analysis Different code analyses provide information implicitly inferred from a source code. Supervision External facts that reflect a hardware and/or an environment where compilation takes place or where a program is supposed to work. There are many supervision layers possible, from custom compiler's mode, to OS- or computer- or even network-wide levels. In other words, supervision covers local or client supplied annotations, e.g. prohibits web cam usage, or external network resources access. Audit Third party supplied external information that reflects additional software properties, e.g. results of security audit. Reasoning rules Reasoning infers additional facts from a 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. A developer is free to define and use custom annotations to express desired properties without prior changes to the compiler.
<?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 only an input for a reasoning procedure that ultimately decides how exactly to influence compilation.
<?xxe-sn 2ajela3ur5s b7?>Cooperation Annotations are gathered from different sources enabling annotations to complement each other. The compiler blends in annotations originated from various sources seamlessly to improve decisions quality.
<?xxe-sn 2ajela3ur5s ba?>External Sources and Adaptability Annotations can be used not only to express properties of a program itself but also properties of a local environment(OS, computer, local network) where the program is supposed to run. Thus, in fact, the compiler operates by information that is usually inaccessible during software development and can't be reflected in a program code otherwise. In essence, it is postcompilation - a process of adjustments to a particular environment and functioning mode.
<?xxe-sn 2ajela3ur5s bd?>Feedback Traditionally software has a rigid strictly defined hierarchical structure of interaction between components. For example, let us focus on a client-service model. A service works the same regardless of a particular client in order to be compatible with as wide set of different clients as possible. However clients may use only small subset of service functionality or use it in a specific and predictable order. Generally speaking, the service in case of having additional information about a particular client is able to serve requests more efficiently in many situations. It can be conceptualized as a feedback from a client. Annotations is a good candidate to express feedback to improve interaction quality.
<?xxe-sn 2ajela3ur5s bj?>Resiliency As a program grows and goes through multiple reworks and rewrites many initial assumptions about the code and relation between different parts invalidated. Some implementation details and approaches became outdated and code quality deteriorates. A dIfferent picture is if the code uses annotations to express important properties. Any changes in an underlying code lead to a restarting of a reasoning procedure which adjust implementation decisions to be as optimal in a changed environment as before.
diff --git a/documentation/exploitation.xml b/documentation/exploitation.xml index 299281a..784c0f9 100644 --- a/documentation/exploitation.xml +++ b/documentation/exploitation.xml @@ -1,490 +1,541 @@ <?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, - 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. + another topic that deals with I/O, exploitation approaches the subject from + a different angle — it is concerned with order + of operations, a sequence in which different clients jointly use + the same resource, and it deals with corresponding difficulties, e.g. + ensures proper initialization of a resource before its 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 + Annotates a 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. + is expected to do nothing as initialization is either not 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" + side effects has received considerable traction. Indeed, side effects are + something that is hard to take into account, and thus programs that have + side effects are inherently unsafe, so best coding practices rightfully + suggest to isolate the code that produces side effects as much as + possible. It is so called pure functional languages whose philosophy goes + even further and frames side effects as something opposite of "pure" and + built around effectless computations, to the point that some languages' + design itself includes side effects producing constructs, such as I/O, + describing them as an afterthought, as something almost + unnecessary. + + Я тут взял на себя смелость + подредактировать последнее предложение, посмотри внимательно - все ли я + правильно понял + + However, in reality the opposite is true, as + most applications' sole responsibility is to communicate with the "outside + world", reacting to the external events and changing the "world's 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. + only important effects + produced by a program, and they surely deserve a first class support from + a programming language and justify the efforts to develop an approach to + alleviate the 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 + One complexity with taking side effects + into account is that the final result depends on an exact + order of operations. For many techniques, this harshly impacts + both performance and safety, e.g. caching or 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 + Мне не очень нравится фраза + "deal with possibly undetermined beforehand order of execution". Выглядит + очень громоздко. Может, лучше сказать "or are connected with such an order + of execution that was not determined beforehand". + + In this chapter, it is assumed that final + effects of execution are 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 + those that deal with an exploited resource. Other (unannotated) code + blocks are assumed to not produce exploitation effects, so they are + excluded from consideration. Thus reasoning about effects is reduced to + considering all possible exploitation paths, checking if they meet certain + requirements that define valid exploitation, and making corrections if + needed and possible. + + The result of the reasoning is called + exploitation plan — a + specification that defines the 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. + Annotations are used to express certain + aspects of side effects to enable further reasoning. They indicate the + code blocks that deal with a resource as well as provide additional + information about how exactly it is exploited, e.g. using, + initializing or deinitializing the 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. + Existing code paths extracted during + source code processing and coupled with relevant annotations are + enough to construct all possible exploitation paths and analyze them. + The analysis determines possible (weak) + paths that can either occur or not occur during particular execution, + as well as certain paths (strong) + that occur under any conditions. Also it checks if an exploitation + path is valid against certain exploitation rules, e.g. initialization + always occurs before the actual usage, and if it is possible to + correct the 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. + The reasoning's result is an + exploitation plan that dictates the order and strategy of exploitation + presented in the form of an 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. + Exploitation-related side effects are + viewed as a set of additional restrictions over the operations' order. + Only the subset of possible reorders is still valid w.r.t. side + effects. Transcend's task is to achieve a refined set of valid orders. + Thus techniques that rely on reordering enjoy an 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. + Safety. Validates the existing + exploitation plan, or determines if it is possible at all to safely + exploit a given resource. Compiler signals an 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. + program. Sometimes refactoring or other code changes break those + dependencies, which inevitably results in regressions. Exploitation + catches this sort of regressions and automatically regenerates the + exploitation plan suited for 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 + for example, by preventing resource initialization in several places + if it can be done safely in just one place, 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 + When it comes to reasoning about the order + of execution and possible code paths, the 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 + Unlike the usual function-bound domination + analysis, when a separate domination tree is produced for each function + defined in a program, Exploitation requires a program-bound analysis, that + is taking into account the control flow across all functions in a program. + It is a computationally intensive task to perform an 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. + takes into account the code blocks that deal with or, in other words, + exploit external resources. Thus there is no necessity to build a 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: + against some predefined constraints. Depending on complexity of the + constraints, i.e. the number of different exploitation events that are + sought for in each path, reasoning goals are 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. + Meaning that all paths are checked to determine if there is + exploitation at all or not, and if there is 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. + Deals with the situations where it is enough to check only two + different exploitation events occurring in a required order. It can be + useful for example, to check whether all resource uses occur after it + is initialized. + + "to check only two + different exploitation events occur in a required order" - нужно + уточнить смысл фразы. "Уточнить только два события, осуществляющиеся в + требуемом порядке", или "уточнить, осуществляются ли два этих + события"? Я использовал герундий (occur - occurring), как более + нейтральный вариант. Higher Order Exploitation. - Expresses constraints involving several(more than two) 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. + Exploitation is an important instance of the zero order + constraint. It is a useful mechanism for the developer to annotate a + function or part of a program as effect free in terms of exploitation. + Thus, effectless, clean or pure code can be clearly separated from the + effectful part, and compiler raises a compilation error in case of + accidental mixing or using "wrong" type of code in a non-appropriate + environment.
<?xxe-sn 26yv439af40 v?>Resource Initialization - One important problem related to an + One important problem related to 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. + initialized before its first usage and, additionally, that it is not + initialized more than once during the exploitation session. This is the + instance of first order exploitation since in a validation mode it is + enough to check the exploitation plan to ensure that every resource usage + was 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: + For the 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. + The central idea of the algorithm is to + consider candidates for initialization only among those code blocks + that dominate a given + usage site. Obviously, initialization in the 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 + for actual initialization in such way that they cover all the found usage sites. - For code blocks chosen for - initialization specialization exploitation(init) - is set, for the rest specialization exploitation(none) - is used. + For the code blocks chosen for + initialization, the specialization exploitation(init) + is set, while for the rest of the code blocks the specialization + exploitation(none) is + used. - Look at the example below: + Please take a 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. + that executes sequentially the following commands: open a file (scopes #1 + and #2), write some text (scope #3), and finally, close the file (scope + #4). It represents a 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 + 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 + initialize a 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 + the 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. + the resource before usage. Next task for exploitation is to choose the + correct exploitation plan, i.e. to assign strategies for all possible + initialization places in the effort to initialize the 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 + to actually initialize the file. The other one is automatically marked + with exploitation(none) to invoke a different specialization of openFile - that does nothing since the file is already initialized. + that does nothing since the file was already initialized.
+?> \ No newline at end of file diff --git a/documentation/index.xml b/documentation/index.xml index 8c227b4..38c577d 100644 --- a/documentation/index.xml +++ b/documentation/index.xml @@ -1,425 +1,434 @@ <?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" is all about a developer - oriented side focused on an ability to easily write, read, reuse, 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 three - dimensions: efficiency, safety, and flexibility. 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. Blending - features of seemingly incompatible programming paradigms is a basis of - Xreate's design principles. + Here "high level" refers to the developer + oriented side meaning exactly an ability to easily write, read, reuse, 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 three dimensions: efficiency, safety, and flexibility. 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. Blending features of seemingly incompatible programming paradigms is a + basis of Xreate's design principles. To achieve the aforementioned design goals, Xreate consists of three distinctive layers: 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. Brute 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 declarative type layer called Transcend. Transcend is a logic reasoner that is appropriate to do management-type work — it analyzes, oversees and controls Brute by guiding compilation process. More precisely, 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. Unlike usual static analysis tools, Transcend directly controls compilation(see Basic Example) and able to make decisions even based on data available only at runtime(see Late Transcend) 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. + used as a contact point and interpreter between Brute and Transcend. See + an example. On a syntactic level, Xreate is a procedural language with extensive use of annotations — arbitrary unconstrained metadata that a 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 не нужен There are several extensions already implemented to give a feeling what does this structure can be used for. Containers chapter describes that it is possible to reason about and automatically choose the most appropriate data structure's implementation depending on how it is used in the code. Look at the example below: x = [1, 2, 3]:: [int]. Container x does not have well defined implementation just yet. Only by looking how it is used throughout the code, the compiler is able to decide how exactly to store container's data. Interaction of different components and joint use of external resources is covered by Exploitation: logger = createFileLogger("/some/file"):: Logger. ... write(logger, "First log entry"). ... write(logger, "Last log entry"). Exploitation reasoning allows to determine when it is the first, last access to resources such as files, in other words, it infers access order. As a result it is possible to automatically initialize / destruct related resources. Unlike RAII, an another related technique, Exploitation is reserved to manage resources usage that spans across different parts of a program: modules, plugins, etc. Virtualization reasoning also helps to work with external resources by enabling access control if and when it is needed only. Example: openFile("/some/file"):: string; assign_sizo(zoneA). openFile("/some/file"):: string; assign_sizo(zoneB). If the compiler recognizes file access from the different zones, as in this example, it applies an appropriate virtualization strategy enough to ensure that instructions that belong to different zones do not interfere with each other. Unlike "pure", academic languages, Xreate targets safe and reliable usage of effectful computations such as IO that is covered above as well as mutable structures described in the Communication chapter. Note, that the described extensions are not part of the compiler and developers can write their own custom transcend rules to cover other aspects.
<?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:: int, b:: int):: int { a / b } } guard:: iAmVerySafe { div = function(a:: int, b:: int):: int { if ( b == 0 ):: int { zeroDivisionErrCode() } else { a / b } } } test = function:: int; entry; iAmVerySecure { div(10, 5) } Here entry point of the program is a function test recognized so by the compiler because of annotation entry in its signature. There are also two functions with the same name 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 a code author writes 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, being "unacceptably slow" due to an extra check instruction, though. This is a basis of polymorphism — client's code test is able to work with any specialization, and the 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. + rules makes decisions to guide various aspects of compilation process, + particularly by selecting appropriate specializations as in the above + example.
<?xxe-sn 2fchdmt7vgg 2?>More Advanced Example Suppose we write a program to generate a web page consisting of several blocks(e.g. a header, a footer) constructed independently by different parts of our program. In order to organise the code, we express our intention that all blocks should be sent to a client in a very specific order: first a header, then a body and footer, as below: name="tests/exploitation.cpp: Exploitation.Doc_ExampleEov_1", lines=15 eov_expect( webpage, header, body; %we expect body to be sent after header webpage, body, footer %.. and footer after body ). This is similar to Exploitation: we are working with the external resource webpage and want to take into account an exact order of resource exploiting operations. Then, we write code like this: send("Header"):: Content; eov_checkpoint(webpage, header). We mark the operations we are interesting in as checkpoints(here header is the name of a checkpoint and webpage is the resource the checkpoint refers to) and want to know are checkpoints executed in the expected(as defined above) order. If it so happens that these blocks are constructed in the correct order in our program we may send them immediately. Otherwise, we must cache already constructed content till a whole page is generated to ensure correctness. In other words, clearly, there is an opportunity for optimizations for caching has not only memory overhead but delays response latency(time before the first block is sent) as well. We write two implementations immediate_output and cached_output each for the corresponding case: name="tests/exploitation.cpp: Exploitation.Doc_ExampleEov_1", lines=15 //type to store either sending error code or cached content Content = type variant { errcode:: int, message:: string }. //Send immediately: guard:: immediate_output { send = function(content:: string):: Content { errcode(printf("%s", content)) } } //Cache content to send it later: guard:: cached_output { send = function(content:: string):: Content { message(content) } } These implementations should be registered for the compiler to know which one to use: name="tests/exploitation.cpp: Exploitation.Doc_ExampleEov_1", lines=15 eov_analysis( success, immediate_output; fail, cached_output ). Predicate eov_analysis compares actual checkpoints execution order with the expected one and chooses either of two implementations depending on the result. This way, it is guarantied that immediate sending is chosen only if it is safe to do so to avoid unnecessary caching. Thus we can safely change and adapt our program knowing that clients always receive web page's content in the correct order by automatically employing the most efficient content delivery strategy depending on particular circumstances.
<?xxe-sn 2fs1xxghz93 -wunr7fl0rw8t?>Differences from other languages it is convenient to talk about intentions in order to outline a vast landscape of programming languages and point out - the place of Xreate on it, i.e. to compare languages on a basis do they + the place of Xreate on it, i.e. to compare languages depending on do they allow to express a developer's intentions along with raw code that can be - used on many occasions, e.g. to validate code's correctness. Traditionally - type system is used to declare intentions. At closer look, types in - (imperative) statically typed languages contain information as - follows: + used on many occasions, e.g. to validate the code's correctness. + Traditionally type system is used to declare intentions. At closer look, + types in (imperative) statically typed languages contain inseparable + combination of the following: Intentions, such as "that - variable is a string". + variable is a string". - Usage patterns. A new code + Usage patterns: a new code should play nicely with the rest of a program, e.g. if a program works - with Unicode, a new string variable should be also of Unicode - type. + with unicode, a new string variable should be also of unicode family + type(even if this is not necessary for a given part of code) Platform constraints, e.g. if a platform supports wide strings natively, a new string variable should also be a wide string. In this regard, in general, statically typed languages are overconstrained, - they require developers to provide more information then they intend to. - This generally hinders code reuse and adaptation; to work on a new - platform, code requires porting: a process of re-expressing underlying - intentions once again with the new platform's constraints. + they require developers to provide more information than they intend to. + This usually hinders code reuse and adaptation; to work on a new platform, + software requires porting: a process of re-expressing underlying + intentions once again with the new platform's constraints. On the other side, dynamically - typed languages in this regard are underconstrained, + typed languages are underconstrained, since they do not allow to express all desirable intentions. This leads to - a disastrous inefficiency and code fragility because any errors can be - caught only at runtime. + disastrous inefficiency and code fragility because any errors can be + caught only at runtime. - OOP languages are hugely - successful among other reasons because they provide classes - to more finely express intentions, e.g. String, + As an example, OOP languages are + hugely successful among other reasons because they provide + classes to more + finely express intentions, e.g. String, UnicodeString, Utf8String with exact behaviour being hidden in implementation details. - Xreate in its turn offers - annotations for developers to express intentions, e.g. string;i_dont_need(cow) - (copy-on-write implementation). Annotations alone is not enough to fully - determine necessary types thus the compiler finishes them by looking at - usage patterns along with platform properties in order to infer most - efficient implementations. - - Also there is an area beyond - type systems capabilities, since types are designed to express intentions - only about data flow. However as shown in the previous example it is also - useful to express intentions about program structure properties, such as - operations order. + Xreate in its turn is based on + the idea to allow developers express as much or as little intentions as + they want to. This is a way to reach one of the the language's goals to + facilitate writing of easily reusable and adaptable software. On a syntax + level, annotations are used to express intentions, e.g. string;i_dont_need(utf8)(note + the modality, annotations can express boundaries, preferences, etc. ). + + + This approach obviously leads to problems + with software's performance and efficiency. For most high level languages, + compilers rely on defaults to fill in unspecified by the developer gaps in + the exact implementation details. Usually languages provide standard, + default data structures the developer have no control over. However Xreate + follows another approach: to resolve this contradiction, the compiler + determines necessary implementation details not only depending on + annotations, but also by looking at usage patterns along with platform + properties trying to infer most efficient implementations in any given + circumstances.