diff --git a/next.config.js b/next.config.js index 37c6fbeea..ee50e20b0 100644 --- a/next.config.js +++ b/next.config.js @@ -10,6 +10,17 @@ const config = withTypescript({ test: path.resolve(__dirname, 'test'), scripts: path.resolve(__dirname, 'scripts') }) + + // TODO: Remove when https://github.com/webpack/webpack/pull/9349 is + // added on the webpack version I'm using + config.module.rules.push({ + test: /\.json$/, + type: 'javascript/auto', + use: { + loader: path.resolve(__dirname, './optimizedJsonLoader.js') + } + }) + return config }, env: { diff --git a/optimizedJsonLoader.js b/optimizedJsonLoader.js new file mode 100644 index 000000000..9df035389 --- /dev/null +++ b/optimizedJsonLoader.js @@ -0,0 +1,12 @@ +module.exports = function loadJsonModule(source) { + if (typeof source !== 'string') { + throw new Error('Unexpected source type: ' + typeof source) + } + const object = JSON.parse(source) + const jsonSource = JSON.stringify(object) + + // cf. https://v8.dev/blog/cost-of-javascript-2019 + // > As long as the JSON string is only evaluated once, the JSON.parse approach is + // > much faster compared to the JavaScript object literal, especially for cold loads. + return `module.exports = JSON.parse(${JSON.stringify(jsonSource)});` +} diff --git a/scripts/lib/buildExpressionFromParams.ts b/scripts/lib/buildExpressionFromParams.ts index 18d3c0e06..8c38b5bfd 100644 --- a/scripts/lib/buildExpressionFromParams.ts +++ b/scripts/lib/buildExpressionFromParams.ts @@ -6,7 +6,8 @@ import { isVariableShorthandBinaryParams, isVariableShorthandUnaryParams, isVariableShorthandNumberParams, - isMagicalVariableParams + isMagicalVariableParams, + isConditionalParams } from 'scripts/lib/expressionParamGuards' import { CallExpressionParams, @@ -17,7 +18,8 @@ import { VariableShorthandBinaryParams, VariableShorthandNumberParams, ConditionalExpressionParams, - MagicalVariableParams + MagicalVariableParams, + RepeatExpressionParams } from 'src/types/ExpressionParamTypes' import { NonExecutableStepCall, @@ -27,7 +29,8 @@ import { StepVariableShorthandBinary, StepVariableShorthandNumber, StepConditional, - StepMagicalVariable + StepMagicalVariable, + RepeatExpression } from 'src/types/ExpressionTypes' import { VariableNames } from 'src/types/VariableNames' @@ -93,6 +96,9 @@ export default function buildExpressionFromParams( export default function buildExpressionFromParams( expressionParams: ConditionalExpressionParams ): StepConditional +export default function buildExpressionFromParams( + expressionParams: RepeatExpressionParams +): RepeatExpression export default function buildExpressionFromParams( expressionParams: ExpressionParams ): StepChild @@ -178,7 +184,7 @@ export default function buildExpressionFromParams( ), magical: expressionParams.magical } - } else { + } else if (isConditionalParams(expressionParams)) { return { type: 'conditional', state: 'default', @@ -188,5 +194,12 @@ export default function buildExpressionFromParams( falseCase: buildExpressionFromParams(expressionParams.falseCase), priority: 0 } + } else { + return { + type: 'repeat', + begin: expressionParams.begin, + end: expressionParams.end, + child: buildExpressionFromParams(expressionParams.child) + } } } diff --git a/scripts/lib/checkExecutableUnaryExists.ts b/scripts/lib/checkExecutableUnaryExists.ts index 429190fe7..cccdf0719 100644 --- a/scripts/lib/checkExecutableUnaryExists.ts +++ b/scripts/lib/checkExecutableUnaryExists.ts @@ -2,7 +2,8 @@ import { isFunction, isVariable, isCall, - isVariableShorthandUnaryNumber + isVariableShorthandUnaryNumber, + isConditional } from 'src/lib/expressionTypeGuards' import { Expression } from 'src/types/ExpressionTypes' @@ -17,12 +18,14 @@ const checkExecutableUnaryExists = (e: Expression): boolean => { return ( checkExecutableUnaryExists(e.arg) || checkExecutableUnaryExists(e.func) ) - } else { + } else if (isConditional(e)) { return ( checkExecutableUnaryExists(e.condition) || checkExecutableUnaryExists(e.trueCase) || checkExecutableUnaryExists(e.falseCase) ) + } else { + throw new Error() } } diff --git a/scripts/lib/getConflictsToUnused.ts b/scripts/lib/getConflictsToUnused.ts index bf1a77fc4..29a183efe 100644 --- a/scripts/lib/getConflictsToUnused.ts +++ b/scripts/lib/getConflictsToUnused.ts @@ -2,7 +2,12 @@ import difference from 'lodash/difference' import intersection from 'lodash/intersection' import { ExecutableCallRegular } from 'src/types/ExpressionTypes' import uniq from 'lodash/uniq' -import { isCall, isVariable, isFunction } from 'src/lib/expressionTypeGuards' +import { + isCall, + isVariable, + isFunction, + isConditional +} from 'src/lib/expressionTypeGuards' import { Expression } from 'src/types/ExpressionTypes' import { VariableNames } from 'src/types/VariableNames' import alphaConvertTargetVariableNames from 'scripts/lib/alphaConvertTargetVariableNames' @@ -29,10 +34,12 @@ function getAllVariableNamesWithDuplicates( return getAllVariableNames(expression.arg, { filter }).concat( getAllVariableNames(expression.body, { filter }) ) - } else { + } else if (isConditional(expression)) { return getAllVariableNames(expression.condition, { filter }) .concat(getAllVariableNames(expression.trueCase, { filter })) .concat(getAllVariableNames(expression.falseCase, { filter })) + } else { + throw new Error() } } diff --git a/scripts/lib/hasUnboundVariables.ts b/scripts/lib/hasUnboundVariables.ts index 13b6bd2a1..e3d097dd4 100644 --- a/scripts/lib/hasUnboundVariables.ts +++ b/scripts/lib/hasUnboundVariables.ts @@ -1,4 +1,9 @@ -import { isCall, isVariable, isFunction } from 'src/lib/expressionTypeGuards' +import { + isCall, + isVariable, + isFunction, + isConditional +} from 'src/lib/expressionTypeGuards' import { Expression } from 'src/types/ExpressionTypes' export default function hasUnboundVariables(expression: Expression): boolean { @@ -14,11 +19,13 @@ export default function hasUnboundVariables(expression: Expression): boolean { hasUnboundVariables(expression.arg) || hasUnboundVariables(expression.body) ) - } else { + } else if (isConditional(expression)) { return ( hasUnboundVariables(expression.condition) || hasUnboundVariables(expression.trueCase) || hasUnboundVariables(expression.falseCase) ) + } else { + throw new Error() } } diff --git a/scripts/lib/initialExpressionContainers.ts b/scripts/lib/initialExpressionContainers.ts index f9750f87b..f728b7c2e 100644 --- a/scripts/lib/initialExpressionContainers.ts +++ b/scripts/lib/initialExpressionContainers.ts @@ -1383,3 +1383,19 @@ export const gxqm = initializeExpressionContainer({ shorthandNumber: 28 } }) + +export const gcie = initializeExpressionContainer([ + { + begin: 2, + end: 5, + child: [ + 'blankNumber', + { + shorthandBinary: 'mult' + } + ] + }, + { + shorthandNumber: 1 + } +]) diff --git a/scripts/lib/maxNestedFunctionDepth.ts b/scripts/lib/maxNestedFunctionDepth.ts index 128ecdf2f..b083b34c1 100644 --- a/scripts/lib/maxNestedFunctionDepth.ts +++ b/scripts/lib/maxNestedFunctionDepth.ts @@ -1,4 +1,9 @@ -import { isCall, isVariable, isFunction } from 'src/lib/expressionTypeGuards' +import { + isCall, + isVariable, + isFunction, + isConditional +} from 'src/lib/expressionTypeGuards' import { Expression } from 'src/types/ExpressionTypes' export default function maxNestedFunctionDepth(expression: Expression): number { @@ -11,11 +16,13 @@ export default function maxNestedFunctionDepth(expression: Expression): number { ) } else if (isFunction(expression)) { return 1 + maxNestedFunctionDepth(expression.body) - } else { + } else if (isConditional(expression)) { return Math.max( maxNestedFunctionDepth(expression.condition), maxNestedFunctionDepth(expression.trueCase), maxNestedFunctionDepth(expression.falseCase) ) + } else { + return 0 } } diff --git a/scripts/lib/prioritizeExpression.ts b/scripts/lib/prioritizeExpression.ts index dd000c14e..6ecf1e3d5 100644 --- a/scripts/lib/prioritizeExpression.ts +++ b/scripts/lib/prioritizeExpression.ts @@ -2,7 +2,8 @@ import { isCall, isFunction, isVariable, - isConditional + isConditional, + isRepeat } from 'src/lib/expressionTypeGuards' import { CallExpression, @@ -190,6 +191,11 @@ function prioritizeExpressionHelper( priority: 1, expression }).expression + } else if (isRepeat(expression)) { + return { + ...expression, + child: prioritizeExpressionHelper(expression.child) + } } else { throw new Error() } @@ -253,6 +259,15 @@ function populatePriorityAggs({ funcPriorityAgg: [expression.priority, ...funcPriorityAgg] }) } + } else if (isRepeat(expression)) { + return { + ...expression, + child: populatePriorityAggs({ + expression: expression.child, + argPriorityAgg, + funcPriorityAgg + }) + } } else { throw new Error() } diff --git a/scripts/lib/replaceCallParentKey.ts b/scripts/lib/replaceCallParentKey.ts index 0130a2181..3191792b7 100644 --- a/scripts/lib/replaceCallParentKey.ts +++ b/scripts/lib/replaceCallParentKey.ts @@ -1,4 +1,9 @@ -import { isCall, isVariable, isFunction } from 'src/lib/expressionTypeGuards' +import { + isCall, + isVariable, + isFunction, + isConditional +} from 'src/lib/expressionTypeGuards' import { CallExpression, Expression, @@ -69,7 +74,7 @@ export default function replaceCallParentKey( ...expression, body: replaceCallParentKey(expression.body, target, key, replaceWith) } - } else { + } else if (isConditional(expression)) { return { ...expression, condition: replaceCallParentKey( @@ -91,5 +96,7 @@ export default function replaceCallParentKey( replaceWith ) } + } else { + throw new Error() } } diff --git a/scripts/lib/replaceConditionalParentKey.ts b/scripts/lib/replaceConditionalParentKey.ts index aab0b2db1..f8e2d87cb 100644 --- a/scripts/lib/replaceConditionalParentKey.ts +++ b/scripts/lib/replaceConditionalParentKey.ts @@ -1,4 +1,9 @@ -import { isCall, isVariable, isFunction } from 'src/lib/expressionTypeGuards' +import { + isCall, + isVariable, + isFunction, + isConditional +} from 'src/lib/expressionTypeGuards' import { CallExpression, Expression, @@ -55,7 +60,7 @@ export default function replaceConditionalParentKey( ...expression, body: replaceConditionalParentKey(expression.body, target, replaceWith) } - } else { + } else if (isConditional(expression)) { if (expression === target) { return { ...expression, @@ -81,5 +86,7 @@ export default function replaceConditionalParentKey( ) } } + } else { + throw new Error() } } diff --git a/scripts/lib/replaceFuncParentKey.ts b/scripts/lib/replaceFuncParentKey.ts index b662637de..235d01834 100644 --- a/scripts/lib/replaceFuncParentKey.ts +++ b/scripts/lib/replaceFuncParentKey.ts @@ -1,4 +1,9 @@ -import { isCall, isVariable, isFunction } from 'src/lib/expressionTypeGuards' +import { + isCall, + isVariable, + isFunction, + isConditional +} from 'src/lib/expressionTypeGuards' import { CallExpression, Expression, @@ -62,7 +67,7 @@ export default function replaceFuncParentKey( body: replaceFuncParentKey(expression.body, target, replaceWith) } } - } else { + } else if (isConditional(expression)) { return { ...expression, condition: replaceFuncParentKey( @@ -73,5 +78,7 @@ export default function replaceFuncParentKey( trueCase: replaceFuncParentKey(expression.trueCase, target, replaceWith), falseCase: replaceFuncParentKey(expression.falseCase, target, replaceWith) } + } else { + throw new Error() } } diff --git a/scripts/lib/resetExpression.ts b/scripts/lib/resetExpression.ts index e9fa7b097..7c6a19a7e 100644 --- a/scripts/lib/resetExpression.ts +++ b/scripts/lib/resetExpression.ts @@ -1,4 +1,9 @@ -import { isCall, isVariable, isFunction } from 'src/lib/expressionTypeGuards' +import { + isCall, + isVariable, + isFunction, + isConditional +} from 'src/lib/expressionTypeGuards' import { CallExpression, Expression, @@ -57,7 +62,7 @@ export default function resetExpression( arg: resetExpression(expression.arg), body: resetExpression(expression.body) } - } else { + } else if (isConditional(expression)) { return { ...expression, state: 'default', @@ -66,5 +71,7 @@ export default function resetExpression( trueCase: resetExpression(expression.trueCase), falseCase: resetExpression(expression.falseCase) } + } else { + throw new Error() } } diff --git a/scripts/lib/runnerConfigs.ts b/scripts/lib/runnerConfigs.ts index f8babfb56..8b0825179 100644 --- a/scripts/lib/runnerConfigs.ts +++ b/scripts/lib/runnerConfigs.ts @@ -2715,3 +2715,8 @@ export const zqum: ExpressionRunnerShorthandConfig = { runner: 'playButtonOnly', initialExpressionContainer: initialExpressionContainers.qolg } + +export const oklg: ExpressionRunnerShorthandConfig = { + runner: 'simple', + initialExpressionContainer: initialExpressionContainers.gcie +} diff --git a/scripts/lib/steps/stepToActive.ts b/scripts/lib/steps/stepToActive.ts index dea91d7dd..60184dab1 100644 --- a/scripts/lib/steps/stepToActive.ts +++ b/scripts/lib/steps/stepToActive.ts @@ -3,7 +3,8 @@ import { isVariable, isExecutableCallRegular, isCall, - isExecutableCallBinary + isExecutableCallBinary, + isConditional } from 'src/lib/expressionTypeGuards' import { CallExpression, @@ -62,7 +63,7 @@ function toActive(e: Expression): StepChild<'active'> { arg: toActive(e.arg), func: toActive(e.func) } - } else { + } else if (isConditional(e)) { return { ...e, state: 'default', @@ -70,6 +71,8 @@ function toActive(e: Expression): StepChild<'active'> { trueCase: toActive(e.trueCase), falseCase: toActive(e.falseCase) } + } else { + throw new Error() } } diff --git a/scripts/lib/steps/stepToAlphaConvertDone.ts b/scripts/lib/steps/stepToAlphaConvertDone.ts index 40727f690..a75fc6387 100644 --- a/scripts/lib/steps/stepToAlphaConvertDone.ts +++ b/scripts/lib/steps/stepToAlphaConvertDone.ts @@ -1,4 +1,9 @@ -import { isFunction, isCall, isVariable } from 'src/lib/expressionTypeGuards' +import { + isFunction, + isCall, + isVariable, + isConditional +} from 'src/lib/expressionTypeGuards' import { activeFuncArg } from 'scripts/lib/steps/stepToShowFuncUnbound' import { CallExpression, @@ -110,7 +115,7 @@ export function toAlphaConvertDone( arg: toAlphaConvertDone(e.arg, conflicts, funcSide), func: toAlphaConvertDone(e.func, conflicts, funcSide) } - } else { + } else if (isConditional(e)) { return { ...e, state: 'default', @@ -118,6 +123,8 @@ export function toAlphaConvertDone( trueCase: toAlphaConvertDone(e.trueCase, conflicts, funcSide), falseCase: toAlphaConvertDone(e.falseCase, conflicts, funcSide) } + } else { + throw new Error() } } diff --git a/scripts/lib/steps/stepToBetaReducePreviewAfter.ts b/scripts/lib/steps/stepToBetaReducePreviewAfter.ts index 1fc7bc63b..8aa536c61 100644 --- a/scripts/lib/steps/stepToBetaReducePreviewAfter.ts +++ b/scripts/lib/steps/stepToBetaReducePreviewAfter.ts @@ -1,4 +1,9 @@ -import { isFunction, isVariable, isCall } from 'src/lib/expressionTypeGuards' +import { + isFunction, + isVariable, + isCall, + isConditional +} from 'src/lib/expressionTypeGuards' import { activeFuncArg } from 'scripts/lib/steps/stepToShowFuncUnbound' import { CallExpression, @@ -66,7 +71,7 @@ function matchBetaReduced( arg, func } - } else { + } else if (isConditional(e)) { const condition = matchBetaReduced(e.condition, shorthandUnary) const trueCase = matchBetaReduced(e.trueCase, shorthandUnary) const falseCase = matchBetaReduced(e.falseCase, shorthandUnary) @@ -77,6 +82,8 @@ function matchBetaReduced( trueCase: trueCase, falseCase: falseCase } + } else { + throw new Error() } } @@ -168,7 +175,7 @@ export function toBetaReducePreviewAfter( arg, func } - } else { + } else if (isConditional(e)) { const condition = toBetaReducePreviewAfter( e.condition, fromName, @@ -194,6 +201,8 @@ export function toBetaReducePreviewAfter( trueCase: trueCase, falseCase: falseCase } + } else { + throw new Error() } } diff --git a/scripts/lib/steps/stepToBetaReducePreviewBefore.ts b/scripts/lib/steps/stepToBetaReducePreviewBefore.ts index ba2407e21..6ea4637ca 100644 --- a/scripts/lib/steps/stepToBetaReducePreviewBefore.ts +++ b/scripts/lib/steps/stepToBetaReducePreviewBefore.ts @@ -1,4 +1,9 @@ -import { isFunction, isVariable, isCall } from 'src/lib/expressionTypeGuards' +import { + isFunction, + isVariable, + isCall, + isConditional +} from 'src/lib/expressionTypeGuards' import { CallExpression, ExecutableCallRegular, @@ -145,7 +150,7 @@ export function toBetaReducePreviewBefore( }, matchExists: arg.matchExists || func.matchExists } - } else { + } else if (isConditional(e)) { const condition = toBetaReducePreviewBefore(e.condition, fromName, funcSide) const trueCase = toBetaReducePreviewBefore(e.trueCase, fromName, funcSide) const falseCase = toBetaReducePreviewBefore(e.falseCase, fromName, funcSide) @@ -160,6 +165,8 @@ export function toBetaReducePreviewBefore( matchExists: condition.matchExists || trueCase.matchExists || falseCase.matchExists } + } else { + throw new Error() } } diff --git a/scripts/lib/steps/stepToBetaReducePreviewCrossed.ts b/scripts/lib/steps/stepToBetaReducePreviewCrossed.ts index 5aed69c42..1a138b437 100644 --- a/scripts/lib/steps/stepToBetaReducePreviewCrossed.ts +++ b/scripts/lib/steps/stepToBetaReducePreviewCrossed.ts @@ -1,4 +1,9 @@ -import { isFunction, isVariable, isCall } from 'src/lib/expressionTypeGuards' +import { + isFunction, + isVariable, + isCall, + isConditional +} from 'src/lib/expressionTypeGuards' import { CallExpression, ExecutableCallRegular, @@ -81,7 +86,7 @@ function toCrossed( arg: toCrossed(e.arg, isCallArg), func: toCrossed(e.func, isCallArg) } - } else { + } else if (isConditional(e)) { return { ...e, state: 'default', @@ -89,6 +94,8 @@ function toCrossed( trueCase: toCrossed(e.trueCase, isCallArg), falseCase: toCrossed(e.falseCase, isCallArg) } + } else { + throw new Error() } } diff --git a/scripts/lib/steps/stepToMagicalExpanded.ts b/scripts/lib/steps/stepToMagicalExpanded.ts index dbab25ad2..b3e91c1ff 100644 --- a/scripts/lib/steps/stepToMagicalExpanded.ts +++ b/scripts/lib/steps/stepToMagicalExpanded.ts @@ -1,4 +1,9 @@ -import { isFunction, isVariable, isCall } from 'src/lib/expressionTypeGuards' +import { + isFunction, + isVariable, + isCall, + isConditional +} from 'src/lib/expressionTypeGuards' import { CallExpression, ExecutableStepCallRegular, @@ -63,7 +68,7 @@ function toMagicalExpanded(e: Expression): StepChild<'magicalExpanded'> { arg: toMagicalExpanded(e.arg), func: toMagicalExpanded(e.func) } - } else { + } else if (isConditional(e)) { return { ...e, state: 'default', @@ -71,6 +76,8 @@ function toMagicalExpanded(e: Expression): StepChild<'magicalExpanded'> { trueCase: toMagicalExpanded(e.trueCase), falseCase: toMagicalExpanded(e.falseCase) } + } else { + throw new Error() } } diff --git a/scripts/lib/steps/stepToNeedsAlphaConvert.ts b/scripts/lib/steps/stepToNeedsAlphaConvert.ts index e5ec3ad74..12effdcb1 100644 --- a/scripts/lib/steps/stepToNeedsAlphaConvert.ts +++ b/scripts/lib/steps/stepToNeedsAlphaConvert.ts @@ -1,4 +1,9 @@ -import { isFunction, isVariable, isCall } from 'src/lib/expressionTypeGuards' +import { + isFunction, + isVariable, + isCall, + isConditional +} from 'src/lib/expressionTypeGuards' import { activeFuncArg } from 'scripts/lib/steps/stepToShowFuncUnbound' import { CallExpression, @@ -105,7 +110,7 @@ export function toNeedsAlphaConvert( arg: toNeedsAlphaConvert(e.arg, conflicts, funcSide), func: toNeedsAlphaConvert(e.func, conflicts, funcSide) } - } else { + } else if (isConditional(e)) { return { ...e, state: 'default', @@ -113,6 +118,8 @@ export function toNeedsAlphaConvert( trueCase: toNeedsAlphaConvert(e.trueCase, conflicts, funcSide), falseCase: toNeedsAlphaConvert(e.falseCase, conflicts, funcSide) } + } else { + throw new Error() } } diff --git a/scripts/lib/steps/stepToShowCallArg.ts b/scripts/lib/steps/stepToShowCallArg.ts index 647dea969..33d679eb9 100644 --- a/scripts/lib/steps/stepToShowCallArg.ts +++ b/scripts/lib/steps/stepToShowCallArg.ts @@ -1,4 +1,9 @@ -import { isFunction, isVariable, isCall } from 'src/lib/expressionTypeGuards' +import { + isFunction, + isVariable, + isCall, + isConditional +} from 'src/lib/expressionTypeGuards' import { CallExpression, ExecutableCallRegular, @@ -71,7 +76,7 @@ export function toShowCallArg( arg: toShowCallArg(e.arg, funcSide), func: toShowCallArg(e.func, funcSide) } - } else { + } else if (isConditional(e)) { return { ...e, state: 'default', @@ -79,6 +84,8 @@ export function toShowCallArg( trueCase: toShowCallArg(e.trueCase, funcSide), falseCase: toShowCallArg(e.falseCase, funcSide) } + } else { + throw new Error() } } diff --git a/scripts/lib/steps/stepToShowExecutableUnary.ts b/scripts/lib/steps/stepToShowExecutableUnary.ts index 0f6e805cf..f1eb7a292 100644 --- a/scripts/lib/steps/stepToShowExecutableUnary.ts +++ b/scripts/lib/steps/stepToShowExecutableUnary.ts @@ -1,4 +1,9 @@ -import { isFunction, isVariable, isCall } from 'src/lib/expressionTypeGuards' +import { + isFunction, + isVariable, + isCall, + isConditional +} from 'src/lib/expressionTypeGuards' import { CallExpression, Expression, @@ -57,7 +62,7 @@ export default function stepToShowExecutableUnary( arg: stepToShowExecutableUnary(e.arg), func: stepToShowExecutableUnary(e.func) } - } else { + } else if (isConditional(e)) { return { ...e, state: 'default', @@ -65,5 +70,7 @@ export default function stepToShowExecutableUnary( trueCase: stepToShowExecutableUnary(e.trueCase), falseCase: stepToShowExecutableUnary(e.falseCase) } + } else { + throw new Error() } } diff --git a/scripts/lib/steps/stepToShowFuncArg.ts b/scripts/lib/steps/stepToShowFuncArg.ts index 55e12add5..e996f968f 100644 --- a/scripts/lib/steps/stepToShowFuncArg.ts +++ b/scripts/lib/steps/stepToShowFuncArg.ts @@ -1,4 +1,9 @@ -import { isFunction, isVariable, isCall } from 'src/lib/expressionTypeGuards' +import { + isFunction, + isVariable, + isCall, + isConditional +} from 'src/lib/expressionTypeGuards' import { CallExpression, ExecutableCallRegular, @@ -72,7 +77,7 @@ export function toShowFuncArg( arg: toShowFuncArg(e.arg, funcSide), func: toShowFuncArg(e.func, funcSide) } - } else { + } else if (isConditional(e)) { return { ...e, state: 'default', @@ -80,6 +85,8 @@ export function toShowFuncArg( trueCase: toShowFuncArg(e.trueCase, funcSide), falseCase: toShowFuncArg(e.falseCase, funcSide) } + } else { + throw new Error() } } diff --git a/scripts/lib/steps/stepToShowFuncBound.ts b/scripts/lib/steps/stepToShowFuncBound.ts index d058be642..9ac8e223b 100644 --- a/scripts/lib/steps/stepToShowFuncBound.ts +++ b/scripts/lib/steps/stepToShowFuncBound.ts @@ -1,4 +1,9 @@ -import { isFunction, isVariable, isCall } from 'src/lib/expressionTypeGuards' +import { + isFunction, + isVariable, + isCall, + isConditional +} from 'src/lib/expressionTypeGuards' import { activeFuncArg } from 'scripts/lib/steps/stepToShowFuncUnbound' import { CallExpression, @@ -97,7 +102,7 @@ export function toShowFuncBound( arg: toShowFuncBound(e.arg, funcSide, highlight), func: toShowFuncBound(e.func, funcSide, highlight) } - } else { + } else if (isConditional(e)) { return { ...e, state: 'default', @@ -105,6 +110,8 @@ export function toShowFuncBound( trueCase: toShowFuncBound(e.trueCase, funcSide, highlight), falseCase: toShowFuncBound(e.falseCase, funcSide, highlight) } + } else { + throw new Error() } } diff --git a/scripts/lib/steps/stepToShowFuncUnbound.ts b/scripts/lib/steps/stepToShowFuncUnbound.ts index fa3ff5aa6..f1f7d3fa3 100644 --- a/scripts/lib/steps/stepToShowFuncUnbound.ts +++ b/scripts/lib/steps/stepToShowFuncUnbound.ts @@ -1,4 +1,9 @@ -import { isFunction, isVariable, isCall } from 'src/lib/expressionTypeGuards' +import { + isFunction, + isVariable, + isCall, + isConditional +} from 'src/lib/expressionTypeGuards' import { CallExpression, ExecutableCallRegular, @@ -95,7 +100,7 @@ export function toShowFuncUnbound( arg: toShowFuncUnbound(e.arg, funcSide, highlight), func: toShowFuncUnbound(e.func, funcSide, highlight) } - } else { + } else if (isConditional(e)) { return { ...e, state: 'default', @@ -103,6 +108,8 @@ export function toShowFuncUnbound( trueCase: toShowFuncUnbound(e.trueCase, funcSide, highlight), falseCase: toShowFuncUnbound(e.falseCase, funcSide, highlight) } + } else { + throw new Error() } } diff --git a/scripts/lib/steps/stepToUnaryProcessed.ts b/scripts/lib/steps/stepToUnaryProcessed.ts index a185a766b..56650c0a0 100644 --- a/scripts/lib/steps/stepToUnaryProcessed.ts +++ b/scripts/lib/steps/stepToUnaryProcessed.ts @@ -1,4 +1,9 @@ -import { isFunction, isVariable, isCall } from 'src/lib/expressionTypeGuards' +import { + isFunction, + isVariable, + isCall, + isConditional +} from 'src/lib/expressionTypeGuards' import { CallExpression, Expression, @@ -59,7 +64,7 @@ export default function stepToUnaryProcessed( arg: stepToUnaryProcessed(e.arg), func: stepToUnaryProcessed(e.func) } - } else { + } else if (isConditional(e)) { return { ...e, state: 'default', @@ -67,5 +72,7 @@ export default function stepToUnaryProcessed( trueCase: stepToUnaryProcessed(e.trueCase), falseCase: stepToUnaryProcessed(e.falseCase) } + } else { + throw new Error() } } diff --git a/scripts/lib/toDefault.ts b/scripts/lib/toDefault.ts index b9e1dc91b..8bc59c76d 100644 --- a/scripts/lib/toDefault.ts +++ b/scripts/lib/toDefault.ts @@ -1,4 +1,9 @@ -import { isFunction, isVariable, isCall } from 'src/lib/expressionTypeGuards' +import { + isFunction, + isVariable, + isCall, + isConditional +} from 'src/lib/expressionTypeGuards' import { CallExpression, Expression, @@ -44,7 +49,7 @@ export default function toDefault(e: Expression): StepChild<'default'> { arg: toDefault(e.arg), func: toDefault(e.func) } - } else { + } else if (isConditional(e)) { return { ...e, state: 'default', @@ -52,5 +57,7 @@ export default function toDefault(e: Expression): StepChild<'default'> { trueCase: toDefault(e.trueCase), falseCase: toDefault(e.falseCase) } + } else { + throw new Error() } } diff --git a/src/components/BlankNumber.tsx b/src/components/BlankNumber.tsx new file mode 100644 index 000000000..13d387776 --- /dev/null +++ b/src/components/BlankNumber.tsx @@ -0,0 +1,18 @@ +import React from 'react' +import BlankNumberSvg from 'src/components/BlankNumberSvg' +import StarNumberSvg from 'src/components/StarNumberSvg' +import Emoji, { EmojiProps } from 'src/components/Emoji' + +const BlankNumber = ({ + star, + ...emojiProps +}: { star?: boolean } & EmojiProps) => ( + : } + /> +) + +BlankNumber.defaultProps = Emoji.defaultProps + +export default BlankNumber diff --git a/src/components/BlankNumberSvg.tsx b/src/components/BlankNumberSvg.tsx new file mode 100644 index 000000000..420e0e4d3 --- /dev/null +++ b/src/components/BlankNumberSvg.tsx @@ -0,0 +1,16 @@ +import * as React from 'react' + +const BlankNumberSvg = (props: React.SVGProps) => ( + + + + + + + +) + +export default BlankNumberSvg diff --git a/src/components/BorderWrapper.tsx b/src/components/BorderWrapper.tsx index 87406018d..9e812873e 100644 --- a/src/components/BorderWrapper.tsx +++ b/src/components/BorderWrapper.tsx @@ -159,13 +159,16 @@ const BorderWrapper = ({ bottom: 0; border-top: 2px solid ${colors('indigo300')}; border-left: 2px solid ${colors('indigo300')}; - z-index: ${zIndices('border')}; `, - topLevel && - css` - border-bottom: 2px solid ${colors('indigo300')}; - border-right: 2px solid ${colors('indigo300')}; - ` + topLevel + ? css` + border-bottom: 2px solid ${colors('indigo300')}; + border-right: 2px solid ${colors('indigo300')}; + z-index: ${zIndices('borderToplevel')}; + ` + : css` + z-index: ${zIndices('border')}; + ` ]} /> {highlightType === 'highlighted' && diff --git a/src/components/ConditionalBorder.tsx b/src/components/ConditionalBorder.tsx index d8c0b1882..37c4c7bd1 100644 --- a/src/components/ConditionalBorder.tsx +++ b/src/components/ConditionalBorder.tsx @@ -30,11 +30,11 @@ const width = ( variableSize: ExpressionRunnerContextProps['variableSize'] ): number => { if (variableSize === 'lg') { - return 0.9 + return 2.1 } else if (variableSize === 'md') { - return 0.8 + return 0.9 } else { - return 0.7 + return 0.8 } } @@ -69,8 +69,8 @@ const ConditionalBorder = ({ css={css` position: absolute; z-index: ${zIndices('badge')}; - top: 4px; - left: 2px; + top: 0.35em; + left: 0.3em; display: inline-flex; font-size: ${fontSize(variableSizeOverrides || variableSize)}; `} @@ -96,7 +96,9 @@ const ConditionalBorder = ({ bottom: 0; width: ${width(variableSize)}em; background: ${color}; + border-left: 2px solid ${colors('indigo300')}; border-right: 2px solid ${colors('indigo300')}; + border-top: 2px solid ${colors('indigo300')}; `} /> diff --git a/src/components/Emoji.tsx b/src/components/Emoji.tsx index 1b7b1c363..b0c9931e1 100644 --- a/src/components/Emoji.tsx +++ b/src/components/Emoji.tsx @@ -33,6 +33,7 @@ export interface EmojiProps { size: 'md' | 'lg' | 'mdlg' | 'sm' noVerticalTransform: boolean cssOverrides?: SerializedStyles + customSvg?: React.ReactNode } const sizeToHeight = (size: Required['size']) => @@ -47,7 +48,8 @@ const Emoji = ({ children, size, noVerticalTransform, - cssOverrides + cssOverrides, + customSvg }: EmojiProps) => ( - {children && } + {customSvg || (children && )} ) diff --git a/src/components/ExpressionBox.tsx b/src/components/ExpressionBox.tsx index cf07e714a..201ff379a 100644 --- a/src/components/ExpressionBox.tsx +++ b/src/components/ExpressionBox.tsx @@ -4,10 +4,16 @@ import { useContext } from 'react' import Flex from 'src/components/Flex' import BorderWrapper, { BorderWrapperProps } from 'src/components/BorderWrapper' import CallExpressionBox from 'src/components/CallExpressionBox' +import RepeatExpressionBox from 'src/components/RepeatExpressionBox' import FunctionExpressionBox from 'src/components/FunctionExpressionBox' import VariableExpressionBox from 'src/components/VariableExpressionBox' import ConditionalExpressionBox from 'src/components/ConditionalExpressionBox' -import { isCall, isVariable, isFunction } from 'src/lib/expressionTypeGuards' +import { + isCall, + isVariable, + isFunction, + isConditional +} from 'src/lib/expressionTypeGuards' import { Expression } from 'src/types/ExpressionTypes' import ExpressionRunnerContext from 'src/components/ExpressionRunnerContext' @@ -120,8 +126,10 @@ const ExpressionBox = ({ expression, topLevel }: ExpressionBoxProps) => { return } else if (isFunction(expression)) { return - } else { + } else if (isConditional(expression)) { return + } else { + return } })()} diff --git a/src/components/ExpressionRunnerExplanation.tsx b/src/components/ExpressionRunnerExplanation.tsx index 25789bc4c..07c1d3294 100644 --- a/src/components/ExpressionRunnerExplanation.tsx +++ b/src/components/ExpressionRunnerExplanation.tsx @@ -12,7 +12,7 @@ import { } from 'src/types/ExpressionContainerTypes' import H from 'src/components/H' import InlinePrioritiesLabel from 'src/components/InlinePrioritiesLabel' -import { InlineEmojiBoxesForCondition } from 'src/components/InlineEmojiBoxes' +import InlineConditionBorder from 'src/components/InlineConditionBorder' interface ExpressionRunnerExplanationProps { expressionContainer: SteppedExpressionContainer @@ -290,11 +290,8 @@ const Explanation = ({ } else { return ( <> - {' '} - が かどうかチェック + が{' '} + かどうかチェック ) } @@ -306,16 +303,9 @@ const Explanation = ({ } else { return ( <> - {' '} - が なので{' '} - {' '} - が残ります + が{' '} + なので{' '} + が残ります ) } @@ -327,16 +317,9 @@ const Explanation = ({ } else { return ( <> - {' '} - が ではないので{' '} - {' '} - が残ります + が{' '} + ではないので{' '} + が残ります ) } diff --git a/src/components/H.tsx b/src/components/H.tsx index 4574418f8..19801857c 100644 --- a/src/components/H.tsx +++ b/src/components/H.tsx @@ -4,6 +4,7 @@ import { Fragment } from 'react' import InlineEmojiBoxes, { InlineEmojiBoxesForQuestion } from 'src/components/InlineEmojiBoxes' +import InlineConditionBorder from 'src/components/InlineConditionBorder' import { useContext } from 'react' import { Em, @@ -1803,6 +1804,31 @@ const H = ({ args, highlightType, episodeNumberOverrides }: HProps) => { ) } } + if (args.name === 'conditionSectionName') { + if (locale === 'en') { + return <>? + } else { + if (args.type === 'condition') { + return ( + <> + 真ん中の部分 + + ) + } else if (args.type === 'falseCase') { + return ( + <> + 上の部分 + + ) + } else { + return ( + <> + 下の部分 + + ) + } + } + } throw new Error() } diff --git a/src/components/InlineConditionBorder.tsx b/src/components/InlineConditionBorder.tsx new file mode 100644 index 000000000..3bd931015 --- /dev/null +++ b/src/components/InlineConditionBorder.tsx @@ -0,0 +1,33 @@ +/** @jsx jsx */ +import { css, jsx } from '@emotion/core' +import { colors } from 'src/lib/theme' +import EmojiNumber from 'src/components/EmojiNumber' +import Emoji from 'src/components/Emoji' + +const InlineConditionBorder = ({ + type +}: { + type: 'trueCase' | 'falseCase' | 'condition' +}) => { + const color = { + trueCase: colors('teal200'), + falseCase: colors('pink200'), + condition: colors('yellow400') + }[type] + return ( + + {type === 'trueCase' && } + {type === 'falseCase' && 🔢} + {type === 'condition' && ↕️} + + ) +} + +export default InlineConditionBorder diff --git a/src/components/RepeatBorder.tsx b/src/components/RepeatBorder.tsx new file mode 100644 index 000000000..eaace15e1 --- /dev/null +++ b/src/components/RepeatBorder.tsx @@ -0,0 +1,111 @@ +/** @jsx jsx */ +import { css, jsx } from '@emotion/core' +import { useContext } from 'react' +import Emoji from 'src/components/Emoji' +import { zIndices, colors, fontSizes, spaces } from 'src/lib/theme' +import ExpressionRunnerContext from 'src/components/ExpressionRunnerContext' +import { ExpressionRunnerContextProps } from 'src/types/ExpressionRunnerTypes' +import EmojiNumber from 'src/components/EmojiNumber' + +export interface ConditionalBorderProps { + begin: number + end?: number + variableSizeOverrides?: ExpressionRunnerContextProps['variableSize'] +} + +const fontSize = ( + variableSize: ExpressionRunnerContextProps['variableSize'] +): string => { + if (variableSize === 'lg') { + return fontSizes(1.2) + } else if (variableSize === 'md') { + return fontSizes(1) + } else { + return fontSizes(0.85) + } +} + +const width = ( + variableSize: ExpressionRunnerContextProps['variableSize'] +): number => { + if (variableSize === 'lg') { + return 2.1 + } else if (variableSize === 'md') { + return 0.9 + } else { + return 0.8 + } +} + +const RepeatBorder = ({ + begin, + end, + variableSizeOverrides +}: ConditionalBorderProps) => { + const { variableSize } = useContext(ExpressionRunnerContext) + return ( + <> + + + + {end && ( + <> + + ⬇️ + + + + + + )} + + + + ) +} + +export default RepeatBorder diff --git a/src/components/RepeatExpressionBox.tsx b/src/components/RepeatExpressionBox.tsx new file mode 100644 index 000000000..73d00f353 --- /dev/null +++ b/src/components/RepeatExpressionBox.tsx @@ -0,0 +1,34 @@ +/** @jsx jsx */ +import { css, jsx } from '@emotion/core' +import Flex from 'src/components/Flex' +import FlexCenter from 'src/components/FlexCenter' +import ExpressionBox from 'src/components/ExpressionBox' +import { RepeatExpression } from 'src/types/ExpressionTypes' +import RepeatBorder from 'src/components/RepeatBorder' + +interface RepeatExpressionBoxProps { + expression: RepeatExpression +} + +const RepeatExpressionBox = ({ expression }: RepeatExpressionBoxProps) => { + return ( + + + + + + + ) +} + +export default RepeatExpressionBox diff --git a/src/components/Runners/Oklg.tsx b/src/components/Runners/Oklg.tsx new file mode 100644 index 000000000..b6f8d44e4 --- /dev/null +++ b/src/components/Runners/Oklg.tsx @@ -0,0 +1,8 @@ +import React from 'react' +import ExpressionRunnerPrecomputed from 'src/components/ExpressionRunnerPrecomputed' +import config from 'src/lib/runners/oklg.json' + +// @ts-ignore +const Oklg = () => + +export default Oklg diff --git a/src/components/Runners/index.ts b/src/components/Runners/index.ts index 2dae978c9..4e13f3cea 100644 --- a/src/components/Runners/index.ts +++ b/src/components/Runners/index.ts @@ -338,3 +338,4 @@ export { default as Sgds } from 'src/components/Runners/Sgds' export { default as Voxy } from 'src/components/Runners/Voxy' export { default as Lvau } from 'src/components/Runners/Lvau' export { default as Zqum } from 'src/components/Runners/Zqum' +export { default as Oklg } from 'src/components/Runners/Oklg' diff --git a/src/components/StarNumberSvg.tsx b/src/components/StarNumberSvg.tsx new file mode 100644 index 000000000..c7f28b243 --- /dev/null +++ b/src/components/StarNumberSvg.tsx @@ -0,0 +1,15 @@ +import * as React from 'react' + +const BlankNumberSvg = (props: React.SVGProps) => ( + + + + + + +) + +export default BlankNumberSvg diff --git a/src/components/VariableExpressionBox.tsx b/src/components/VariableExpressionBox.tsx index 69b01b853..1f17e9a32 100644 --- a/src/components/VariableExpressionBox.tsx +++ b/src/components/VariableExpressionBox.tsx @@ -15,6 +15,7 @@ import letterEmojiMapping from 'src/lib/letterEmojiMapping' import { VariableExpression } from 'src/types/ExpressionTypes' import H from 'src/components/H' import { ExpressionRunnerContextProps } from 'src/types/ExpressionRunnerTypes' +import BlankNumber from 'src/components/BlankNumber' interface VariableExpressionBoxProps { expression: VariableExpression @@ -137,6 +138,18 @@ const VariableEmoji = ({ expression }: VariableExpressionBoxProps) => { ) + } else if (expression.name === 'blankNumber') { + return ( +
+ +
+ ) + } else if (expression.name === 'questionV2') { + return ( +
+ +
+ ) } else if (expression.name === 'Amult') { return (
diff --git a/src/contents/1.v2.jp.tsx b/src/contents/1.v2.jp.tsx index 230c8cfa2..9e4779eda 100644 --- a/src/contents/1.v2.jp.tsx +++ b/src/contents/1.v2.jp.tsx @@ -14,8 +14,8 @@ import EmojiSeparator from 'src/components/EmojiSeparator' import Emoji from 'src/components/Emoji' import EmojiNumber from 'src/components/EmojiNumber' import * as R from 'src/components/Runners' -import { InlineEmojiBoxesForCondition } from 'src/components/InlineEmojiBoxes' import NextLessonButton from 'src/components/NextLessonButton' +import BlankNumber from 'src/components/BlankNumber' export default () => ( (

- 一番上と下にハテナマーク {' '} + 一番上と下にハテナマーク {' '} があり、真ん中に足し算の記号 がありますね。

- この {' '} + この {' '} の部分には、それぞれ数字を入れることができます。たとえば{' '} を両方に入れてみましょう。

@@ -156,8 +156,10 @@ export default () => (

条件分岐の計算箱」には - ハテナマーク {' '} - が3つあり、それぞれ左端に違う色と、以下の三種類の印がついています + ハテナマーク {' '} + が3つあります。それぞれ左端に赤・黄色・青と信号機{' '} + 🚦{' '} + のような色があり、左上に以下の三種類の印がついています 。いったいどんな計算ができるのでしょう? 🤔 @@ -166,7 +168,7 @@ export default () => (

とりあえず、{' '} - それぞれの に適当な数字を入れ、 + それぞれの に適当な数字を入れ、 したらどうなるか試してみましょう。 @@ -196,14 +198,14 @@ export default () => (

条件分岐の計算箱」はまず、 - 真ん中の部分 {' '} + {' '} に入っている数字が かどうか チェックします。

- 真ん中の部分 {' '} + {' '} に入っている数字は なので、{' '} ではありません。 @@ -212,15 +214,15 @@ export default () => (

このように真ん中が ではない場合、 - 上の部分 {' '} + {' '} に入っている数字が最終的に残ります。

- だから、 上の部分{' '} - に入っている{' '} - が残る、というわけです。 + だから、{' '} + {' '} + に入っている が残る、というわけです。

@@ -248,13 +250,16 @@ export default () => ( 今回は真ん中が {' '} ですね。この場合は前回と逆で、 - 下の部分 {' '} + {' '} に入っている数字が最終的に残ります。

- だから、下の部分 {' '} + だから、 + {' '} に入っている が残る、というわけです。

@@ -276,7 +281,10 @@ export default () => (

- まず、真ん中の {' '} + まず、 + {' '} の中にある数字が {' '} かどうかチェックします。 @@ -284,15 +292,19 @@ export default () => (

    - もし なら、 下の部分{' '} - {' '} + もし なら、{' '} + {' '} の中にある数字が残ります。 - もし でなければ、 上の部分{' '} - {' '} + もし でなければ、 + {' '} の中にある数字が残ります。 @@ -325,8 +337,11 @@ export default () => (

    - まず、真ん中の部分{' '} - に入っている「 + まず、 + {' '} + に入っている「 {' '} で割ったときの余りがわかる計算箱 @@ -337,18 +352,25 @@ export default () => (

    {' '} - で割ると余りは になるので、真ん中の部分{' '} - が{' '} - になります。 + で割ると余りは になるので、 + {' '} + が になります。

    - あとは以前と同じです。真ん中の部分{' '} - が{' '} - ではないので、上の部分{' '} - の中にある{' '} - が最終的に残るというわけです。 + あとは以前と同じです。 + {' '} + が ではないので、 + {' '} + の中にある {' '} + が最終的に残るというわけです。

    diff --git a/src/contents/2.v2.jp.tsx b/src/contents/2.v2.jp.tsx index 2a986f33c..1fcf6b9a0 100644 --- a/src/contents/2.v2.jp.tsx +++ b/src/contents/2.v2.jp.tsx @@ -12,10 +12,10 @@ import EmojiSeparator from 'src/components/EmojiSeparator' import EmojiNumber from 'src/components/EmojiNumber' import ExpressionRunnerSeparator from 'src/components/ExpressionRunnerSeparator' import EpisodeCardList from 'src/components/EpisodeCardList' -import { InlineEmojiBoxesForCondition } from 'src/components/InlineEmojiBoxes' import H from 'src/components/H' import * as R from 'src/components/Runners' import NextLessonButton from 'src/components/NextLessonButton' +import BlankNumber from 'src/components/BlankNumber' export default () => ( (

    試しに、 - + に何か数字を入れてみましょう。 本稿を公開したのは2019年なので、 @@ -58,8 +58,10 @@ export default () => (

    前回説明した通り、 - 先に真ん中の部分{' '} - {' '} + 先に + {' '} の中にある、割り算の余りを計算します。 @@ -72,16 +74,19 @@ export default () => (

    - 真ん中の部分 が{' '} - ではないので、上の部分{' '} - の中にある{' '} - が最終的に残るというわけです。 + {' '} + が ではないので、 + {' '} + の中にある {' '} + が最終的に残るというわけです。

    - まとめると、最初に に{' '} - を入れると、結果は{' '} - になります。 + まとめると、最初に + {' '} + を入れると、結果は になります。

    (

    今回も、 - 先に真ん中の部分{' '} - {' '} + 先に + {' '} の中にある、割り算の余りを計算します。 @@ -125,16 +132,19 @@ export default () => (

    - 真ん中の部分 が{' '} - ではないので、下の部分{' '} - の中にある{' '} - が最終的に残るというわけです。 + {' '} + が ではないので、 + {' '} + の中にある {' '} + が最終的に残るというわけです。

    - まとめると、最初に に{' '} - を入れると、結果は{' '} - になります。 + まとめると、最初に + {' '} + を入れると、結果は になります。

    ( content: ( <>

    - まとめると、こちらの計算箱のの部分に、 + まとめると、こちらの計算箱の + + の部分に、

      @@ -212,7 +224,8 @@ export default () => (

      つまりこの計算箱は、「 - に入れた年の2月には何日まであるか + + に入れた年の2月には何日まであるか 」を自動で計算してくれるのです。

      @@ -279,26 +292,34 @@ export default () => ( <>

      先ほどの計算箱は、この「うるう年かどうか - 」という計算を、真ん中の部分{' '} - {' '} + 」という計算を、 + {' '} で行っているのです。

      - うるう年なら真ん中の部分{' '} - が{' '} - になるので、最後は下の部分{' '} - に入っている{' '} - が残ります。 + うるう年なら + {' '} + が になるので、最後は + {' '} + に入っている が残ります。

      うるう年でなければ、 - に入っている{' '} - が残ります。 + {' '} + に入っている が残ります。

      @@ -332,7 +353,7 @@ export default () => ( ]} />

      - 下のように、先ほどの計算箱の に{' '} + 下のように、先ほどの計算箱の に{' '} {' '} を入れれば、自動で計算してくれるのです。 diff --git a/src/contents/3.v2.jp.tsx b/src/contents/3.v2.jp.tsx index 5f4ca258b..00548dc56 100644 --- a/src/contents/3.v2.jp.tsx +++ b/src/contents/3.v2.jp.tsx @@ -1,4 +1,18 @@ import React from 'react' import EpisodeCardList from 'src/components/EpisodeCardList' +import * as R from 'src/components/Runners' -export default () => +export default () => ( + 計算箱の使い道は?, + content: ( + <> + + + ) + } + ]} + /> +) diff --git a/src/lib/expressionTypeGuards.ts b/src/lib/expressionTypeGuards.ts index 84a095e29..42f07e6c3 100644 --- a/src/lib/expressionTypeGuards.ts +++ b/src/lib/expressionTypeGuards.ts @@ -13,7 +13,8 @@ import { ExecutableCallBinary, VariableShorthandUnaryNumber, ExecutableCallMagical, - MagicalVariable + MagicalVariable, + RepeatExpression } from 'src/types/ExpressionTypes' export function isVariable( @@ -111,3 +112,9 @@ export function isExecutableConditional( ): expression is E { return isVariableShorthandNumber(expression.condition) } + +export function isRepeat( + expression: Expression +): expression is E { + return expression.type === 'repeat' +} diff --git a/src/lib/letterEmojiMappingJson.json b/src/lib/letterEmojiMappingJson.json index 44213d753..470f65e58 100644 --- a/src/lib/letterEmojiMappingJson.json +++ b/src/lib/letterEmojiMappingJson.json @@ -34,5 +34,6 @@ "someNumber": "❔", "abbreviated": "❔", "Amult": "❔", - "questionV2": "❓" + "questionV2": "❓", + "blankNumber": "❔" } diff --git a/src/lib/runners/oklg.json b/src/lib/runners/oklg.json new file mode 100644 index 000000000..4c2434565 --- /dev/null +++ b/src/lib/runners/oklg.json @@ -0,0 +1,84 @@ +{ + "expressionContainers": [ + { + "containerState": "ready", + "previouslyChangedExpressionState": "default", + "expression": { + "arg": { + "name": "shorthandNumber", + "highlightType": "default", + "topLeftBadgeType": "none", + "bottomRightBadgeType": "none", + "type": "variable", + "argPriorityAgg": [ + 1 + ], + "funcPriorityAgg": [], + "emphasizePriority": false, + "bound": true, + "shorthandNumber": 1 + }, + "func": { + "type": "repeat", + "begin": 2, + "end": 5, + "child": { + "arg": { + "name": "shorthandBinary", + "highlightType": "default", + "topLeftBadgeType": "none", + "bottomRightBadgeType": "none", + "type": "variable", + "argPriorityAgg": [ + 1 + ], + "funcPriorityAgg": [], + "emphasizePriority": false, + "bound": true, + "shorthandBinary": "mult" + }, + "func": { + "name": "blankNumber", + "highlightType": "default", + "topLeftBadgeType": "none", + "bottomRightBadgeType": "none", + "type": "variable", + "argPriorityAgg": [], + "funcPriorityAgg": [ + 1, + 1 + ], + "emphasizePriority": false, + "bound": true + }, + "state": "default", + "type": "call", + "priority": 1 + } + }, + "state": "default", + "type": "call", + "priority": 1 + } + } + ], + "speed": 1, + "showOnlyFocused": false, + "hideControls": true, + "explanationsVisibility": "hidden", + "hidePriorities": true, + "variableSize": "lg", + "containerSize": "xxs", + "hidePlayButton": false, + "hideBottomRightBadges": false, + "skipToTheEnd": false, + "hideFuncUnboundBadgeOnExplanation": false, + "highlightOverridesCallArgAndFuncUnboundOnly": false, + "bottomRightBadgeOverrides": {}, + "highlightOverrides": {}, + "highlightOverrideActiveAfterStart": false, + "argPriorityAggHighlights": [], + "funcPriorityAggHighlights": [], + "highlightFunctions": false, + "superFastForward": false +} diff --git a/src/lib/theme/spaces.ts b/src/lib/theme/spaces.ts index f3f022eff..7d42ba327 100644 --- a/src/lib/theme/spaces.ts +++ b/src/lib/theme/spaces.ts @@ -1,4 +1,5 @@ export const allSpaces = { + '-0.125': -0.125, '-0.25': -0.25, '-0.5': -0.5, '-0.75': -0.75, @@ -16,6 +17,7 @@ export const allSpaces = { '-7': -7, '-8': -8, 0: 0, + 0.125: 0.125, 0.2: 0.2, 0.25: 0.25, 0.375: 0.375, diff --git a/src/lib/theme/zIndices.ts b/src/lib/theme/zIndices.ts index 009e39081..b9057d291 100644 --- a/src/lib/theme/zIndices.ts +++ b/src/lib/theme/zIndices.ts @@ -1,9 +1,10 @@ export const allZIndices = { - conditionalBorder: 99, border: 100, - badge: 101, + conditionalBorder: 101, + borderToplevel: 102, + badge: 102, expressionPriorityNumber: 101, - conditionalBorderShade: 102, + conditionalBorderShade: 103, modal: 1000 } diff --git a/src/types/ExpressionParamTypes.ts b/src/types/ExpressionParamTypes.ts index 2358e412a..c489edbc4 100644 --- a/src/types/ExpressionParamTypes.ts +++ b/src/types/ExpressionParamTypes.ts @@ -52,6 +52,12 @@ export interface ConditionalExpressionParams { readonly checkType: ConditionalExpression['checkType'] } +export interface RepeatExpressionParams { + readonly child: ExpressionParams + readonly begin: number + readonly end?: number +} + export type ExpressionParams = | VariableExpressionParams | FunctionExpressionParams @@ -62,3 +68,4 @@ export type ExpressionParams = | VariableShorthandUnaryParams | ConditionalExpressionParams | MagicalVariableParams + | RepeatExpressionParams diff --git a/src/types/ExpressionTypes.ts b/src/types/ExpressionTypes.ts index 9b635881f..e943a8034 100644 --- a/src/types/ExpressionTypes.ts +++ b/src/types/ExpressionTypes.ts @@ -324,11 +324,19 @@ export interface ConditionalExpression { readonly state: ConditionalStates } +export interface RepeatExpression { + readonly type: 'repeat' + readonly child: Expression + readonly begin: number + readonly end?: number +} + export type Expression = | VariableExpression | CallExpression | FunctionExpression | ConditionalExpression + | RepeatExpression type FunctionWithArgBody< A extends VariableExpression, @@ -454,6 +462,7 @@ export type StepChild = | StepFunction | StepConditional | NonExecutableStepCall + | RepeatExpression // Map from a union type to another union type // https://stackoverflow.com/a/51691257/114157 diff --git a/src/types/HTypes.ts b/src/types/HTypes.ts index 8681abda4..f07f0c69e 100644 --- a/src/types/HTypes.ts +++ b/src/types/HTypes.ts @@ -132,4 +132,8 @@ export interface HProps { | { name: 'isLeapYearCaption' } | { name: 'yellowHighlighted' } | { name: 'leapYearConditionalCaption' } + | { + name: 'conditionSectionName' + type: 'condition' | 'trueCase' | 'falseCase' + } } diff --git a/src/types/VariableNames.ts b/src/types/VariableNames.ts index 850e80fec..469806c49 100644 --- a/src/types/VariableNames.ts +++ b/src/types/VariableNames.ts @@ -35,6 +35,7 @@ export type VariableNames = | 'abbreviated' | 'Amult' | 'questionV2' + | 'blankNumber' export interface VariableNamesWithAlphaConvertCount { name: VariableNames