From d28ef8af49bcbfd15f00fd78b08a4aa8aa455efe Mon Sep 17 00:00:00 2001 From: Evgeny Kochetkov Date: Tue, 24 Dec 2019 16:41:35 +0300 Subject: [PATCH] =?UTF-8?q?feat(xod-project,=20xod-arduino):=20introduce?= =?UTF-8?q?=20=E2=80=9Cread-only=20type=E2=80=9D=20concept=20and=20`evalua?= =?UTF-8?q?teTmpl`=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Read-only types can not be redefined during runtime. This means that their values can be used at compile time (for validation, buffer allocation etc). If a user defines `evaluateTmpl` function in the patch implementation, read-only values will be passed to it as template arguments. --- packages/xod-arduino/platform/patchContext.tpl.cpp | 8 +++++--- packages/xod-arduino/platform/program.tpl.cpp | 12 ++++++++++++ packages/xod-arduino/src/Directives.re | 5 +++++ packages/xod-arduino/src/Directives.rei | 12 ++++++++++++ packages/xod-arduino/src/Directives_Js.re | 2 ++ packages/xod-arduino/src/templates.js | 11 +++++++++++ packages/xod-arduino/src/transpiler.js | 2 ++ packages/xod-project/src/constants.js | 5 +++++ 8 files changed, 54 insertions(+), 3 deletions(-) diff --git a/packages/xod-arduino/platform/patchContext.tpl.cpp b/packages/xod-arduino/platform/patchContext.tpl.cpp index 4aaea5a7..359a2a7d 100644 --- a/packages/xod-arduino/platform/patchContext.tpl.cpp +++ b/packages/xod-arduino/platform/patchContext.tpl.cpp @@ -114,10 +114,11 @@ template<> bool isInputDirty(Context ctx) { template void emitValue(Context ctx, typename ValueType::T val) { static_assert(always_false::value, "Invalid output descriptor. Expected one of:" \ - "{{#each outputs}} output_{{pinKey}}{{/each}}"); + "{{#each outputs}}{{#unless (isReadOnlyPin this)}} output_{{pinKey}}{{/unless}}{{/each}}"); } {{#each outputs}} +{{#unless (isReadOnlyPin this)}} template<> void emitValue(Context ctx, {{ cppType type }} val) { {{#unless (isPulse type)}} ctx->_node->output_{{ pinKey }} = val; @@ -129,6 +130,7 @@ template<> void emitValue(Context ctx, {{ cppType type }} v {{#if ../isDefer}}if (isEarlyDeferPass()) {{/if}}ctx->_node->errors.output_{{ pinKey }} = false; {{/if}} } +{{/unless}} {{/each}} State* getState(Context ctx) { @@ -167,7 +169,7 @@ void raiseError(Context ctx) { {{/each}} } -{{/if}} +{{/if}}{{!-- raisesErrors --}} {{#if catchesErrors}} @@ -184,4 +186,4 @@ template<> uint8_t getError(Context ctx) { return ctx->_error_input_{{ pinKey }}; } {{/each}} -{{/if}} +{{/if}}{{!-- catchesErrors --}} diff --git a/packages/xod-arduino/platform/program.tpl.cpp b/packages/xod-arduino/platform/program.tpl.cpp index f1f1ea2f..5cea369f 100644 --- a/packages/xod-arduino/platform/program.tpl.cpp +++ b/packages/xod-arduino/platform/program.tpl.cpp @@ -370,7 +370,19 @@ void runTransaction() { {{/unless}} {{/if}} + {{#if patch.implementsEvaluateTmpl}} + {{ ns patch }}::evaluateTmpl + {{~#if (containsReadOnlyInputs inputs)~}} + < + {{~#each (readOnlyInputs inputs)~}} + {{#if @index}}, {{/if}}node_{{ fromNodeId }}_output_{{ fromPinKey }} + {{~/each~}} + > + {{~/if~}} + (&ctxObj); + {{else}} {{ ns patch }}::evaluate(&ctxObj); + {{/if}} // transfer possibly modified dirtiness state from context to g_transaction {{#eachDirtyablePin outputs}} diff --git a/packages/xod-arduino/src/Directives.re b/packages/xod-arduino/src/Directives.re index 427ece10..60687b60 100644 --- a/packages/xod-arduino/src/Directives.re +++ b/packages/xod-arduino/src/Directives.re @@ -127,6 +127,11 @@ let doesRaiseErrors = (code) => |. Code.lastPragmaEndis("error_raise") |. Endis.toBoolean(Code.doesReferSymbol("raiseError", code)); +let implementsEvaluateTmpl = code => + code + |. Code.lastPragmaEndis("evaluate_tmpl") + |. Endis.toBoolean(Code.doesReferSymbol("evaluateTmpl", code)); + let isDirtienessEnabled = (code, identifier) => code |. Code.findXodPragmas diff --git a/packages/xod-arduino/src/Directives.rei b/packages/xod-arduino/src/Directives.rei index d1847f02..da5a2834 100644 --- a/packages/xod-arduino/src/Directives.rei +++ b/packages/xod-arduino/src/Directives.rei @@ -50,6 +50,18 @@ let doesRaiseErrors: code => bool; */ let isDirtienessEnabled: (code, string) => bool; +/** + Returns whether a C++ code requires `evaluateTmpl` + instead of the regular `evaluate`. Prefers an explicit + declaration + + #pragma XOD evaluate_tmpl enable + + If no pragma found, looks for `evaluateTmpl` symbol in the code and returns true + if it is found. + */ +let implementsEvaluateTmpl: code => bool; + /** Returns wether node declares itself as an error catcher */ diff --git a/packages/xod-arduino/src/Directives_Js.re b/packages/xod-arduino/src/Directives_Js.re index e328fc1c..41813476 100644 --- a/packages/xod-arduino/src/Directives_Js.re +++ b/packages/xod-arduino/src/Directives_Js.re @@ -8,6 +8,8 @@ let isNodeIdEnabled = Directives.isNodeIdEnabled; let doesRaiseErrors = Directives.doesRaiseErrors; +let implementsEvaluateTmpl = Directives.implementsEvaluateTmpl; + let areTimeoutsEnabled = Directives.areTimeoutsEnabled; let stripCppComments = Directives.stripCppComments; diff --git a/packages/xod-arduino/src/templates.js b/packages/xod-arduino/src/templates.js index 98dc34c4..6ebd7038 100644 --- a/packages/xod-arduino/src/templates.js +++ b/packages/xod-arduino/src/templates.js @@ -267,6 +267,17 @@ Handlebars.registerHelper('isTweakNode', isTweakNode); Handlebars.registerHelper('isPulse', R.equals(XP.PIN_TYPE.PULSE)); +const isReadOnlyPin = ({ type }) => XP.READ_ONLY_TYPES.includes(type); + +Handlebars.registerHelper('isReadOnlyPin', isReadOnlyPin); + +Handlebars.registerHelper('readOnlyInputs', R.filter(isReadOnlyPin)); + +Handlebars.registerHelper( + 'containsReadOnlyInputs', + R.pipe(R.filter(isReadOnlyPin), R.isEmpty, R.not) +); + // A helper to quickly introduce a new filtered {{each ...}} loop function registerHandlebarsFilterLoopHelper(name, predicate) { Handlebars.registerHelper(name, (list, block) => diff --git a/packages/xod-arduino/src/transpiler.js b/packages/xod-arduino/src/transpiler.js index 67af5a39..9095eb8e 100644 --- a/packages/xod-arduino/src/transpiler.js +++ b/packages/xod-arduino/src/transpiler.js @@ -23,6 +23,7 @@ import { isNodeIdEnabled, doesRaiseErrors, isDirtienessEnabled, + implementsEvaluateTmpl, doesCatchErrors, findRequireUrls, } from './directives'; @@ -160,6 +161,7 @@ const convertPatchToTPatch = def( catchesErrors: doesCatchErrors(impl), raisesErrors: doesRaiseErrors(impl), usesNodeId: isNodeIdEnabled(impl), + implementsEvaluateTmpl: implementsEvaluateTmpl(impl), }; return R.mergeAll([ diff --git a/packages/xod-project/src/constants.js b/packages/xod-project/src/constants.js index b1ef7f09..fad7ad33 100644 --- a/packages/xod-project/src/constants.js +++ b/packages/xod-project/src/constants.js @@ -245,3 +245,8 @@ export const MANAGED_ATTACHMENT_TEMPLATES = { [NOT_IMPLEMENTED_IN_XOD_PATH]: IMPL_TEMPLATE, [TABTEST_MARKER_PATH]: TABTEST_TEMPLATE, }; + +/** + * Types that are could not be redefined at runtime. + */ +export const READ_ONLY_TYPES = [PIN_TYPE.PORT];