mirror of
https://github.com/xodio/xod.git
synced 2026-03-19 23:26:57 +01:00
feat(xod-project, xod-arduino): introduce “read-only type” concept and evaluateTmpl API
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.
This commit is contained in:
@@ -114,10 +114,11 @@ template<> bool isInputDirty<input_{{ pinKey }}>(Context ctx) {
|
||||
template<typename OutputT> void emitValue(Context ctx, typename ValueType<OutputT>::T val) {
|
||||
static_assert(always_false<OutputT>::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<output_{{ pinKey }}>(Context ctx, {{ cppType type }} val) {
|
||||
{{#unless (isPulse type)}}
|
||||
ctx->_node->output_{{ pinKey }} = val;
|
||||
@@ -129,6 +130,7 @@ template<> void emitValue<output_{{ pinKey }}>(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<input_{{ pinKey }}>(Context ctx) {
|
||||
return ctx->_error_input_{{ pinKey }};
|
||||
}
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
{{/if}}{{!-- catchesErrors --}}
|
||||
|
||||
@@ -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}}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -8,6 +8,8 @@ let isNodeIdEnabled = Directives.isNodeIdEnabled;
|
||||
|
||||
let doesRaiseErrors = Directives.doesRaiseErrors;
|
||||
|
||||
let implementsEvaluateTmpl = Directives.implementsEvaluateTmpl;
|
||||
|
||||
let areTimeoutsEnabled = Directives.areTimeoutsEnabled;
|
||||
|
||||
let stripCppComments = Directives.stripCppComments;
|
||||
|
||||
@@ -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) =>
|
||||
|
||||
@@ -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([
|
||||
|
||||
@@ -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];
|
||||
|
||||
Reference in New Issue
Block a user