diff --git a/app/imports/api/users/patreon/updatePatreonDetails.js b/app/imports/api/users/patreon/updatePatreonDetails.js index 90a83b49..ddd2a377 100644 --- a/app/imports/api/users/patreon/updatePatreonDetails.js +++ b/app/imports/api/users/patreon/updatePatreonDetails.js @@ -112,9 +112,9 @@ const writePatreonToken = function(userId, { // Write Meteor.users.update(userId, { $set: { - 'patreon.accessToken': access_token, - 'patreon.refreshToken': refresh_token, - 'patreon.expiresAt': expiryDate, + 'services.patreon.accessToken': access_token, + 'services.patreon.refreshToken': refresh_token, + 'services.patreon.expiresAt': expiryDate, }, $unset: { 'patreon.error': 1, diff --git a/app/imports/parser/functions.js b/app/imports/parser/functions.js index 57378390..c89322ab 100644 --- a/app/imports/parser/functions.js +++ b/app/imports/parser/functions.js @@ -80,4 +80,15 @@ export default { resultType: 'number', fn: Math.trunc, }, + 'sign': { + comment: 'Returns either a positive or negative 1, indicating the sign of a number, or zero', + examples: [ + {input: 'sign(-3)', result: '-1'}, + {input: 'sign(3)', result: '1'}, + {input: 'sign(0)', result: '0'}, + ], + argumentType: 'number', + resultType: 'number', + fn: Math.sign, + } } diff --git a/app/imports/parser/grammar.js b/app/imports/parser/grammar.js index 289327de..bdd8d245 100644 --- a/app/imports/parser/grammar.js +++ b/app/imports/parser/grammar.js @@ -12,6 +12,7 @@ function id(x) { return x[0]; } import ParenthesisNode from '/imports/parser/parseTree/ParenthesisNode.js'; import RollNode from '/imports/parser/parseTree/RollNode.js'; import SymbolNode from '/imports/parser/parseTree/SymbolNode.js'; + import UnaryOperatorNode from '/imports/parser/parseTree/UnaryOperatorNode.js'; import moo from 'moo'; @@ -37,7 +38,6 @@ function id(x) { return x[0]; } multiplicativeOperator: ['*', '/'], exponentOperator: ['^'], additiveOperator: ['+', '-'], - unaryOperator: ['-'], andOperator: ['&', '&&'], orOperator: ['|', '||'], stringDelimiters: ['\"', '\''], @@ -79,7 +79,9 @@ let ParserRules = [ {"name": "singleRollExpression", "symbols": [{"literal":"d"}, "_", "exponentExpression"], "postprocess": d => new RollNode({left: new ConstantNode({value: 1, type: 'number'}), right: d[2]})}, {"name": "singleRollExpression", "symbols": ["exponentExpression"], "postprocess": id}, {"name": "exponentExpression", "symbols": ["callExpression", "_", (lexer.has("exponentOperator") ? {type: "exponentOperator"} : exponentOperator), "_", "exponentExpression"], "postprocess": d => operator(d, 'exponent')}, - {"name": "exponentExpression", "symbols": ["callExpression"], "postprocess": id}, + {"name": "exponentExpression", "symbols": ["unaryExpression"], "postprocess": id}, + {"name": "unaryExpression", "symbols": [(lexer.has("additiveOperator") ? {type: "additiveOperator"} : additiveOperator), "_", "unaryExpression"], "postprocess": d => new UnaryOperatorNode({operator: d[0].value, right: d[2]})}, + {"name": "unaryExpression", "symbols": ["callExpression"], "postprocess": id}, {"name": "callExpression", "symbols": ["name", "_", "arguments"], "postprocess": d => new CallNode ({functionName: d[0].name, args: d[2]}) }, diff --git a/app/imports/parser/grammar.ne b/app/imports/parser/grammar.ne index bac66f8a..a6e52dae 100644 --- a/app/imports/parser/grammar.ne +++ b/app/imports/parser/grammar.ne @@ -10,6 +10,7 @@ import ParenthesisNode from '/imports/parser/parseTree/ParenthesisNode.js'; import RollNode from '/imports/parser/parseTree/RollNode.js'; import SymbolNode from '/imports/parser/parseTree/SymbolNode.js'; + import UnaryOperatorNode from '/imports/parser/parseTree/UnaryOperatorNode.js'; import moo from 'moo'; @@ -35,7 +36,6 @@ multiplicativeOperator: ['*', '/'], exponentOperator: ['^'], additiveOperator: ['+', '-'], - unaryOperator: ['-'], andOperator: ['&', '&&'], orOperator: ['|', '||'], stringDelimiters: ['\"', '\''], @@ -101,6 +101,10 @@ singleRollExpression -> exponentExpression -> callExpression _ %exponentOperator _ exponentExpression {% d => operator(d, 'exponent') %} +| unaryExpression {% id %} + +unaryExpression -> + %additiveOperator _ unaryExpression {% d => new UnaryOperatorNode({operator: d[0].value, right: d[2]})%} | callExpression {% id %} callExpression -> diff --git a/app/imports/parser/parseTree/IndexNode.js b/app/imports/parser/parseTree/IndexNode.js index 592bf8d0..4535c6d6 100644 --- a/app/imports/parser/parseTree/IndexNode.js +++ b/app/imports/parser/parseTree/IndexNode.js @@ -12,13 +12,12 @@ export default class IndexNode extends ParseNode { let selection = this.array.values[index.value - 1]; if (selection){ let result = selection[fn](scope, context); - result.inheritDetails([index, this]); return result; } } return new IndexNode({ + index, array: this.array[fn](scope, context), - index: this.index[fn](scope, context), previousNodes: [this], }); } diff --git a/app/imports/parser/parseTree/OperatorNode.js b/app/imports/parser/parseTree/OperatorNode.js index 5fee48c4..8d609f41 100644 --- a/app/imports/parser/parseTree/OperatorNode.js +++ b/app/imports/parser/parseTree/OperatorNode.js @@ -19,7 +19,6 @@ export default class OperatorNode extends ParseNode { right: rightNode, operator: this.operator, fn: this.fn, - previousNodes: [this], }); } else { left = leftNode.value; @@ -48,7 +47,6 @@ export default class OperatorNode extends ParseNode { return new ConstantNode({ value: result, type: typeof result, - previousNodes: [this, leftNode, rightNode], }); } toString(){ diff --git a/app/imports/parser/parseTree/ParenthesisNode.js b/app/imports/parser/parseTree/ParenthesisNode.js index facca06b..1a99e45a 100644 --- a/app/imports/parser/parseTree/ParenthesisNode.js +++ b/app/imports/parser/parseTree/ParenthesisNode.js @@ -9,7 +9,8 @@ export default class ParenthesisNode extends ParseNode { let content = this.content[fn](scope, context); if ( content.constructor.name === 'IfNode' || - content.constructor.name === 'OperatorNode' + content.constructor.name === 'OperatorNode' || + content.constructor.name === 'RollNode' ){ return new ParenthesisNode({content, previousNodes: [this]}); } else { diff --git a/app/imports/parser/parseTree/UnaryOperatorNode.js b/app/imports/parser/parseTree/UnaryOperatorNode.js new file mode 100644 index 00000000..30844cfe --- /dev/null +++ b/app/imports/parser/parseTree/UnaryOperatorNode.js @@ -0,0 +1,33 @@ +import ParseNode from '/imports/parser/parseTree/ParseNode.js'; +import ConstantNode from '/imports/parser/parseTree/ConstantNode.js'; + +export default class UnaryOperatorNode extends ParseNode { + constructor({operator, right}) { + super(...arguments); + this.operator = operator; + this.right = right; + } + resolve(fn, scope, context){ + let rightNode = this.right[fn](scope, context); + if (rightNode.type !== 'number'){ + return new UnaryOperatorNode({ + operator: this.operator, + right: rightNode, + }); + } + let right = rightNode.value; + let result; + switch(this.operator){ + case '-': result = -right; break; + case '+': result = +right; break; + } + return new ConstantNode({ + value: result, + type: typeof result, + }); + } + toString(){ + let {right, operator} = this; + return `${operator}${right.toString()}`; + } +} diff --git a/app/imports/parser/parser.js b/app/imports/parser/parser.js index bf174759..3fc568e1 100644 --- a/app/imports/parser/parser.js +++ b/app/imports/parser/parser.js @@ -8,7 +8,7 @@ export default function parser(){ } export class CompilationContext { - constructor({doubleRolls}){ + constructor({doubleRolls} = {}){ this.errors = []; this.rolls = []; this.doubleRolls = doubleRolls;