Skip to content

Commit

Permalink
Merge pull request #44 from rycont/fix-identifier-as-parameter-parse-…
Browse files Browse the repository at this point in the history
…error

Fix identifier as parameter parse error
  • Loading branch information
rycont authored Nov 14, 2024
2 parents 9a31ca4 + 2c48604 commit c1c0eaa
Show file tree
Hide file tree
Showing 9 changed files with 159 additions and 50 deletions.
2 changes: 1 addition & 1 deletion deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
}
},
"name": "@yaksok-ts/core",
"version": "0.1.16",
"version": "0.1.17",
"exports": "./src/mod.ts",
"nodeModulesDir": "auto",
"workspace": [
Expand Down
2 changes: 1 addition & 1 deletion quickjs/deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@
"quickjs-emscripten": "npm:quickjs-emscripten@^0.31.0",
"quickjs-emscripten-core": "npm:quickjs-emscripten-core@^0.31.0"
},
"version": "0.1.16"
"version": "0.1.17"
}
65 changes: 31 additions & 34 deletions runtest.ts
Original file line number Diff line number Diff line change
@@ -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 + "<join>" + 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 도 회전하기
각도 도 회전하기
(각도)도 회전하기
`,
)
4 changes: 3 additions & 1 deletion src/prepare/parse/dynamicRule/local/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,7 @@ export function createLocalDynamicRules(
}),
)

return [...functionRules, ...ffiRules].map((e) => [e])
return [...functionRules, ...ffiRules]
.toSorted((a, b) => b.pattern.length - a.pattern.length)
.map((e) => [e])
}
74 changes: 61 additions & 13 deletions src/prepare/parse/dynamicRule/local/invokeRule.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { FunctionParams } from '../../../../constant/type.ts'
import {
type Node,
Expression,
Expand All @@ -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,
Expand All @@ -35,20 +39,64 @@ export function createFunctionInvokeRule(
}

function getParamsFromMatchedNodes(
template: FunctionHeaderNode[],
matchedNodes: Node[],
paramNameIndexMap: Map<string, number>,
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(
Expand Down
32 changes: 32 additions & 0 deletions test/codes/call-function-with-variable-as-argument.yak
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
약속, 회전설정 (회전)
결과: "rotate:" + 회전

약속, 시간설정 (시간)
결과: "time:" + 시간

약속, (A) 합 (B)
결과: A + "<join>" + B

약속, (각도)도 회전하기
회전설정 각도 보여주기

약속, (시간)초 동안 (각도)도 회전하기
(시간설정 시간) 합 (회전설정 각도) 보여주기

각도: 45
시간: 30

(3)초 동안 (90)도 회전하기
3 초 동안 90 도 회전하기
(3)초 동안 90 도 회전하기
3 초 동안 (90)도 회전하기

시간 초 동안 각도 도 회전하기
(시간)초 동안 (각도)도 회전하기
(시간)초 동안 각도 도 회전하기
시간 초 동안 (각도)도 회전하기

(90)도 회전하기
90 도 회전하기
각도 도 회전하기
(각도)도 회전하기
12 changes: 12 additions & 0 deletions test/codes/call-function-with-variable-as-argument.yak.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
time:3<join>rotate:90
time:3<join>rotate:90
time:3<join>rotate:90
time:3<join>rotate:90
time:30<join>rotate:45
time:30<join>rotate:45
time:30<join>rotate:45
time:30<join>rotate:45
rotate:90
rotate:90
rotate:45
rotate:45
14 changes: 14 additions & 0 deletions test/codes/function-variants.yak
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,17 @@
"햄버거"를 "영희"와 먹기
"치킨"을 "형님"과 먹기
"초밥"을 "동생"과 먹기

먹을_음식: "유부초밥"
먹일_사람: "현수"

먹을_음식 을 먹일_사람 과 먹기
먹을_음식 을 (먹일_사람)과 먹기

먹을_음식: "대나무"

(먹을_음식)을 먹일_사람 과 먹기

먹일_사람: "지우"

(먹을_음식)을 (먹일_사람)과 먹기
4 changes: 4 additions & 0 deletions test/codes/function-variants.yak.out
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,7 @@
맛있는 햄버거, 영희의 입으로 모두 들어갑니다.
맛있는 치킨, 형님의 입으로 모두 들어갑니다.
맛있는 초밥, 동생의 입으로 모두 들어갑니다.
맛있는 유부초밥, 현수의 입으로 모두 들어갑니다.
맛있는 유부초밥, 현수의 입으로 모두 들어갑니다.
맛있는 대나무, 현수의 입으로 모두 들어갑니다.
맛있는 대나무, 지우의 입으로 모두 들어갑니다.

0 comments on commit c1c0eaa

Please sign in to comment.