Skip to content

Commit

Permalink
Merge pull request #2007 from xodio/read-only-types
Browse files Browse the repository at this point in the history
Introduce constant types
  • Loading branch information
evgenykochetkov authored Sep 4, 2020
2 parents 07b5e41 + f911ad5 commit 2c4da81
Show file tree
Hide file tree
Showing 358 changed files with 15,478 additions and 14,373 deletions.
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ dist/
node_modules/

**/*.bs.js
**/*.ne.js
2 changes: 2 additions & 0 deletions packages/xod-arduino/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
**/*.ne.js

test-cpp/run-tests
test-cpp/run-tests.dSYM
.pio-build
5 changes: 4 additions & 1 deletion packages/xod-arduino/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
"version": "0.34.0",
"description": "XOD project: Arduino transpiler",
"scripts": {
"build:nearley": "nearleyc src/implementationGrammar.ne -o src/implementationGrammar.ne.js",
"build:js": "babel src/ -d dist/ --source-maps",
"build:re": "bsb -make-world",
"build": "yarn build:re && yarn build:js",
"build": "yarn build:nearley && yarn build:re && yarn build:js",
"dev:re": "yarn run build:re -w",
"dev": "onchange \"src/**/*.js\" \"platform/**/*\" -- yarn run build:js",
"doc": "documentation build --format html --output doc --sort-order alpha src/",
Expand All @@ -24,6 +25,8 @@
"belt-holes": "^0.34.0",
"handlebars": "^4.0.6",
"hm-def": "^0.3.2",
"moo": "^0.5.1",
"nearley": "^2.19.6",
"ramda": "^0.24.1",
"ramda-fantasy": "^0.8.0",
"sanctuary-def": "^0.14.0",
Expand Down
8 changes: 0 additions & 8 deletions packages/xod-arduino/platform/implList.tpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,11 @@
*
=============================================================================*/

