From 160382dba653ef08e1072043875ab7d8571fa45d 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: Sat, 9 Nov 2024 10:00:10 +0000 Subject: [PATCH 1/4] test: update test code to apply changed syntax --- deno.json | 2 +- deno.lock | 12 ++++++++++ src/index.ts | 5 ++++ test/codes/bmi.yak | 2 +- test/codes/function-variants.yak | 8 +++---- test/codes/hanoi.yak | 2 +- ...d-argument-closing-parenthesis-but.test.ts | 2 +- test/future-function-invoke-syntax.test.ts | 23 +++++++++++++++++++ test/mention.test.ts | 4 ++-- 9 files changed, 50 insertions(+), 10 deletions(-) create mode 100644 test/future-function-invoke-syntax.test.ts diff --git a/deno.json b/deno.json index 8c7c7d5..efb1c09 100644 --- a/deno.json +++ b/deno.json @@ -3,7 +3,7 @@ "@vue/runtime-dom": "npm:@vue/runtime-dom@^3.5.12", "@vueuse/core": "npm:@vueuse/core@^11.2.0", "ansi-to-html": "npm:ansi-to-html@^0.7.2", - "assert": "https://deno.land/std@0.208.0/assert/mod.ts", + "assert": "jsr:@std/assert", "quickjs-emscripten": "npm:quickjs-emscripten@^0.31.0", "quickjs-emscripten-core": "npm:quickjs-emscripten-core@^0.31.0", "typedoc": "npm:typedoc@0.26.11", diff --git a/deno.lock b/deno.lock index 857478e..7a0cbc1 100644 --- a/deno.lock +++ b/deno.lock @@ -3,8 +3,10 @@ "specifiers": { "jsr:@luca/esbuild-deno-loader@0.11": "0.11.0", "jsr:@sebastianwessel/quickjs@*": "1.3.0", + "jsr:@std/assert@*": "1.0.7", "jsr:@std/bytes@^1.0.2": "1.0.2", "jsr:@std/encoding@^1.0.5": "1.0.5", + "jsr:@std/internal@^1.0.5": "1.0.5", "jsr:@std/path@^1.0.6": "1.0.7", "npm:@types/node@*": "22.5.4", "npm:@vue/runtime-dom@^3.5.12": "3.5.12", @@ -49,12 +51,21 @@ "npm:typescript" ] }, + "@std/assert@1.0.7": { + "integrity": "64ce9fac879e0b9f3042a89b3c3f8ccfc9c984391af19e2087513a79d73e28c3", + "dependencies": [ + "jsr:@std/internal" + ] + }, "@std/bytes@1.0.2": { "integrity": "fbdee322bbd8c599a6af186a1603b3355e59a5fb1baa139f8f4c3c9a1b3e3d57" }, "@std/encoding@1.0.5": { "integrity": "ecf363d4fc25bd85bd915ff6733a7e79b67e0e7806334af15f4645c569fefc04" }, + "@std/internal@1.0.5": { + "integrity": "54a546004f769c1ac9e025abd15a76b6671ddc9687e2313b67376125650dc7ba" + }, "@std/path@1.0.7": { "integrity": "76a689e07f0e15dcc6002ec39d0866797e7156629212b28f27179b8a5c3b33a1" } @@ -2228,6 +2239,7 @@ }, "workspace": { "dependencies": [ + "jsr:@std/assert@*", "npm:@vue/runtime-dom@^3.5.12", "npm:@vueuse/core@^11.2.0", "npm:ansi-to-html@~0.7.2", diff --git a/src/index.ts b/src/index.ts index 5275827..1332eb4 100644 --- a/src/index.ts +++ b/src/index.ts @@ -16,11 +16,16 @@ import { parse } from './prepare/parse/index.ts' import { tokenize } from './prepare/tokenize/index.ts' import { ErrorInModuleError } from './error/mention.ts' +interface FeatureFlags { + 'future-function-invoke-syntax': boolean +} + interface YaksokConfig { stdout: (message: string) => void stderr: (message: string) => void entryPoint: string runFFI: (runtime: string, code: string, args: Params) => ValueTypes + flags?: Partial } const defaultConfig: YaksokConfig = { diff --git a/test/codes/bmi.yak b/test/codes/bmi.yak index 66ad4b3..6222c56 100644 --- a/test/codes/bmi.yak +++ b/test/codes/bmi.yak @@ -1,5 +1,5 @@ 약속, 키 (키) 몸무게 (몸무게)의 비만도 결과: 몸무게 / (키 / 100 * 키 / 100) -비만도: 키 (177) 몸무게 (68)의 비만도 +비만도: 키 177 몸무게 68 의 비만도 비만도 보여주기 diff --git a/test/codes/function-variants.yak b/test/codes/function-variants.yak index afeea82..e2b37f4 100644 --- a/test/codes/function-variants.yak +++ b/test/codes/function-variants.yak @@ -1,7 +1,7 @@ 약속, (음식)을/를 (사람)와/과 먹기 "맛있는 " + 음식 + ", " + 사람 + "의 입으로 모두 들어갑니다." 보여주기 -("피자")를 ("철수")와 먹기 -("햄버거")를 ("영희")와 먹기 -("치킨")을 ("형님")과 먹기 -("초밥")을 ("동생")과 먹기 +"피자"를 "철수"와 먹기 +"햄버거"를 "영희"와 먹기 +"치킨"을 "형님"과 먹기 +"초밥"을 "동생"과 먹기 diff --git a/test/codes/hanoi.yak b/test/codes/hanoi.yak index b1faad1..775f9b6 100644 --- a/test/codes/hanoi.yak +++ b/test/codes/hanoi.yak @@ -6,4 +6,4 @@ 막대1 + " -> " + 막대3 보여주기 하노이 (개수-1) (막대2) (막대1) (막대3) 이동 -하노이 (3) ("A") ("B") ("C") 이동 +하노이 3 "A" "B" "C" 이동 diff --git a/test/errors/expected-argument-closing-parenthesis-but.test.ts b/test/errors/expected-argument-closing-parenthesis-but.test.ts index be6da21..ab0addb 100644 --- a/test/errors/expected-argument-closing-parenthesis-but.test.ts +++ b/test/errors/expected-argument-closing-parenthesis-but.test.ts @@ -2,7 +2,7 @@ import { assertIsError, unreachable } from 'assert' import { yaksok } from '../../src/index.ts' import { UnexpectedTokenError } from '../../src/error/index.ts' -Deno.test('인자를 닫는 괄호가 필요하지만 없습니다', () => { +Deno.test('인자를 닫는 괄호가 제 위치에 없습니다', () => { try { yaksok(` 약속, (음식 10)을 맛있게 만들기 diff --git a/test/future-function-invoke-syntax.test.ts b/test/future-function-invoke-syntax.test.ts new file mode 100644 index 0000000..67298a8 --- /dev/null +++ b/test/future-function-invoke-syntax.test.ts @@ -0,0 +1,23 @@ +import { equal } from 'assert' +import { yaksok } from '../src/index.ts' + +Deno.test('미래의 약속 호출 문법', () => { + let output = '' + + yaksok( + `약속, (A)와 (B)를 더하기 + 결과: A + B + +(4)와 (5)를 더하기 보여주기`, + { + flags: { + 'future-function-invoke-syntax': true, + }, + stdout(value) { + output += value + '\n' + }, + }, + ) + + equal(output, '9\n') +}) diff --git a/test/mention.test.ts b/test/mention.test.ts index b287573..371dee4 100644 --- a/test/mention.test.ts +++ b/test/mention.test.ts @@ -25,10 +25,10 @@ Deno.test('Mentioning', () => { `.trim(), main: ` "청량리부터 안동까지 KTX 이음을 타면" 보여주기 -(@코레일 (@차종 KTX이음)으로 (@역간거리 ("청량리")부터 ("안동")까지)km을 이동할 때 운임) + "원" 보여주기 +(@코레일 (@차종 KTX이음)으로 (@역간거리 "청량리" 부터 "안동" 까지)km을 이동할 때 운임) + "원" 보여주기 "판교부터 충주까지 무궁화호를 타면" 보여주기 -(@코레일 (@차종 무궁화호)으로 (@역간거리 ("판교")부터 ("충주")까지)km을 이동할 때 운임) + "원" 보여주기 +(@코레일 (@차종 무궁화호)으로 (@역간거리 "판교" 부터 "충주" 까지)km을 이동할 때 운임) + "원" 보여주기 @코레일 출발하기 `, From ddfeb7fad790914a1349fea2135de5140654d01e 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: Sat, 9 Nov 2024 10:23:20 +0000 Subject: [PATCH 2/4] feat: add feature flags support --- src/contant/feature-flags.ts | 5 +++++ src/index.ts | 10 +++++----- 2 files changed, 10 insertions(+), 5 deletions(-) create mode 100644 src/contant/feature-flags.ts diff --git a/src/contant/feature-flags.ts b/src/contant/feature-flags.ts new file mode 100644 index 0000000..02cb0a3 --- /dev/null +++ b/src/contant/feature-flags.ts @@ -0,0 +1,5 @@ +export enum FEATURE_FLAG { + FUTURE_FUNCTION_INVOKE_SYNTAX = 'future-function-invoke-syntax', +} + +export type EnabledFlags = Partial> diff --git a/src/index.ts b/src/index.ts index 1332eb4..1dcd2f1 100644 --- a/src/index.ts +++ b/src/index.ts @@ -15,17 +15,14 @@ import { run } from '../src/runtime/run.ts' import { parse } from './prepare/parse/index.ts' import { tokenize } from './prepare/tokenize/index.ts' import { ErrorInModuleError } from './error/mention.ts' - -interface FeatureFlags { - 'future-function-invoke-syntax': boolean -} +import { EnabledFlags } from './contant/feature-flags.ts' interface YaksokConfig { stdout: (message: string) => void stderr: (message: string) => void entryPoint: string runFFI: (runtime: string, code: string, args: Params) => ValueTypes - flags?: Partial + flags: EnabledFlags } const defaultConfig: YaksokConfig = { @@ -35,6 +32,7 @@ const defaultConfig: YaksokConfig = { runFFI: (runtime: string) => { throw new Error(`FFI ${runtime} not implemented`) }, + flags: {}, } export class CodeRunner { @@ -119,6 +117,7 @@ export class Yaksok implements YaksokConfig { stderr: YaksokConfig['stderr'] entryPoint: YaksokConfig['entryPoint'] runFFI: YaksokConfig['runFFI'] + flags: Partial = {} runners: Record = {} ran: Record = {} @@ -131,6 +130,7 @@ export class Yaksok implements YaksokConfig { this.stderr = config.stderr || defaultConfig.stderr this.entryPoint = config.entryPoint || defaultConfig.entryPoint this.runFFI = config.runFFI || defaultConfig.runFFI + this.flags = config.flags || defaultConfig.flags } getRunner(fileName = this.entryPoint): CodeRunner { From 621ec0865ca4bf0e60322aa530840f3c043811f8 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: Sat, 9 Nov 2024 10:23:51 +0000 Subject: [PATCH 3/4] feat: add support for non-parenthesis value usage for parameter --- runtest.ts | 37 ++++++--------- src/prepare/parse/dynamicRule/index.ts | 2 +- .../local/createRuleFromFunctionHeader.ts | 45 ++++++++++++++----- src/prepare/parse/dynamicRule/local/index.ts | 21 ++++++--- 4 files changed, 65 insertions(+), 40 deletions(-) diff --git a/runtest.ts b/runtest.ts index 662bdc3..32a1ce0 100644 --- a/runtest.ts +++ b/runtest.ts @@ -1,31 +1,22 @@ -import { QuickJS, yaksok } from './src/index.ts' - -const quickJS = new QuickJS({ - prompt: () => { - return '10' - }, -}) - -await quickJS.init() +import { yaksok } from './src/index.ts' yaksok( ` -번역(QuickJS), 에러 발생 -*** - return ("ㅁㄴㅇㄹ" as string) */ 10 -*** +약속, (음식)을/를 (사람)와/과 먹기 + "맛있는 " + 음식 + ", " + 사람 + "의 입으로 모두 들어갑니다." 보여주기 -에러 발생 - `, - { - runFFI(_, code, args) { - const result = quickJS.run(code, args) - - if (!result) { - throw new Error('Result is null') - } +"피자"를 "철수"와 먹기 +"햄버거"를 "영희"와 먹기 +"치킨"을 "형님"과 먹기 +"초밥"을 "동생"과 먹기 - return result +("피자")를 ("철수")와 먹기 +("햄버거")를 ("영희")와 먹기 +("치킨")을 ("형님")과 먹기 +("초밥")을 ("동생")과 먹기`, + { + flags: { + 'future-function-invoke-syntax': false, }, }, ) diff --git a/src/prepare/parse/dynamicRule/index.ts b/src/prepare/parse/dynamicRule/index.ts index 2976ca2..e0784ac 100644 --- a/src/prepare/parse/dynamicRule/index.ts +++ b/src/prepare/parse/dynamicRule/index.ts @@ -4,7 +4,7 @@ import type { TokenizeResult } from '../../tokenize/index.ts' import type { Yaksok } from '../../../index.ts' export function createDynamicRule(tokenized: TokenizeResult, runtime: Yaksok) { - const localRules = createLocalDynamicRules(tokenized) + const localRules = createLocalDynamicRules(tokenized, runtime) const mentioningRules = getDynamicRulesFromMention( tokenized.tokens, runtime, diff --git a/src/prepare/parse/dynamicRule/local/createRuleFromFunctionHeader.ts b/src/prepare/parse/dynamicRule/local/createRuleFromFunctionHeader.ts index f96e0b7..b3e3557 100644 --- a/src/prepare/parse/dynamicRule/local/createRuleFromFunctionHeader.ts +++ b/src/prepare/parse/dynamicRule/local/createRuleFromFunctionHeader.ts @@ -1,3 +1,9 @@ +import { + EnabledFlags, + FEATURE_FLAG, +} from '../../../../contant/feature-flags.ts' +import { Evaluable } from '../../../../node/base.ts' +import { ValueWithParenthesis } from '../../../../node/calculation.ts' import { type Node, Identifier, Expression } from '../../../../node/index.ts' import { isParentheses } from '../../../../util/isBracket.ts' import { createFunctionDeclareRule } from './declareRule.ts' @@ -8,19 +14,38 @@ import type { import { getVariants } from './getVariants.ts' import { createFunctionInvokeRule } from './invokeRule.ts' -export function createRuleFromFunctionHeader( - subtokens: Node[], - type: keyof typeof functionRuleByType, -) { - assertValidFunctionHeader(subtokens) +interface Args { + subtokens: Node[] + type: keyof typeof functionRuleByType + flags: EnabledFlags +} - const name = getFunctionNameFromHeader(subtokens) - const variants = [...getVariants(subtokens)] +export function createRuleFromFunctionHeader(args: Args) { + assertValidFunctionHeader(args.subtokens) - const declareRule = createFunctionDeclareRule(name, subtokens, { - type, + const name = getFunctionNameFromHeader(args.subtokens) + const variants = [...getVariants(args.subtokens)] + + const declareRule = createFunctionDeclareRule(name, args.subtokens, { + type: args.type, }) - const invokeRules = variants.map((v) => createFunctionInvokeRule(name, v)) + + let invokeRules = variants.map((v) => createFunctionInvokeRule(name, v)) + + if (!args.flags[FEATURE_FLAG.FUTURE_FUNCTION_INVOKE_SYNTAX]) { + invokeRules = invokeRules.map((rule) => ({ + ...rule, + pattern: rule.pattern.map((unit) => { + if (unit.type === ValueWithParenthesis) { + return { + type: Evaluable, + } + } + + return unit + }), + })) + } return [declareRule, ...invokeRules] } diff --git a/src/prepare/parse/dynamicRule/local/index.ts b/src/prepare/parse/dynamicRule/local/index.ts index d0b4f2e..e779f83 100644 --- a/src/prepare/parse/dynamicRule/local/index.ts +++ b/src/prepare/parse/dynamicRule/local/index.ts @@ -1,16 +1,25 @@ import type { TokenizeResult } from '../../../tokenize/index.ts' +import type { Yaksok } from '../../../../index.ts' import { createRuleFromFunctionHeader } from './createRuleFromFunctionHeader.ts' -export function createLocalDynamicRules({ - functionHeaders, - ffiHeaders, -}: TokenizeResult) { +export function createLocalDynamicRules( + { functionHeaders, ffiHeaders }: TokenizeResult, + runtime: Yaksok, +) { const functionRules = functionHeaders.flatMap((rule) => - createRuleFromFunctionHeader(rule, 'yaksok'), + createRuleFromFunctionHeader({ + subtokens: rule, + type: 'yaksok', + flags: runtime.flags, + }), ) const ffiRules = ffiHeaders.flatMap((header) => - createRuleFromFunctionHeader(header, 'ffi'), + createRuleFromFunctionHeader({ + subtokens: header, + type: 'ffi', + flags: runtime.flags, + }), ) return [...functionRules, ...ffiRules].map((e) => [e]) From 9618ecf6a0ebb64cf62df7195d2edd711d3a0d9f 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: Sat, 9 Nov 2024 10:24:49 +0000 Subject: [PATCH 4/4] chore: bump version to v0.1.13 --- deno.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deno.json b/deno.json index efb1c09..d44f788 100644 --- a/deno.json +++ b/deno.json @@ -34,7 +34,7 @@ } }, "name": "@yaksok-ts/core", - "version": "0.1.12", + "version": "0.1.13", "exports": "./src/index.ts", "nodeModulesDir": "auto" } \ No newline at end of file