From 948d4cbd0cc8c92fb3b4b7493782e17b84d69f38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=ED=95=9C=20Rycont?= <35295182+rycont@users.noreply.github.com> Date: Thu, 14 Nov 2024 10:28:17 +0000 Subject: [PATCH] fix: figure function parameters with explicit retriever --- runtest.ts | 65 ++++++++-------- .../parse/dynamicRule/local/invokeRule.ts | 74 +++++++++++++++---- 2 files changed, 92 insertions(+), 47 deletions(-) diff --git a/runtest.ts b/runtest.ts index 8bc0447..25e6a7c 100644 --- a/runtest.ts +++ b/runtest.ts @@ -1,41 +1,38 @@ -import { FunctionParams } from './src/mod.ts' -import { NumberValue } from './src/mod.ts' import { yaksok } from './src/mod.ts' yaksok( ` -번역(JavaScript), (A)와 (B) 사이 랜덤 수 -*** - return Math.floor(Math.random() * (B - A) + A) -*** +약속, 회전설정 (회전) + 결과: "rotate:" + 회전 -(1)와 (10) 사이 랜덤 수 보여주기 -`, - { - runFFI: (runtime, code, params) => { - if (runtime !== 'JavaScript') { - throw new Error('지원하지 않는 런타임입니다') - } - - const runnableCode = buildCodeFromCodeAndParams(code, params) - const resultInJS = eval(runnableCode) - - if (typeof resultInJS !== 'number') { - throw new Error('결과값은 숫자여야 합니다') - } - - return new NumberValue(resultInJS) - }, - }, -) +약속, 시간설정 (시간) + 결과: "time:" + 시간 + +약속, (A) 합 (B) + 결과: A + "" + B + +약속, (각도)도 회전하기 + 회전설정 각도 보여주기 + +약속, (시간)초 동안 (각도)도 회전하기 + (시간설정 시간) 합 (회전설정 각도) 보여주기 -function buildCodeFromCodeAndParams(code: string, params: FunctionParams) { - const paramNames = Object.keys(params) - const paramsInJS = Object.fromEntries( - Object.entries(params).map(([key, value]) => [key, value.value]), - ) +각도: 45 +시간: 30 - return `((${paramNames.join(', ')}) => {${code}})(${Object.values( - paramsInJS, - ).join(', ')})` -} +(3)초 동안 (90)도 회전하기 +3 초 동안 90 도 회전하기 +(3)초 동안 90 도 회전하기 +3 초 동안 (90)도 회전하기 + +시간 초 동안 각도 도 회전하기 +(시간)초 동안 (각도)도 회전하기 +(시간)초 동안 각도 도 회전하기 +시간 초 동안 (각도)도 회전하기 + +(90)도 회전하기 +90 도 회전하기 +각도 도 회전하기 +(각도)도 회전하기 +`, +) diff --git a/src/prepare/parse/dynamicRule/local/invokeRule.ts b/src/prepare/parse/dynamicRule/local/invokeRule.ts index 7802270..aafe5e9 100644 --- a/src/prepare/parse/dynamicRule/local/invokeRule.ts +++ b/src/prepare/parse/dynamicRule/local/invokeRule.ts @@ -1,3 +1,4 @@ +import { FunctionParams } from '../../../../constant/type.ts' import { type Node, Expression, @@ -19,10 +20,13 @@ export function createFunctionInvokeRule( .map(functionHeaderToInvokeMap) .filter(Boolean) as PatternUnit[] + const paramNameIndexMap = getParamNameIndexMapFromHeader(subtokens) + return { pattern: invokeTemplate, factory(nodes: Node[]) { - const params = getParamsFromMatchedNodes(subtokens, nodes) + const params = getParamsFromMatchedNodes(paramNameIndexMap, nodes) + return new FunctionInvoke({ name, params, @@ -35,20 +39,64 @@ export function createFunctionInvokeRule( } function getParamsFromMatchedNodes( - template: FunctionHeaderNode[], - matchedNodes: Node[], + paramNameIndexMap: Map, + nodes: Node[], +) { + const params = {} as FunctionParams + + for (const [paramName, index] of paramNameIndexMap) { + const node = nodes[index] + + if (!(node instanceof Evaluable)) { + throw new Error('Node is not Evaluable') + } + + params[paramName] = node + } + + return params +} + +function getParamNameIndexMapFromHeader( + functionHeaderNodes: FunctionHeaderNode[], ) { - return Object.fromEntries( - template - .filter((token) => !(token instanceof Expression)) - .map((token, i) => [token, matchedNodes[i]]) - .filter( - (set): set is [Identifier, Evaluable] => - set[1] instanceof Evaluable && - !(set[1] instanceof Identifier), - ) - .map(([token, node]) => [token.value, node]), + let parenthesesCount = 0 + + const paramNameIndexMap = new Map( + ( + functionHeaderNodes + .map((token, index) => { + if (token instanceof Expression) { + parenthesesCount += 1 + return null + } + + const prevToken = functionHeaderNodes[index - 1] + const nextToken = functionHeaderNodes[index + 1] + + if (!prevToken || !nextToken) { + return null + } + + const isPreviousTokenOpeningParentheses = + isParentheses(prevToken) === BRACKET_TYPE.OPENING + const isNextTokenClosingParentheses = + isParentheses(nextToken) === BRACKET_TYPE.CLOSING + + if ( + !isPreviousTokenOpeningParentheses || + !isNextTokenClosingParentheses + ) { + return null + } + + return [token, index - parenthesesCount] + }) + .filter(Boolean) as [FunctionHeaderNode, number][] + ).map(([token, index]) => [token.value, index]), ) + + return paramNameIndexMap } function functionHeaderToInvokeMap(