diff --git a/config/default.json b/config/default.json index 631feec..d52c52a 100644 --- a/config/default.json +++ b/config/default.json @@ -1,74 +1,74 @@ { "containers": { "id": { "implementations": "containers_impl", "linkedlist": "linkedlist" }, "impl": { "solid": "solid", "onthefly": "onthefly" } }, "logging": { "id": "logging" }, "function-entry": "entry", "transcend": { "bindings" : { "variable": "bind", "function": "bind_func", "scope": "bind_scope", "function_demand" : "bind_function_demand", "scope_decision": "bind_scope_decision" }, "context" : { "decisions":{ "dependent": "resolution_dependency" } }, "nonevalue": "nonevalue", "ret": { "symbol": "retv", "tag": "ret" } }, "tests": { "template": "default", "templates": { - "troubleshooting":"Exploitation.Doc_ExampleEov_1", + "troubleshooting":"*", "documentation":"Modules.Doc_*:Modules_API.Doc_*:Interpretation.Doc_*:AST.Doc_*:Loop.Doc_*:LateReasoning.Doc_*:Latex.Doc_*:Polymorphs.Doc_*:Transcend.Doc_*:ASTCorrespondence.Doc_*:Virtualization.Doc_*:Exploitation.Doc_*:Communication.Doc_*:Introduction.*", "default": "*", "ast": "AST.*", "effects": "Effects.*", "basic": "Attachments.*", "compilation": "Compilation.*", "communication": "Communication.*", "cfa": "CFA.*", "containers": "Containers.*", "dfa": "DFA.*", "diagnostic": "Diagnostic.*", "dsl": "Association.*:Interpretation.*", "exploitation": "Exploitation.*", "ExpressionSerializer": "ExpressionSerializer.*", "externc": "InterfaceExternC.*", "loops": "Loop.*", "latereasoning": "LateReasoning.*", "latex": "Latex.*", "modules": "Modules.*", "polymorphs": "Polymorphs.*", "intrinsic-query": "Types.SlaveTypes*:Association.TypedQuery*", "types": "Types.*", "virtualization": "Virtualization.*", "vendorsAPI/clang": "ClangAPI.*", "vendorsAPI/xml2": "libxml2.*" } } } diff --git a/cpp/tests/ast.cpp b/cpp/tests/ast.cpp index 5072b32..1a6c65a 100644 --- a/cpp/tests/ast.cpp +++ b/cpp/tests/ast.cpp @@ -1,229 +1,254 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ * * ast.cpp * * Created on: Jun 11, 2015 * Author: pgess */ #include "supplemental/docutils.h" #include "xreatemanager.h" #include "main/Parser.h" #include "supplemental/defines.h" #include "gtest/gtest.h" using namespace std; using namespace xreate; using namespace xreate::grammar::main; TEST(AST, Containers1) { FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate", "r"); Scanner scanner(input); Parser parser(&scanner); parser.Parse(); assert(!parser.errors->count && "Parser errors"); fclose(input); } TEST(AST, InterfacesDataCFA) { XreateManager* man = XreateManager::prepare ("interface(cfa){\n" " operator map :: annotation1.\n" "}"); auto answer = man->root->__interfacesData.equal_range(CFA); EXPECT_EQ(1, std::distance(answer.first, answer.second)); Expression&& scheme = move(answer.first->second); EXPECT_EQ(Operator::MAP, scheme.op); EXPECT_EQ("annotation1", scheme.getOperands().at(0).getValueString()); } TEST(AST, syntax_recognizeIdentifiers) { XreateManager* man = XreateManager::prepare(R"Code( test= function(a:: num):: num; entry { a = b:: int. b = 8:: int. a } )Code"); } TEST(AST, syntax_operatorIndex) { XreateManager* man = XreateManager::prepare(R"Code( test= function(a:: num):: num; entry { b = a[1]. b } )Code"); } TEST(AST, Variants_switch) { XreateManager* man = XreateManager::prepare(R"Code( Color = type variant{Blue, White, Green}. main = function:: int { x = White()::Color. switch variant(x)::int case (Green) {0} case (White) {1} case (Blue){2} } )Code"); Expression e = man->root->findFunction("main")->getEntryScope()->getBody(); ASSERT_EQ(4, e.getOperands().size()); ASSERT_EQ(3, e.blocks.size()); } TEST(AST, DISABLED_InterfacesDataDFA) { } TEST(AST, DISABLED_InterfacesDataExtern) { } TEST(AST, Doc_LiteralsAndExpressions) { XreateManager* man = XreateManager::prepare( R"Code( Record1 = type {year:: int, month:: string}. isOdd = function(x :: int) :: bool {true} test = function:: bool; entry { x1 = 5 :: int. x2 = "Nimefurahi kukujua":: string. x3 = {year = 1934, month = "april"}:: Record1. x4 = {16, 8, 3} :: [int]. x41 = [1..18]:: [int]. x5 = 8>=3:: bool. x6 = "Blue" <> "Green" :: bool. x7 = -true:: bool. colors = {"Green", "Blue"} :: [string]. color = colors[0] :: string. date = {year = 1934, month = "april"}:: Record1. year = date["year"] :: int. a = 0::int. b = 0 :: int. x7 = a - b:: int. result = isOdd(6) :: bool. true } )Code"); ASSERT_TRUE(true); } TEST(AST, Doc_CodeBlocks1) { XreateManager* man = XreateManager::prepare( getDocumentationExampleById("documentation/Syntax/syntax.xml", "CodeBlocks1")); FnNoArgs resultFn = (FnNoArgs) man->run(); int resultExpected = resultFn(); ASSERT_EQ(12, resultExpected); } TEST(AST, Doc_Functions1) { XreateManager* man = XreateManager::prepare( getDocumentationExampleById("documentation/Syntax/syntax.xml", "Functions1")); ASSERT_TRUE(true); } TEST(AST, Doc_FunctionSpecializations1) { XreateManager* man = XreateManager::prepare( getDocumentationExampleById("documentation/Syntax/syntax.xml", "FunctionSpecialization1")); ASSERT_TRUE(true); } TEST(AST, Doc_BranchStatements) { string code_IfStatement1 = getDocumentationExampleById("documentation/Syntax/syntax.xml", "IfStatement1"); string code_SwitchStatement1 = getDocumentationExampleById("documentation/Syntax/syntax.xml", "SwitchStatement1"); string code = R"Code( test = function:: int; entry { question = "Favorite color?":: string. monthNum = 2:: int. %IfStatement1 %SwitchStatement1 monthName } )Code"; replace(code, "%IfStatement1", code_IfStatement1); replace(code, "%SwitchStatement1", code_SwitchStatement1); XreateManager* man = XreateManager::prepare(move(code)); ASSERT_TRUE(true); } TEST(AST, Doc_LoopStatements) { string code_LoopStatement1 = getDocumentationExampleById("documentation/Syntax/syntax.xml", "LoopStatement1"); string code_LoopStatement2 = getDocumentationExampleById("documentation/Syntax/syntax.xml", "LoopStatement2"); string code_FoldStatement1 = getDocumentationExampleById("documentation/Syntax/syntax.xml", "FoldStatement1"); string code_MapStatement1 = getDocumentationExampleById("documentation/Syntax/syntax.xml", "MapStatement1"); string code = R"Code( test = function:: int; entry { %LoopStatement1 %LoopStatement2 %FoldStatement1 %MapStatement1 min } )Code"; replace(code, "%LoopStatement1", code_LoopStatement1); replace(code, "%LoopStatement2", code_LoopStatement2); replace(code, "%FoldStatement1", code_FoldStatement1); replace(code, "%MapStatement1", code_MapStatement1); XreateManager::prepare(move(code)); ASSERT_TRUE(true); } TEST(AST, Doc_Types){ string code = getDocumentationExampleById("documentation/Syntax/syntax.xml", "Types1"); XreateManager::prepare(move(code)); ASSERT_TRUE(true); } TEST(AST, Doc_Variants1){ string code_Variants1 = getDocumentationExampleById("documentation/Syntax/syntax.xml", "Variants1"); XreateManager::prepare(move(code_Variants1)); ASSERT_TRUE(true); } TEST(AST, Doc_VariantsSwitch1){ string code_Variants1 = getDocumentationExampleById("documentation/Syntax/syntax.xml", "VariantsSwitch1"); XreateManager::prepare(move(code_Variants1)); ASSERT_TRUE(true); } TEST(AST, Doc_RecField1){ string code_Variants1 = getDocumentationExampleById("documentation/Syntax/syntax.xml", "RecField1"); XreateManager::prepare(move(code_Variants1)); ASSERT_TRUE(true); } TEST(AST, Doc_RecUpdate1){ string code_Variants1 = getDocumentationExampleById("documentation/Syntax/syntax.xml", "RecUpdate1"); XreateManager::prepare(move(code_Variants1)); ASSERT_TRUE(true); +} + +TEST(AST, Doc_Versions1){ + string code_Variants1 = getDocumentationExampleById("documentation/Syntax/syntax.xml", "Versions1_1"); + string code_Variants2 = getDocumentationExampleById("documentation/Syntax/syntax.xml", "Versions1_2"); + + string code = R"Code( +test = function:: int; entry +{ + + y +})Code"; + + { + XreateManager* man = XreateManager::prepare(move(code_Variants1)); + man->run(); + delete man; + ASSERT_TRUE(true); + } + + { + replace(code, "", code_Variants2); + auto man = details::tier1::XreateManager::prepare(move(code)); + ASSERT_DEATH(man->analyse(), ".*versions graph.*"); + } } \ No newline at end of file diff --git a/cpp/tests/introduction.cpp b/cpp/tests/introduction.cpp index 64f4d2b..d28a716 100644 --- a/cpp/tests/introduction.cpp +++ b/cpp/tests/introduction.cpp @@ -1,25 +1,28 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ * * Introduction.cpp * * Created on: March 2019 * Author: pgess */ #include "xreatemanager.h" #include "transcendlayer.h" #include "supplemental/docutils.h" #include using namespace xreate; using namespace std; TEST(Introduction, Doc_Example_1){ + string codePreamble = R"CODE( + zeroDivisionErrCode = function:: int {0} +)CODE"; string example = getDocumentationExampleById("documentation/index.xml", "Example_1"); string rules = getDocumentationExampleById("documentation/index.xml", "Transcend_Example_1"); - std::unique_ptr man(XreateManager::prepare(move(example))); + std::unique_ptr man(XreateManager::prepare(codePreamble + example)); man->transcend->addRawScript(move(rules)); int (* main)() = (int (*)()) man->run(); } \ No newline at end of file diff --git a/cpp/tests/latex.cpp b/cpp/tests/latex.cpp index 77db129..be55f08 100644 --- a/cpp/tests/latex.cpp +++ b/cpp/tests/latex.cpp @@ -1,328 +1,358 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ * * Author: pgess * Created on June 25, 2018, 5:42 PM * * \file latex.cpp * \brief Testing of latex */ #include "xreatemanager.h" #include "pass/compilepass.h" #include "transcendlayer.h" #include "query/latex.h" #include "compilation/latex.h" #include "aux/xreatemanager-decorators.h" #include "compilation/scopedecorators.h" #include "llvmlayer.h" #include "supplemental/docutils.h" +#include "supplemental/defines.h" #include #include using namespace xreate::latex; using namespace xreate::latereasoning; using namespace xreate::compilation; using namespace xreate; using namespace std; TEST(Latex, Script_NestedScopePropagation_1) { std::string program = R"CODE( import raw("scripts/cfa/context.lp"). fn = function:: int; entry { context:: test1. if(1==11)::int {2} else {3} } )CODE"; std::unique_ptr man(details::tier1::XreateManager::prepare(move(program))); CodeScope* blockTrue = man->root->findFunction("fn")->getEntryScope()->getBody().blocks.front(); auto blockTrueP = man->transcend->pack(blockTrue); boost::format formatAlias("alias(%1%, %2%)."); man->transcend->addRawScript((formatAlias % blockTrueP % "block1").str()); man->transcend->addRawScript( R"SCRIPT( success1:- bind_scope(Block1, test1, strong); alias(Block1, block1). )SCRIPT"); man->analyse(); ASSERT_EQ(1, man->transcend->query("success1").size()); } TEST(Latex, Script_DemAndDecision_1) { std::string program = R"CODE( import raw("scripts/cfa/context.lp"). a = function:: int { context:: forC(a). c() } b = function:: int { context:: forC(b). c() } c = function:: int {0} main = function:: int; entry { a() + b() } )CODE"; std::unique_ptr man(details::tier1::XreateManager::prepare(move(program))); CodeScope* blockC = man->root->findFunction("c")->getEntryScope(); auto blockCP = man->transcend->pack(blockC); boost::format formatAlias("alias(%1%, %2%)."); man->transcend->addRawScript((formatAlias % blockCP % "blockC").str()); man->transcend->addRawScript( R"SCRIPT( latex_scope_demand(BlockC, forC):- alias(BlockC, blockC). latex_registered_subjects(forC, Variant):- bind_scope(_, Variant, strong); Variant = forC(_). )SCRIPT"); man->analyse(); ASSERT_EQ(1, man->transcend->query("latex_fn_demand").size()); ASSERT_EQ(2, man->transcend->query("latex_decision").size()); } TEST(Latex, LatexQuery_getFnDemand_1){ std::string program = R"CODE( import raw("scripts/cfa/context.lp"). main = function:: int; entry { context:: alias(blockMain). 0 } )CODE"; std::unique_ptr man(details::tier1::XreateManager::prepare(move(program))); man->transcend->addRawScript( R"SCRIPT( latex_scope_demand(BlockC, forC):- bind_scope(BlockC, alias(blockMain), strong). latex_registered_subjects(forC, decisionSome). )SCRIPT"); LatexQuery* query = new LatexQuery(); man->transcend->registerQuery(query, QueryId::LatexQuery); man->analyse(); Demand demand = query->getFnDemand("main"); ASSERT_EQ(1, demand.size()); ASSERT_STREQ("forC", demand.front().c_str()); } TEST(Latex, LatexQuery_getDecision_static_1){ std::string program = R"CODE( import raw("scripts/cfa/context.lp"). a = function:: int {context::decisionSome. c()} b = function:: int {c()} c = function:: int {context:: alias(blockC). 0} )CODE"; std::unique_ptr man(details::tier1::XreateManager::prepare(move(program))); man->transcend->addRawScript( R"SCRIPT( latex_scope_demand(BlockC, forC):- bind_scope(BlockC, alias(blockC), strong). latex_registered_subjects(forC, decisionSome). )SCRIPT"); LatexQuery* query = new LatexQuery(); man->transcend->registerQuery(query, QueryId::LatexQuery); man->analyse(); LateAnnotation decisionLA = query->getDecision("forC", man->root->findFunction("a")->getEntryScope()); auto decisionGS = decisionLA.select({}, man->root, man->transcend); ASSERT_TRUE(decisionGS); decisionGS->print(cout); cout << endl; auto decisionTuple = man->transcend->parse(*decisionGS); string decision = get<2>(decisionTuple); ASSERT_STREQ("decisionSome", decision.c_str()); } TEST(Latex, Compilation_1) { std::string program = R"CODE( a = function:: int {0} main = function:: int; entry { a() } )CODE"; string script = R"SCRIPT( latex_fn_demand(%1%, subject1). latex_decision(%2%, subject1, 5). latex_registered_subjects(subject1, 1). latex_registered_subjects(subject1, 5). )SCRIPT"; typedef LatexBruteFunctionDecorator FnImpl; typedef LatexBruteScopeDecorator> ScopeImpl; std::unique_ptr man(details::tier1::XreateManager::prepare(move(program))); ScopePacked scopeMainP = man->transcend->pack(man->root->findFunction("main")->getEntryScope()); boost::format format(script); man->transcend->addRawScript((format % "a" % scopeMainP).str()); man->transcend->registerQuery(new LatexQuery(), QueryId::LatexQuery); man->analyse(); std::unique_ptr compiler(new compilation::CompilePassCustomDecorators(man.get())); compiler->run(); man->llvm->initJit(); int(*fnMain)() = (int(*)())man->llvm->getFunctionPointer(compiler->getEntryFunction()); ASSERT_EQ(0, fnMain()); } // //TEST(Latex, Full1) { // std::string program = // R"CODE( // import raw("scripts/cfa/context.lp"). // // a = function:: int // { // context:: forC(a). // c() // } // // b = function:: int // { // context:: forC(b). // c() // } // // c = function:: int {0} // // main = function:: int; entry // { // a() + b() // } // )CODE"; // // string script = // R"SCRIPT( // alias(%1%, scopeC). // latex_scope_demand(ScopeC, forC) :- alias(ScopeC, scopeC). // latex_registered_subjects(forC, forC(a)). // latex_registered_subjects(forC, forC(b)). // )SCRIPT"; // // typedef LatexBruteFunctionDecorator FnImpl; // typedef LatexBruteScopeDecorator> ScopeImpl; // // std::unique_ptr man(details::tier1::XreateManager::prepare(move(program))); // ScopePacked scopeMainP = man->transcend->pack(man->root->findFunction("main")->getEntryScope()); // auto scopeCP = man->transcend->pack(man->root->findFunction("c")->getEntryScope()); // boost::format format(script); // man->transcend->addRawScript((format %scopeCP).str()); // man->transcend->registerQuery(new LatexQuery(), QueryId::LatexQuery); // man->analyse(); // // std::unique_ptr compiler(new compilation::CompilePassCustomDecorators(man.get())); // compiler->run(); // man->llvm->print(); //} // TEST(Latex, Compilation_TransitFn1){ std::string program = R"CODE( import raw("scripts/cfa/context.lp"). branchA = function:: int { context:: sink_a. fnTransit() } branchB = function:: int { context:: sink_b. fnTransit() } fnSink = function:: int {0} fnTransit = function:: int {fnSink()} main = function:: int; entry { branchA() + branchB() } )CODE"; string script = R"SCRIPT( alias(scopeSink, %1%). latex_scope_demand(ScopeSink, sink):- alias(scopeSink, ScopeSink). latex_registered_subjects(sink, sink_a). latex_registered_subjects(sink, sink_b). )SCRIPT"; typedef LatexBruteFunctionDecorator FnImpl; typedef LatexBruteScopeDecorator> ScopeImpl; std::unique_ptr man(details::tier1::XreateManager::prepare(move(program))); CodeScope* scopeSink = man->root->findFunction("fnSink")->getEntryScope(); auto scopeSinkP = man->transcend->pack(scopeSink); ScopedSymbol argLatexSS{1, -1}; Symbol argLatexS{argLatexSS, scopeSink}; man->transcend->pack(argLatexS); boost::format format(script); man->transcend->addRawScript((format %scopeSinkP).str()); man->transcend->registerQuery(new LatexQuery(), QueryId::LatexQuery); man->analyse(); std::unique_ptr compiler(new compilation::CompilePassCustomDecorators(man.get())); compiler->run(); man->llvm->print(); man->llvm->initJit(); int(*fnMain)() = (int(*)()) man->llvm->getFunctionPointer(compiler->getEntryFunction()); int valueActual = fnMain(); ASSERT_EQ(0, valueActual); } TEST(Latex, Doc_Examples1){ std::string program = getDocumentationExampleById("documentation/Concepts/context.xml", "Examples_1"); std::unique_ptr man(details::tier1::XreateManager::prepare(move(program))); } TEST(Latex, Doc_Examples2){ std::string program = getDocumentationExampleById("documentation/Concepts/context.xml", "Examples_2"); std::unique_ptr man(details::tier1::XreateManager::prepare(move(program))); } TEST(Latex, Doc_ContextPropagation1){ std::string program =getDocumentationExampleById("documentation/Concepts/context.xml", "ContextPropagation1"); std::unique_ptr man(details::tier1::XreateManager::prepare(move(program))); } TEST(Latex, Doc_ContextPropagation2){ std::string program = getDocumentationExampleById("documentation/Concepts/context.xml", "ContextPropagation2"); std::unique_ptr man(details::tier1::XreateManager::prepare(move(program))); } TEST(Latex, Doc_Latex1){ std::string program = getDocumentationExampleById("documentation/Concepts/context.xml", "Latex1"); - std::unique_ptr man(details::tier1::XreateManager::prepare(move(program))); + string script = +R"SCRIPT( + latef(compute). + + latex_scope_demand(Scope, f_guarded(F)):- + cfa_call(Scope, F); + latef(F). + + latex_registered_subjects(f_guarded(F), Guard):- + cfa_function_specializations(F, Guard); + latef(F). + + late(TargetS, LatexParam, Guard, dfa_callguard(TargetS, Guard)):- + dfa_callfn(TargetS, FnGuarded); + latef(FnGuarded); + latex_symbol(FnCallerBody, f_guarded(FnGuarded), LatexParam); + TargetS=s(_,_, TargetScope); + scope_fnbody(TargetScope, FnCallerBody); + cfa_function_specializations(FnGuarded, Guard). +)SCRIPT"; + + auto man(XreateManager::prepare(move(program))); + man->transcend->addRawScript(move(script)); + Fn3args fn = (Fn3args) man->run(); + + int resultActual = fn(1, 4, 3); + ASSERT_EQ(7, resultActual); + + resultActual = fn(0, 4, 3); + ASSERT_EQ(1, resultActual); } \ No newline at end of file diff --git a/cpp/tests/supplemental/defines.h b/cpp/tests/supplemental/defines.h new file mode 100644 index 0000000..f51b989 --- /dev/null +++ b/cpp/tests/supplemental/defines.h @@ -0,0 +1,21 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + * + * + * File: defines.h + * Author: pgess + * + * Created on May 7, 2019, 8:11 PM + */ + +#ifndef DEFINES_H +#define DEFINES_H + +typedef int (*FnNoArgs)(); +typedef int (*Fn1Args)(int); +typedef int (*Fn2args)(int, int); +typedef int (*Fn3args)(int, int, int); + + +#endif /* DEFINES_H */ + diff --git a/documentation/Concepts/context.xml b/documentation/Concepts/context.xml index 8d1cd0a..5e7508a 100644 --- a/documentation/Concepts/context.xml +++ b/documentation/Concepts/context.xml @@ -1,312 +1,303 @@ <?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. - - + transitions between them can be looked at from two different sides: control + flow and data flow. This chapter expands on a specific mechanism called + context to reflect control flow + as well as a program's structure to facilitate optimizations, safety + measures and supporting code. In simpler terms it is a tool to adjust a + service to serve the best + particular needs of clients + that actually use it. Block level annotations are used to define - context and reason about it. See syntax.
<?xxe-sn 2ahi4rjnvuo e?>Examples of Context Usage: Suggestions and Requirements - //someStringFn = function:: string {...} + Context can be used to convey various forms + of information as shown in a few examples below. + + name="tests/latex.cpp: Latex.Doc_Examples1" +//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} + In this example the env(utf8) + annotation conveys some information about a code block distinguishing it + from 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 a specialization tailored for the UTF-8 environment. In this case a + context can be viewed as a suggestion + to pick up an appropriate specialization. + + On the other hand, there is a possibility to + define expected properties of a context: + + name="tests/latex.cpp: Latex.Doc_Examples2" +guard:: only_safe_env +{ + crucialOperation = function:: bool + {true} } -main = function:: int; entry +main = function:: bool; 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. + has only one specialization only_safe_env + in the example. If the context does not provide the required environment + env(safe) the compiler can't find an + appropriate specialization and reports a compilation error. This is a way + for a function to express requirements + or a 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: + propagation means that contexts of different blocks are related + reflecting control flow. Context of a particular code block consists of + the following: - Local context — annotations that are - defined within the block + 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. + context of its parent block reflecting enclosing + - nested code blocks relation. - 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. + Client context. Block's context inherits + a caller's context reflecting clients of a particular function or + caller-callee relation. + It allows to take into account how functions are used. - Example below + An example below: - name = "..." + name="tests/latex.cpp: Latex.Doc_ContextPropagation1" //requires 'safe' context -guard:: safe +guard:: only_safe_env { 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 + crucialOperation(x, acc) } } - 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. + demonstrates context propagation. There are + no compilation errors for the context of blockB + contains inherited property env(safe) + defined in blockA. + + Another case is when a callee inherits a + caller's context. The example below demonstrates this: + + name="tests/latex.cpp: Latex.Doc_ContextPropagation2", lines=15 +guard:: units(mm) +{ + lengthToSI = function(x:: float):: int + { x / 1000 } +} - 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: +guard:: units(min) +{ + timeToSI = function(x:: float):: int + { x * 60 } +} - name = "..." -toSI = function(x:: int):: int - { 0 } +guard:: units(m, sec) +{ + velocityToEnv = function(x:: float):: int + { x } +} -calculate = function(x:: int):: int +calculateVelocity = function(length:: float, time:: float):: float { - y = toSI(x):: int. - y + velocity_si = lengthToSI(length) / timeToSI(time). + + velocityToEnv(velocity_si) } 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. + context:: length(units(mm)); time(units(min)); velocity(units(m, sec)). + calculate(10, 2) +} + + Function calculateVelocity() + works with values measured in different units. It normalizes each value by + invoking the ..toSI() functions; + after the computation is done it converts the result back to an + environment's units. One approach is to keep unit information for each + variable independently. But if we know that an entire program or a part of + it works only with specific units we can register it in a context, such as + length(units(mm)) in this example, + letting the function calculateVelocity() + and its callees to inherit the context, thus allowing the compiler to + generate code tailored to specific units only.
- <?xxe-sn 2ahi4rjnvuo 1n?>Latex (Late - Context) - - - - - This section is still incomplete. It will - be reworked soon. - - - 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, + <?xxe-sn 2ahi4rjnvuo 1n?>Latex (Late Context) + + Importance of context as a development tool + stems from the fact that if reflects among other thing a code's clients - + by whom a given code is used. This allows to tailor a service based on + specific clients' needs. Unfortunately this sort of information cannot be + gathered fully at compile time. Compile time or static context reasoning + is partial in a sense that + it is capable of inferring only properties that are true for all possible + paths leading in a CFG to a given block. Beyond that are properties that + depend on an exact path in a CFG. Such uncertainty is possible to resolve + only at runtime once it's known which path exactly is chosen. If a + function is called from different locations, with each location having a + different context, the context of the function in question is obviously + different during each invocation. To solve this problem + late context (latex, in + short) is introduced - a mechanism of embedding into compiled code certain + instructions to gather data on relevant occasions at runtime to determine + an 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. + A cloud of all possible context + facts(weak context) for a + given block is computed during compile time. Each such fact is + associated with code paths it is held 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. + gathered which facts are hold depending on an actual code path. There + are late parameters reserved to store late context. To pass on latex + parameters, they are injected into functions as hidden + parameters. - Late parameter is used as guard for - late transcend facts context consists of. + Late parameters are used internally to + match against guards to determine which specialization to + invoke. - name = "..." -import raw ("core/control-context.lp"). - -compute = function:: int - { 0 } + An example: -computeFast = function:: int { - context:: computation(fast). - - compute() -} - -computePrecisely = function:: int { - context:: computation(precise). - - compute() -} + name="tests/latex.cpp: Latex.Doc_Latex1", lines=15 +import raw ("scripts/cfa/context.lp"). //enable context reasoning -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 +guard:: sum +{ + compute = function(arg1:: int, arg2:: int):: int + { + arg1 + arg2 } } -case context:: computation(precise) { - compute = function:: num { - 0 +guard:: sub +{ + compute = function(arg1:: int, arg2:: int):: int + { + arg1 - arg2 } } -executeComputation= function:: num { - compute() +executeComputation= function(arg1:: int, arg2:: int):: int +{ + compute(arg1, arg2) //`compute` has several specializations } -test = function(cmnd:: num):: num; entry { - if (cmnd > 0)::num { - context:: computation(fast). - executeComputation() +test = function(cmnd:: int, arg1:: int, arg2:: int):: int; entry +{ + if (cmnd > 0)::int + { + //scopeA + context:: sum. + executeComputation(arg1, arg2) - } else { - context:: computation(precise). - executeComputation() + } else + { + //scopeB + context:: sub. + executeComputation(arg1, arg2) } } - 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. + Function executeComputation + is used in different contexts in scopes scopeA, + scopeB, thus it is impossible to + infer statically which compute 's + specialisation it should invoke. In this case executeComputation + function's signature is expanded to take in a hidden late parameter with + its value conveying an actual context in order to dynamically invoke an + appropriate specialization at run time.
diff --git a/documentation/Syntax/syntax.xml b/documentation/Syntax/syntax.xml index c079908..9d47543 100644 --- a/documentation/Syntax/syntax.xml +++ b/documentation/Syntax/syntax.xml @@ -1,1232 +1,1290 @@ <?xxe-sn 26yv439af40 5a?>Syntax There is a number of principles the Xreate syntax is based on: Follows SSA(single assignment) form: each identifier is defined only once and no redefinitions allowed. Follows literate programming principles where possible. For example, identifiers can be defined in any order reflecting personal preferences and convenience for a developer. Regardless of the definition order, expressions are computed based on dependencies between them. Literate programming principles from a practical point of view simplify code testing, support, catching regressions, etc.
<?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 is a specific form of a list - [1..18]. Arithmetic operations Basic arithmetic operations: +, -, *, /. Boolean operations Negation example: -isEmty(). Relations ==, !=, <>, <, <=, >, >=. Both !=, <> mean not equal relation. Examples: 8>=3, "Blue" <> "Green". List and record operations The index operation to access individual elements of a list or record. Example: colors = {"Green", "Blue"}::[string]. color = colors[0]:: string. Accesing a record's element: date = {year = 1934, month = "april"}. year = date["year"]. Identifiers Example: a - b Functions Example: result = isOdd(6):: bool.
<?xxe-sn 2evpzktyvg7 -wunr7fl0rw8u?>Annotations This chapter is about Brute syntax. See Transcend for details regarding Transcend and annotations syntax.
<?xxe-sn 26yv439af40 7c?>Code Blocks Code block is a list of expressions delimited by a period. It has a body - the main expression along with optional identifiers' definitions. SYNTAX: { [//ident// = //expression//. | //body-expression//. ].. } Code blocks consist of a body expression and an optional set of assignments to define identifiers used in the body expression. A code block's computation result is defined as a result of computing its body expression. Identifiers are computed before expressions they are appear in, regardless of a definitions' order. name="tests/ast.cpp: AST.Doc_CodeBlocks1" test = function:: int; entry { a + b:: int a = 10:: int. b = 2:: int. } Above is an example of the code block with a+b as its body expression(because it does not have a form of an assignment). In this case the body depends on the identifiers a, b so the compiler computes both of them beforehand. A computation order depends only on dependencies between expressions. This approach has properties as follows: Mutually independent identifiers can be evaluated in any order. An identifier computed only if it is required(at least transitively) by a code 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 a function. argument Formal parameters. Arguments are delimited by comma. type, return-type Formal parameter's and returning value's types. function-block Code block that acts as a function's definition. annotations List of annotations delimited by semicolon. Below is an example of the function sum returning sum of its two arguments. Moreover there are several annotations defined. First annotation entry has a special meaning — it depicts an entry point or a main function in a program. Second annotation status(needs_review) is a demonstration that developers can annotate functions using custom annotations to express related intentions or 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 in the form of an annotation. functions-list One or more functions that share the same guard. Specializations is a crucial Xreate concept serving as the principal connection between Transcend and Brute levels. Xreate allows several functions to share the same name; in this case they are called specializations. This is a syntactic foundation for function level polymorphism, i.e. ability for the compiler to decide which exactly function is called out of several available options. The polymorphism resolution can happen during compilation(early polymorphism) or at run-time(late polymorphism). Functions with the same name, i.e. different specializations must have identifiers called guards to uniquely define a specialization. In this sense, a shared name is just a placeholder, which only along with a guard comprise the fully qualified exact function identifier. On the Brute level it is possible to specify only a function's shared name for invocation. On the other hand, Transcend is responsible to supply a guard part. When a function is actually called by its name in a program it's expected that the resolution is already done by Transcend at some time earlier and it supplies the correct guard to uniquely specify which exactly specialization to call. This gives Transcend a deep control over an actual program behaviour. An example: name="tests/ast.cpp: AST.Doc_FunctionSpecializations1", lines=15 guard:: safe_enviroment { sum = function (a::int, b::int):: int { result = a + b:: int. if (-isLastOpOverflow(result)):: int { result } else { overflowErrorCode() } } } guard:: fast_enviroment { sum = function (a::int, b::int) :: int { a + b } } To alter existing code behaviour it's always possible to add new specializations and adjust Transcend rules to specify situations when a new specialization should(or should not) be used. See API to get more detailed information on how guards are processed on the Transcend side.
<?xxe-sn 26yv439af40 93?>Branch Statements
<?xxe-sn 26yv439af40 95?>IF Statement SYNTAX: **if (** //condition// **)::** //type// [; //annotations// ].. //block-true// **else** //block-false// The if statement executes block-true or block-false depending on the condition evaluation's 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 Expression to to decide which branch to execute next. guard Value to match against condition. default-code-block Executed if no appropriate case found. The switch statement evaluation's result is that of the branch whose guard matches the condition. An example: name="tests/ast.cpp: AST.Doc_BranchStatements" monthName = switch(monthNum) :: string case (1) {"Jan"} case (2) {"Feb"} case default {"It's strange..an unexpected month"}.
<?xxe-sn 26yv439af40 9x?>Loops Xreate loops are constructed in such a way that they hide actually mutable operations semantic under an immutable facade compatible with a single assignment form.
<?xxe-sn 26yv439af40 9z?>LOOP Statement SYNTAX: **loop (** //init-value// **->** //accumulator// **)::** //type// [; //annotations//] //loop-body// init-value Initial value a loop starts from. accumulator Identifier which holds loop's result after each iteration. For each iteration accumulator assumes the result of a previous iteration or init-value for the first iteration. The result of loop-body evaluation is used as a accumulator's next iteration value and as an overall loop statement result after the last iteration. Note, that this notation does not have an explicit termination condition! The compiler relies on the loop body's fixed point in order to decide when to interrupt the loop. Consider an example: COUNTEREXAMPLE, name="tests/ast.cpp: AST.Doc_LoopStatements" //an 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). During iterations the accumulator x assumes values as follows: 2, 3, 4, 5, 6, 6... After the first perfect number is found, no further iteration will change the result anymore since there is no increment, so the loop continues to go through the same number again and again, making this an infinite loop. Obviously, x=6(the first perfect number) is a fixed point in this example. It does not make any sense to continue going through further iterations once a fixed point is reached because the result is not going to be changed anymore, thus the loop can be safely interrupted at this point. The compiler relies on manually provided annotations to recognize when a fixed point is reached. There is a special annotation final reserved to specify a fixed point for loops. Once an expression that marked as final gets evaluated it's assumed that a fixed point is reached or in words the compiler knows it's the very last iteration after which loop can be terminated safely. The correct code for the example above is: name="tests/ast.cpp: AST.Doc_LoopStatements" //a loop exits after the first perfect number is found answer2 = loop (2->x) :: int { if(IsPerfect(x))::int {x:: int; final} else {x+1} }. In this case the compiler is able to recognize that a fixed point is reached in order to know when it is safe to terminate the loop. In the example, the final result answer2 is 6.
<?xxe-sn 26yv439af40 aq?>LOOP FOLD Statement SYNTAX: **loop fold (** //list// **->** //element//:: //type// [; //annotations//], //init-value// **->** //accumulator//**)**:: //type// [; //annotations//] //loop-body// list Container to iterate over. element Identifier that assumes value of a currently processing list element. type, annotations Expression types and optional annotations delimited by semicolon. init-value Accumulator's initial value loop starts from. accumulator Identifier that assumes loop-body evaluation result after each iteration. The loop fold statement is a commonly used particular instance of loop to Iterate over list in order to accumulate the result by applying the loop-body transformation to each element and an intermediate accumulator. The result of a current iteration is used as the accumulator value for a next iteration. Accordingly, the overall loop value equals that of accumulator after the last iteration. If a fixed point is found evaluation terminates earlier. Example shows a code excerpt that looks for the minimal element in a given list(and less then the 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 Container to iterate over. element Identifier that assumes value of a currently processed list element. type, annotations Type and optional annotations delimited by semicolon. The loop fold statement is a commonly used particular instance of loop to Iterate over list and applying the loop-body transformation to each element. The result is a list that consists of all the transformed elements. An example below demonstrates creating the even_number list by multiplying by 2 every element of odd_numbers: name="tests/ast.cpp: AST.Doc_LoopStatements" odd_numbers = {1, 3, 5}:: [int]. even_numbers = loop map(odd_numbers -> number:: int) :: [int] { 2 * number }.
<?xxe-sn 26yv439af40 c6?>Types Primitive Types: bool Booleans. i8, i32, i64 Signed integers; 8, 32, 64 bit wide respectively. int, num Currently i32 aliases. Reserved as placeholders for an auto detected appropriate integral type and for auto detected appropriate either integral of floating-point type, respectively. float Double precision floating-point numbers. string Currently null terminated ANSI char string. Reserved to be generic type with no particular implementation. A concrete implementation is to be determined similarly to the containers approach. * An unspecified type. Postpones type checks for this expression. Examples: x = {amount=200, currency="USD"}::*. Compound types: element-type ] List of elements of the same type element-type. Examples: x = {1, 2, 3}:: [int] - list of int's. Lists can have different internal implementations. { key:: type, ... } Record: a list of elements of different types possibly with named keys. Examples: {int, string}, {name::string, age::int}. variant {option :: {type, ...}, ...} ADT type. Variables of this type can hold value of any type out of a list of permitted ones. Examples: variant {FullAddress:: {string, string, string}, ShortAddress:: {string}}. slave identifier Denotes a type constructed by Transcend. See slave types. An example: slave unit_test. Type operations: type [ key ] Index operation: accessing elements of a compound type. Examples: Bio = type {birth_year:: int, name:: string}. YearBirth = type Bio[birth_year]. type ( parameters... ) Constructs a concrete type with the given parameters. Examples: MyTree = type Tree(int). New types are defined as follows: SYNTAX: //type-name// = **type** (//parameters//...) //type-definition// . Examples: name="tests/ast.cpp: AST.Doc_Types" Tuple = type {string, int}. Int = type Tuple[1]. //accessing by index List = type(X) [X]. // List of elements of type X. IntList = type List(int). // type function to construct List of ints.
<?xxe-sn 2f0cduzin5j -wunr7fl0rw8u?>Slave Types SYNTAX: **slave** //predicate// predicate Name of a logic predicate Slave type is a reference to a type defined on the Transcend side. This gives Transcend a full control over program types marked as slave ones. The type is constructed in such a way that variables of this type are able to hold predicate's arguments. Type inference works as follows: If a predicate has only one argument then a constructed type is a type of this argument: int, string, variant or tuple. A constructed type is a record in case of several arguments. Predicates correspond to variants in a constructed type. An example; Transcend facts: person("John", 1962). person("Bill", 1961). The Brute side: name="tests/transcend.cpp: Transcend.Doc_SlaveTypes1", lines=15 PersonNative = type {string, int}. Person = type slave person. In the example above the types PersonNative and Person are equivalent.
<?xxe-sn 2ey6qxf8um8 1a?>Variants Sometimes it is useful for a variable to have an ability to hold values of different types depending on some conditions, in other words to have a variant type. An example: name="tests/ast.cpp: AST.Doc_Variants1" Color = type variant { White, Black, Magenta, CustomColor:: {r:: int, g:: int, b:: int} }. draw = function:: int { clrBorder = Black():: Color. clrBackground = CustomColor(50, 50, 50):: Color. drawRectangle({0, 0, 100, 100}, clrBorder, clrBackground) }
<?xxe-sn 26yv439af40 ej?>SWITCH VARIANT Statement SYNTAX: **switch variant** ( //condition// [**->** //alias// ] [:: //type// [; //annotations//... ] ] ) :: type [; annotations... ] [ **case** ( //guard// ) //case-branch// ]... condition Expression of a variant type. alias Identifier to denote unwrapped content of the condition expression withing case branches. guard Name of a variant to match against actual condition's variant. case-branch Code block to execute in case of the matched variant. The condition expression's content is referred to by alias within the branch. Variant variables require special means to test which exactly variant they contain at any given moment as well as to access it. Usually, languages that support variant types(ADT) solve this problem be means of pattern matching. Xreate intentionally does not support pattern matching since it is depends on parameters order, which is plainly unacceptable; besides, it's hardly usable in case of a large amount of parameters. Instead, Xreate supports special syntax to unwrap a variable's content using switch variant statement. An example: name="tests/ast.cpp: AST.Doc_VariantsSwitch1",lines=15 Month = type variant { MonByName :: {name:: string}, MonById :: {id:: int} }. nextMonth = function(month:: Month):: Month { switch variant(month):: Month case (MonByName) { monthName = month["name"]:: string. //here month has {name:: string} type MonByName(nextMonthByName(monthName)) } case (MonById) { monthId = month["id"]:: int. //here month has {id:: int} type if(monthId == 11):: Month { MonById(0) } else {MonById(monthId + 1)} } } The function nextMonth computes the next month after a given one. The parameter month can't be directly accessed due to being of a variant type; hence, It should be unwrapped before using. As seen in this example, Xreate silently defines a new variable with the same name month which holds an unwrapped content for each switch variant's branch independently.
+
+ + + <?xxe-sn 2fds09lgw74 n?>Versions + + //identifier// [**{** //version// **}**] + + + + + + + + version + Number to specify the identifier's version. + + + + Versions is a language construct to deal + with mutable data. An example: + + name="tests/ast.cpp: AST.Doc_Versions1" +Date = type {year:: int, month:: string}. + +test = function:: Date; entry +{ + x{0} = {year = 1953, month = "March"}:: Date. + x{1} = x{0} + {month = "February"}:: Date. //updates a single record's field + + x{1} //returned value +} + + In the example above x{0}, + x{1} are different versions of the + same variable. This is a simple trick with the idea that for all intents + and purposes x{0}, x{1} + behave like different variables but really aren't. All analyses treat them + as different immutable variables, yet the compiler actually uses the same + memory address for them making this an update of a variable. It is a hint + from a developer that the only one version of a variable should be + available at any given time. The only analysis that knows the truth is the + versions analysis. It is responsible for code validation in order to make + sure that there is no expression that uses an outdated/unknown/unreachable + variable's version. An another (counter)example: + + COUNTEREXAMPLE, name="tests/ast.cpp: AST.Doc_Versions1" +x{0} = 8:: int. +x{1} = x{0} + 10:: int. +y = x{0} + x{1} :: int. //invalid code: uses several versions + + The versions analysis builds a variables' + liveliness graph to track versions usage and reveal situations when it's + impossible to compute an expression due to the fact that it refers to an + (possibly) outdated or unreachable version. +
+
<?xxe-sn 2ey6qxf8um8 1u?>Records Record's elements(fields) are denoted by strings in order to access the field's value. This gives a possibility to use variables to reference fields. Such references are statically resolved during Interpretation. An example: name="tests/ast.cpp: AST.Doc_RecField1" Employee = type { name :: string, surname :: string, signature:: string }. test = function:: string; entry { employee = getAnyEmployee():: Employee. primaryKey = "surname":: string. employee[primaryKey] } In Xreate the left side of any assignment is always an identifier, hence there is special syntax to update one(or more) record's fields. An example: name="tests/ast.cpp: AST.Doc_RecUpdate1" Day = type { year:: int, month:: string, day:: int }. test = function:: Day { tomorrow today = {year = 1936, month = "July", day = 21}:: Day. tomorrow = today + {day = 22}:: Day. }
\ No newline at end of file diff --git a/documentation/communication.xml b/documentation/communication.xml index 1547364..e344954 100644 --- a/documentation/communication.xml +++ b/documentation/communication.xml @@ -1,443 +1,497 @@ <?xxe-sn 29tvny21340 2?>Communication The chapter discusses safe usage of non-local - variables, that is variables accessible by different components or threads + variables, that is variables accessible by different components or threads, with global variables as a particular case.
<?xxe-sn 29xq7jt0wzk 2?>Syntax Annotations: SYNTAX: **commop(send)** (1) **commop(receive)** (2) annotation (1) marks SEND communication event. annotation (2) marks RECEIVE communication event. Specializations: SYNTAX: **commDirect** **commGuarded** - Communication reasoning able to assign - following specializations: + Communication reasoning is able to assign + the following specializations: commDirect — specialization is expected to provide direct access to raw variable's content. - commGaurded + commGuarded — specialization is expected to do internal consistency checks at run time.
<?xxe-sn 29tvny21340 4?>Background One of the major concepts that support writing of safe programs is a notion of immutability. Immutability tremendously simplifies many kinds of analyses; using immutable structures is a practical way to write multithreaded - applications and has many other benefits beyond that. However in its most - basic form it comes with a price of disastrous, in many cases, memory - overhead, since property of immutability stipulates for each change of - variable to make an independent copy of it occupying different memory - region. Unwise using of immutable structures lead to the situation such - that CPU is mostly occupied with unnecessary variables copying to and fro - as well as with extensive garbage collection, irrelevant of actual - algorithm's complexity at hand. Thus it is one of the central highlights - of proper programming language design to provide techniques to overcome - the shortcomings by relaxing immutability requirements keeping - nevertheless safety benefits. There are many ways to approach the problem, - and one such technique, namely communication - model is discussed next. + applications and has many other benefits beyond that. However, in its most + basic form it comes with the price of a disastrous, in many cases, memory + overhead, since the property of immutability implies that with each change + of a variable an independent copy of it shall be made, occupying a + different memory region. Unwise use of immutable structures would lead to + a situation where CPU is mostly occupied with unnecessary variables + copying to and fro as well as with extensive garbage collection, + irrelevant of actual algorithm's complexity at hand. Thus one of the + central points of a proper programming language design is enabling the + techniques that would help to overcome the shortcomings by relaxing the + immutability requirements while keeping the safety benefits. There are + many ways to approach the problem, and one such technique, namely + communication model, is + discussed next.
<?xxe-sn 29xq7jt0wzk 6?>Communication Model Communication - model is a way to capture and express what's going on with + model is a way to capture and express what is going on with variables in a program as well as to define rules that describe valid - operations over variables. Within the framework writing value to a + operations over variables. Within this framework, writing a value to a variable is viewed as sending, - and conversely reading variable's value is viewed as receiving. + while reading a variable's value is viewed as receiving. Variables that are accessed from different components or threads are referred to as non-local variables. This chapter - is focused on a on-local variables, global variables particularly, since - exactly for them it's hard to manually check exhaustively where and how - they are used in order to catch any errors. It is natural to view them as - the means of interaction between different parts of a program, in other - words, interaction between sender and receiver, where sender and receiver + is focused on non-local variables, the global ones particularly, since it + is the very type of variables for which it is difficult to perform a + manual exhaustive check and find out where and how they are used in order + to catch any errors. It is natural to view them as the means of an + interaction between different parts of a program, in other words, an + interaction between a sender and receiver, where such sender and receiver are different components. The same terms comprise rules that express valid ways of interacting. The abstraction is named communication model due to similarity with the network communication. Reasoning based on working with a - communication path, i.e chain - of communication events(e.g. - sending/receiving) occurred during program execution. + communication path, i.e a + chain of communication events + (e.g. sending/receiving) that occur during program execution. - Let's consider small example: + Let's consider a small example: a = init():: int; commop(send). //(1) b = a + 1 :: int; commop(receive). //(2) - It shows computing of variable + It shows computing of the variable b. Variable b depends on a so a is calculated first. Variables a, b are annotated with comm(send) and comm(receive), denoting sending and receiving events, respectively. Communication path in this case is an ordered list {<begin>, SEND, RECEIVE, - <end>} where <begin>, - <end> — are special events that denote first and last events - in the path, respectively. + <end>} where <begin> and + <end> are special events that denote the first and last + events in the path, respectively. The gist of using communication model is to ensure that every sent value is properly received. It relies on the compiler to gather all possible communication paths in the program as an input for processing. There are two supported modes of reasoning: Validation. In this mode all communication paths are checked against communication rules to confirm - that the program is valid. Otherwise compilation error is + that the program is valid. Otherwise a compilation error is raised. Planning. In this mode reasoning assigns proper implementation for variables in efforts to ensure validity.
<?xxe-sn 29xq7jt0wzk k?>Validation To perform validation, every communication - path is checked against number of communication rules that express which - communication path are valid. Default behaviour expressed by "every sent - value being properly received" produce next possible cases: + path is checked against number of communication rules that define which + communication paths are valid. Default behaviour expressed by the "every + sent value being properly received" presumption results in the next + possible cases: - Valid. Path that consists of pairs of + Valid. Paths that consist of pairs of events {SEND, RECEIVE} are valid meaning that each - sent value is properly received. + sent value was properly received. Undefined and expired value. Paths that - have parts {<begin>, + have the parts {<begin>, RECEIVE} or {RECEIVE, - RECEIVE} are invalid meaning possibly undefined value is - received in the first case or duplication i.e. expired value is used - in the second's one. + RECEIVE} are invalid meaning that either a possibly undefined + value was received in the first case or a duplication, i.e. an expired + value, was used in the second case. - Lost value. Paths that have parts + Lost value. Paths that have the parts {SEND, SEND} or {SEND, - <end>} indicate possibly lost change since consequent - sender replaces value in the former case and sent value is not used at - all in the latter case. + <end>} indicate possibly lost change since the consequent + SEND event replaces the value in + the former case while the sent value is not used at all in the latter + case. + + Не вполне понятен смысл + фразы "consequent sender", и перед ней нужен артикль Traditional immutability validation is - based on the idea that once valid value is valid as long it is unmodified. - In this regards communication model can be viewed as an extension and more - expressive tool since it also captures value - expiration after it was used as well as value + based on a concept that a valid value shall remain valid as long as it was + not modified. In this regard the communication model can be viewed as an + extension and more expressive tool since it also captures + value expiration after it was + used as well as value loss, if it was not used at all.
<?xxe-sn 29xq7jt0wzk 2a?>Planning - Reasoning in the communication model aside - of performing validation, also assigns appropriate specialization for - sending and receiving operations, as appropriate. At the moment there are - two specializations the operations are expected to support: + Aside of performing validation, reasoning in + the communication model also assigns appropriate specialization to sending + and receiving operations, as appropriate. At the moment there are two + specializations the operations are expected to support: Direct. Direct specialization commDirect is expected to provide - direct access to variable's value. This specialization is assigned in - case of fully statically validated communication path. + direct access to a variable's value. This specialization is assigned + in case of a fully statically validated communication path. - Guarded. In case if there are possible - communication path inconsistencies that can not be completely ruled - out at compile time, checking logic should be embedded into compiled - code. Specialization commGaurded - is expected to hold variable state and check usage consistency. + Guarded. In case there are possible + communication path inconsistencies that cannot be completely ruled out + at compile time, checking logic should be embedded into compiled code. + Specialization commGaurded is + expected to track a variable's state in order to be able to check + usage consistency. + + "hold variable state" - ? + Удерживать переменную в каком-либо состоянии? Зафиксировать ее + состояние? Тогда может лучше "hold the [current] state of a variable"? + Или даже seize?
<?xxe-sn 2a3uy8rr2f4 9?>Planning Horizon - Reasoning implements algorithm that is + Reasoning implements an algorithm that is bounded by the maximal path length it can process. The parameter is called planning horizon. Any - variable that it can not check due to exceedingly large path's length is + variable that it cannot check due to exceedingly large path's length is assigned default implementation commGaurded that performs necessary checks during runtime. Thus the parameter - regulates trade off between static analysis extensiveness and runtime - checks overhead. + establishes a trade-off between the static analysis extensiveness and the + runtime checks overhead.
<?xxe-sn 2a7t1hxqqyo 2?>Example: Direct Implementation name="tests/effects-communication.cpp: Doc_DirImpl", lines=15 import raw("scripts/dfa/propagation.lp"). import raw("scripts/dfa/polymorphism.lp"). import raw("scripts/effects-communication/communication.lp"). import raw("scripts/effects-communication/config.lp"). CommDirect = type { value:: int }. guard:: commDirect { init = function::CommDirect { {value = 0} } read = function(vault1:: CommDirect):: int { (vault1:: *;commop(receive))["value"] } write = function(vault2:: CommDirect, valueNew:: int)::CommDirect { (vault2:: *; dfa_pseudo(vault2)) + {value = valueNew}:: int; commop(send); dfa_uppy(vault2) } } main = function::int; entry { x1 = init()::*; dfa_polym(ret). x2 = write(x1, 1)::*; dfa_polym(arg). val = read(x2)::int; dfa_polym(arg). val } In this example, basic workflow is presented in main — the function write(x1, 1) is invoked following by invocation of read(x2). Functions write() and read() are annotated with commop(send) and commop(receive) respectively in order to enable communication reasoning. Analyzer gathers and validates observed - communication path and since there is no ambiguity, it's possible to + communication path, and since there is no ambiguity, it is possible to assign specialization CommDirect allowing direct access to the variables avoiding any additional overhead. - Note, there are no any other specializations defined and if reasoning was - not enable to conclude that it is the case the compilation error would be - raised. + Note, there are no other specializations defined, and if reasoning was not + able to conclude direct access specialization, then the compilation error + would be raised. + + "is invoked following by + invocation" - тут из-за грамматики не ясно, что за чем следует. Предлагаю + заменить на "is invoked after the invocation of...", или на "is invoked + following the invocation of..." + + + + | "if reasoning was not able to + conclude that it was the case" - лучше уточнить что подразумевается под + словами "that it was the case" - "расшифровать", т.к. мне например не + понятно
<?xxe-sn 2a7t1hxqqyo a?>Example: Guarded Implementation name="tests/effects-communication.cpp: Doc_GuardedImpl", lines=15 import raw ("scripts/effects-communication/communication.lp"). import raw ("scripts/dfa/propagation.lp"). import raw ("scripts/dfa/polymorphism.lp"). import raw ("scripts/effects-communication/config.lp"). CommState = type variant{Invalid, Valid, Outdated}. CommDirect = type { value:: int }. CommGuarded = type { value:: int, state:: CommState }. guard:: commDirect { init=function::CommDirect{ {value = 0} } read= function(vault1:: CommDirect):: int{ (vault1::CommDirect; commop(receive))["value"] } write= function(vault2:: CommDirect, valueNew1:: int)::CommDirect{ (vault2::CommDirect;dfa_pseudo(vault2)) + {value = valueNew1}:: int; commop(send); dfa_uppy(vault2) } } errorRead = function:: int { -1 } errorWrite = function:: CommGuarded{ { value = -1, state = Invalid() } } guard:: commGuarded{ init=function::CommGuarded{ { value = 0, state = Invalid() } } read=function(vault3:: CommGuarded):: int { switch variant (vault3["state"]->whatever::CommState;commop(receive)):: int case (Invalid) { errorRead() } case (Outdated) { errorRead() } case (Valid) { vault3["value"] } } write=function(vault4:: CommGuarded, valueNew2:: int)::CommGuarded{ switch variant (vault4["state"]->whatever::CommState;commop(send); dfa_pseudo(vault4))::int case (Invalid) { {value = valueNew2, state = Valid()}:: CommGuarded; dfa_uppy(vault4) } case (Outdated) { {value = valueNew2, state = Valid()}:: CommGuarded; dfa_uppy(vault4) } case (Valid) { errorWrite():: CommGuarded; dfa_uppy(vault4) } } } main=function(cmd:: num)::int; entry { x1 = init():: *; dfa_polym(ret). x2 = write(x1, 1)::*; dfa_polym(arg). x3 = if (cmd > 0)::int { y = read(x2):: int; dfa_polym(arg). y } else { z = write(x2, 2)::*; dfa_polym(arg). a = read(z):: int; dfa_polym(arg). a }. x3 } - Here example of slightly more complicated - workflow. Function main contains - branching that depends on argument known at run time only. Analyzer is - presented with two possible communication paths and one of them(false - branch) leads to a possibly lost value for it contains two consequent - SEND events. In this situation the - analyzer unable to statically validate correctness and assigns - specialization commGuarded to embed - checking logic into compiled code as an intermediary layer between - variable's content and client's code. Implementation commGuarded - along with a variable access also tracks the variable status and returns - error if the value is inconsistent. + Here is an example of a slightly more + complicated workflow. Function main + contains branching that depends on an argument known at run time only. + Analyzer is presented with two possible communication paths, one of which + (the false branch) leads to a possibly lost value for it contains two + consequent SEND events. In this + situation analyzer is unable to statically validate correctness and + assigns specialization commGuarded to + embed checking logic into compiled code as an intermediary layer between + the variable's content and the client's code. Implementation + commGuarded besides accessing to a + variable's value also tracks the variable's status and will return error + if the value is inconsistent. + + "along with a variable access" + - ? Если буквально переводить, получается "вместе с переменным доступом". + Нужен или апостроф после variable, или как-то перефразировать.
\ No newline at end of file diff --git a/documentation/index.xml b/documentation/index.xml index 7e573d3..8c227b4 100644 --- a/documentation/index.xml +++ b/documentation/index.xml @@ -1,338 +1,425 @@ <?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, 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 + 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. 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. 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: - dataA = readFromFile("/some/file"):: string. //here a file is accessed for the very first time -dataB = readFromFile("/some/file"):: string. //this is the last time the file is accessed + 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 a file, in other - words, infers access order. As a result, using the data it is possible to - automatically initialize / destruct related resources. + 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 enables access control if and - when it is needed only. Example: + 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:: float, b:: float):: float + div = function(a:: int, b:: int):: int { a / b } } guard:: iAmVerySafe { - div = function(a:: float, b:: float):: float + div = function(a:: int, b:: int):: int { - if ( b == (0::float)):: float {0::float} else {a / b} + if ( b == 0 ):: int { zeroDivisionErrCode() } else { a / b } } } -test = function:: float; entry; iAmVerySecure +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 compiler must decide which one to invoke with - the only hint it has — annotation iAmVerySecure + 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.
- <?xxe-sn 2fchdmt7vgg 2?>More Advanced Example: Intentions + <?xxe-sn 2fchdmt7vgg 2?>More Advanced Example - Suppose we write a program to prepare a web + 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 the blocks should be sent to a - client in a very specific order: first a header, then a body and footer, - as below: + 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 the checkpoint + 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 - memory overhead and delays response latency as well. We write two - implementations immediate_output and - cached_output each for the + 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 + 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: + + + + + + + + Intentions, such as "that + variable is a string". + + + + + + 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. + + + + + + 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. + + On the other side, dynamically + typed languages in this regard 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. + + 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. +
diff --git a/documentation/manual.json b/documentation/manual.json index 1ca4a56..df326dd 100644 --- a/documentation/manual.json +++ b/documentation/manual.json @@ -1,36 +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": "Modules", "slug": "syntax/modules/", "filename": "modules.xml.remarkup", "subtitle": "Reuse and combine existing code in Xreate"} ]}, {"title": "Transcend", "pages": [ {"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": "Late Transcend", "slug": "transcend/late-transcend/", "filename": "latetranscend.xml.remarkup", "subtitle": "Reasoning 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": "Polymorphism", "slug": "concepts/polymorphism/", "filename": "polymorphism.xml.remarkup", "subtitle": "Rules to configure and adjust program behaviour"}, + {"title": "Context", "slug": "concepts/context/", "filename": "context.xml.remarkup", "subtitle": "Use the information about control flow and code hierachy"}, {"title": "Interpretation", "slug": "concepts/interpretation/", "filename": "interpretation.xml.remarkup", "subtitle": "Compile time computations"} ]}, {"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": "Containers", "slug": "concepts/containers/", "filename": "containers.xml.remarkup", "subtitle": "Automatic inference of the most apporpriate container implementation"}, + {"title": "Communication", "slug": "communication/", "filename": "communication.xml.remarkup", "subtitle": "Safe usage of mutable and 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": ""} ]} ] }