namespace xod {

{{#each this}}
{{#unless isConstant}}
//-----------------------------------------------------------------------------
// {{ patchPath }} implementation
//-----------------------------------------------------------------------------
namespace {{ns this }} {

{{ implementation }}

} // namespace {{ns this }}

{{/unless}}
{{/each}}
} // namespace xod
22 changes: 22 additions & 0 deletions packages/xod-arduino/platform/patch.legacy.tpl.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{{ globals }}

namespace xod {
namespace {{ ns patch }} {
{{> patchTemplateDefinition}}
struct Node {
{{ indent patchPinTypes }}

{{ indent beforeNodeImplementation }}

{{ indent generatedCode }}

State state;

State* getState(__attribute__((unused)) Context ctx) {
return &state;
}

{{ indent insideNodeImplementation }}
};
} // namespace {{ ns patch }}
} // namespace xod
26 changes: 26 additions & 0 deletions packages/xod-arduino/platform/patch.tpl.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{{#each implBlocks}}
{{#if (eq type "global")}}
{{ contents }}
{{else if (eq type "nodespace")}}
namespace xod {
namespace {{ ns ../patch }} {
{{ contents }}
} // namespace {{ ns ../patch }}
} // namespace xod
{{else if (eq type "node")}}
namespace xod {
namespace {{ ns ../patch }} {
{{> patchTemplateDefinition .. }}
struct Node {
{{ indent ../patchPinTypes }}

{{ unindent meta }}

{{ indent ../generatedCode }}

{{ contents }}
};
} // namespace {{ ns ../patch }}
} // namespace xod
{{/if}}
{{/each}}
179 changes: 113 additions & 66 deletions packages/xod-arduino/platform/patchContext.tpl.cpp
Original file line number Diff line number Diff line change
@@ -1,30 +1,10 @@
{{!-- Template for GENERATED_CODE token inside each patch implementation --}}
{{!-- Accepts TPatch context --}}

{{#if raisesErrors}}
union NodeErrors {
struct {
{{#each outputs}}
bool output_{{ pinKey }} : 1;
{{/each}}
};

ErrorFlags flags;
};
{{#each outputs}}
{{#if isOutputSelf }}
typedef Type typeof_{{ pinKey }};
{{/if}}

struct Node {
{{#if raisesErrors}}
NodeErrors errors;
{{/if}}
{{#if usesTimeouts}}
TimeMs timeoutAt;
{{/if}}
{{#eachNonPulse outputs}}
{{ cppType type }} output_{{ pinKey }};
{{/eachNonPulse}}
State state;
};
{{/each}}

{{#each inputs}}
struct input_{{ pinKey }} { };
Expand All @@ -33,17 +13,52 @@ struct input_{{ pinKey }} { };
struct output_{{ pinKey }} { };
{{/each}}

template<typename PinT> struct ValueType { using T = void; };
{{#each inputs}}
template<> struct ValueType<input_{{ pinKey }}> { using T = {{ cppType type }}; };
static const identity<typeof_{{ pinKey }}> getValueType(input_{{ pinKey }}) {
return identity<typeof_{{ pinKey }}>();
}
{{/each}}
{{#each outputs}}
template<> struct ValueType<output_{{ pinKey }}> { using T = {{ cppType type }}; };
static const identity<typeof_{{ pinKey }}> getValueType(output_{{ pinKey }}) {
return identity<typeof_{{ pinKey }}>();
}
{{/each}}


{{#if raisesErrors}}
union NodeErrors {
struct {
{{#each outputs}}
bool output_{{ pinKey }} : 1;
{{/each}}
};

ErrorFlags flags = 0;
};
{{/if}}

{{#if raisesErrors}}
NodeErrors errors = {};
{{/if}}
{{#if usesTimeouts}}
TimeMs timeoutAt = 0;
{{/if}}

{{#eachNonPulseOrConstant outputs}}
typeof_{{ pinKey }} _output_{{ pinKey }};
{{/eachNonPulseOrConstant}}

Node (
{{~#eachNonPulseOrConstant outputs ~}}
typeof_{{ pinKey }} output_{{ pinKey }}{{#unless @last}}, {{/unless ~}}
{{/eachNonPulseOrConstant ~}}
) {
{{#eachNonPulseOrConstant outputs}}
_output_{{ pinKey }} = output_{{ pinKey }};
{{/eachNonPulseOrConstant}}
}

struct ContextObject {
Node* _node;
{{#if catchesErrors}}
{{#each inputs}}
uint8_t _error_input_{{ pinKey }};
Expand All @@ -53,9 +68,9 @@ struct ContextObject {
uint16_t _nodeId;
{{/if}}

{{#eachNonPulse inputs}}
{{ cppType type }} _input_{{ pinKey }};
{{/eachNonPulse}}
{{#eachNonPulseOrConstant inputs}}
typeof_{{ pinKey }} _input_{{ pinKey }};
{{/eachNonPulseOrConstant}}

{{#eachDirtyablePin inputs}}
bool _isInputDirty_{{ pinKey }};
Expand All @@ -72,86 +87,117 @@ struct ContextObject {

using Context = ContextObject*;

template<typename PinT> typename ValueType<PinT>::T getValue(Context ctx) {
{{#if usesNodeId}}
uint16_t getNodeId(Context ctx) {
return ctx->_nodeId;
}
{{/if}}

{{#if usesTimeouts}}
void setTimeout(__attribute__((unused)) Context ctx, TimeMs timeout) {
this->timeoutAt = transactionTime() + timeout;
}

void clearTimeout(__attribute__((unused)) Context ctx) {
detail::clearTimeout(this);
}

bool isTimedOut(__attribute__((unused)) const Context ctx) {
return detail::isTimedOut(this);
}
{{/if}}

template<typename PinT> typename decltype(getValueType(PinT()))::type getValue(Context ctx) {
return getValue(ctx, identity<PinT>());
}

template<typename PinT> typename decltype(getValueType(PinT()))::type getValue(Context ctx, identity<PinT>) {
static_assert(always_false<PinT>::value,
"Invalid pin descriptor. Expected one of:" \
"{{#each inputs}} input_{{pinKey}}{{/each}}" \
"{{#each outputs}} output_{{pinKey}}{{/each}}");
}

{{#each inputs}}
template<> {{ cppType type }} getValue<input_{{ pinKey }}>(Context ctx) {
{{#if (isPulse type)}}
typeof_{{ pinKey }} getValue(Context ctx, identity<input_{{ pinKey }}>) {
{{#if (isConstantType type)}}
return constant_input_{{ pinKey }};
{{else if (isPulse type)}}
return Pulse();
{{else}}
{{else}}
return ctx->_input_{{ pinKey }};
{{/if}}
{{/if}}
}
{{/each}}
{{#each outputs}}
template<> {{ cppType type }} getValue<output_{{ pinKey }}>(Context ctx) {
{{#if (isPulse type)}}
typeof_{{ pinKey }} getValue(Context ctx, identity<output_{{ pinKey }}>) {
{{#if (isConstantType type)}}
return constant_output_{{ pinKey }};
{{else if (isPulse type)}}
return Pulse();
{{else}}
return ctx->_node->output_{{ pinKey }};
{{/if}}
{{else}}
return this->_output_{{ pinKey }};
{{/if}}
}
{{/each}}

template<typename InputT> bool isInputDirty(Context ctx) {
return isInputDirty(ctx, identity<InputT>());
}

template<typename InputT> bool isInputDirty(Context ctx, identity<InputT>) {
static_assert(always_false<InputT>::value,
"Invalid input descriptor. Expected one of:" \
"{{#eachDirtyablePin inputs}} input_{{pinKey}}{{/eachDirtyablePin}}");
return false;
}

{{#eachDirtyablePin inputs}}
template<> bool isInputDirty<input_{{ pinKey }}>(Context ctx) {
bool isInputDirty(Context ctx, identity<input_{{ pinKey }}>) {
return ctx->_isInputDirty_{{ pinKey }};
}
{{/eachDirtyablePin}}

template<typename OutputT> void emitValue(Context ctx, typename ValueType<OutputT>::T val) {
template<typename OutputT> void emitValue(Context ctx, typename decltype(getValueType(OutputT()))::type val) {
emitValue(ctx, val, identity<OutputT>());
}

template<typename OutputT> void emitValue(Context ctx, typename decltype(getValueType(OutputT()))::type val, identity<OutputT>) {
static_assert(always_false<OutputT>::value,
"Invalid output descriptor. Expected one of:" \
"{{#each outputs}} output_{{pinKey}}{{/each}}");
}

{{#each outputs}}
template<> void emitValue<output_{{ pinKey }}>(Context ctx, {{ cppType type }} val) {
void emitValue(Context ctx, typeof_{{ pinKey }} val, identity<output_{{ pinKey }}>) {{#if (isConstantType type)}}__attribute__((deprecated("No need to emitValue from constant outputs."))) {{/if}}{
{{#unless (isConstantType type)}}
{{#unless (isPulse type)}}
ctx->_node->output_{{ pinKey }} = val;
this->_output_{{ pinKey }} = val;
{{/unless}}
{{#if isDirtyable}}
ctx->_isOutputDirty_{{ pinKey }} = true;
{{/if}}
{{#if ../raisesErrors}}
{{#if ../isDefer}}if (isEarlyDeferPass()) {{/if}}ctx->_node->errors.output_{{ pinKey }} = false;
{{#if ../isDefer}}if (isEarlyDeferPass()) {{/if}}this->errors.output_{{ pinKey }} = false;
{{/if}}
{{/unless}}
}
{{/each}}

State* getState(Context ctx) {
return &ctx->_node->state;
}

{{#if usesNodeId}}
uint16_t getNodeId(Context ctx) {
return ctx->_nodeId;
}
{{/if}}


{{#if raisesErrors}}
template<typename OutputT> void raiseError(Context ctx) {
raiseError(ctx, identity<OutputT>());
}

template<typename OutputT> void raiseError(Context ctx, identity<OutputT>) {
static_assert(always_false<OutputT>::value,
"Invalid output descriptor. Expected one of:" \
"{{#each outputs}} output_{{pinKey}}{{/each}}");
}

{{#each outputs}}
template<> void raiseError<output_{{ pinKey }}>(Context ctx) {
ctx->_node->errors.output_{{ pinKey }} = true;
void raiseError(Context ctx, identity<output_{{ pinKey }}>) {
this->errors.output_{{ pinKey }} = true;
{{#if isDirtyable}}
ctx->_isOutputDirty_{{ pinKey }} = true;
{{/if}}
Expand All @@ -160,28 +206,29 @@ template<> void raiseError<output_{{ pinKey }}>(Context ctx) {

void raiseError(Context ctx) {
{{#each outputs}}
ctx->_node->errors.output_{{ pinKey }} = true;
this->errors.output_{{ pinKey }} = true;
{{#if isDirtyable}}
ctx->_isOutputDirty_{{ pinKey }} = true;
{{/if}}
{{/each}}
}

{{/if}}

{{/if}} {{!-- raisesErrors --}}

{{#if catchesErrors}}

template<typename InputT> uint8_t getError(Context ctx) {
return getError(ctx, identity<InputT>());
}

template<typename InputT> uint8_t getError(Context ctx, identity<InputT>) {
static_assert(always_false<InputT>::value,
"Invalid input descriptor. Expected one of:" \
"{{#each inputs}} input_{{pinKey}}{{/each}}");
return 0;
}

{{#each inputs}}
template<> uint8_t getError<input_{{ pinKey }}>(Context ctx) {
uint8_t getError(Context ctx, identity<input_{{ pinKey }}>) {
return ctx->_error_input_{{ pinKey }};
}
{{/each}}
{{/if}}
{{/if}} {{!-- catchesErrors --}}
Loading

0 comments on commit 2c4da81

Please sign in to comment.