diff --git a/core/deno.json b/core/deno.json index 0b4705f..668f70f 100644 --- a/core/deno.json +++ b/core/deno.json @@ -6,5 +6,5 @@ }, "name": "@dalbit-yaksok/core", "exports": "./mod.ts", - "version": "0.2.0-RC.3" + "version": "0.2.0-RC.4" } \ No newline at end of file diff --git a/core/error/calculation.ts b/core/error/calculation.ts index 4e15570..7ec2e1d 100644 --- a/core/error/calculation.ts +++ b/core/error/calculation.ts @@ -41,3 +41,31 @@ export class InvalidTypeForOperatorError extends YaksokError { )}할 수 없어요.` } } + +export class RangeStartMustBeIntegerError extends YaksokError { + constructor(props: { + tokens?: Token[] + resource: { + start: ValueType + } + }) { + super(props) + + const startText = valueTypeToText(props.resource.start) + this.message = `범위의 시작은 정수여야 해요. ${startText}는 정수가 아니에요.` + } +} + +export class RangeEndMustBeIntegerError extends YaksokError { + constructor(props: { + tokens?: Token[] + resource: { + end: ValueType + } + }) { + super(props) + + const endText = valueTypeToText(props.resource.end) + this.message = `범위의 끝은 정수여야 해요. ${endText}는 정수가 아니에요.` + } +} diff --git a/core/error/indexed.ts b/core/error/indexed.ts index 42ddb06..c3c20b3 100644 --- a/core/error/indexed.ts +++ b/core/error/indexed.ts @@ -46,7 +46,7 @@ export class ListIndexMustBeGreaterThan1Error extends YaksokError { export class RangeEndMustBeNumberError extends YaksokError { constructor(props: { - position?: Position + tokens?: Token[] resource: { end: ValueType } @@ -86,7 +86,6 @@ export class ListIndexTypeError extends YaksokError { export class RangeStartMustBeNumberError extends YaksokError { constructor(props: { - position?: Position tokens?: Token[] resource: { start: ValueType @@ -102,7 +101,6 @@ export class RangeStartMustBeNumberError extends YaksokError { export class TargetIsNotIndexedValueError extends YaksokError { constructor(props: { tokens: Token[] - resource: { target: Evaluable } diff --git a/core/node/calculation.ts b/core/node/calculation.ts index c48ab13..db1bb07 100644 --- a/core/node/calculation.ts +++ b/core/node/calculation.ts @@ -20,7 +20,11 @@ import { import { Evaluable, Operator, OperatorClass } from './base.ts' import { ValueType } from '../value/base.ts' import type { Token } from '../prepare/tokenize/token.ts' -import { InvalidTypeForOperatorError } from '../error/calculation.ts' +import { + InvalidTypeForOperatorError, + RangeEndMustBeIntegerError, + RangeStartMustBeIntegerError, +} from '../error/calculation.ts' import { YaksokError } from '../error/common.ts' import { RangeEndMustBeNumberError, @@ -153,9 +157,15 @@ export class Formula extends Evaluable { if (e instanceof YaksokError && !e.tokens) { if (e instanceof InvalidTypeForOperatorError) { e.tokens = mergedTokens - } else if (e instanceof RangeStartMustBeNumberError) { + } else if ( + e instanceof RangeStartMustBeNumberError || + e instanceof RangeStartMustBeIntegerError + ) { e.tokens = termsWithToken[i - 1].tokens - } else if (e instanceof RangeEndMustBeNumberError) { + } else if ( + e instanceof RangeEndMustBeNumberError || + e instanceof RangeEndMustBeIntegerError + ) { e.tokens = termsWithToken[i + 1].tokens } else if (e instanceof RangeStartMustBeLessThanEndError) { e.tokens = mergedTokens diff --git a/core/node/operator.ts b/core/node/operator.ts index 864c812..cf1cff9 100644 --- a/core/node/operator.ts +++ b/core/node/operator.ts @@ -4,6 +4,8 @@ import { RangeEndMustBeNumberError, RangeStartMustBeLessThanEndError, RangeStartMustBeNumberError, + RangeStartMustBeIntegerError, + RangeEndMustBeIntegerError, } from '../error/index.ts' import { Token } from '../prepare/tokenize/token.ts' @@ -445,9 +447,11 @@ export class RangeOperator extends Operator { this.assertProperOperands(operands) const [start, end] = operands - const items = new Array(end.value - start.value + 1) + const roundedStart = Math.round(start.value) + const roundedEnd = Math.round(end.value) + const items = new Array(roundedEnd - roundedStart + 1) .fill(null) - .map((_, index) => new NumberValue(start.value + index)) + .map((_, index) => new NumberValue(roundedStart + index)) return new ListValue(items) } @@ -465,25 +469,39 @@ export class RangeOperator extends Operator { private assertProperStartType( start: ValueType, ): asserts start is NumberValue { - if (start instanceof NumberValue) return + if (!(start instanceof NumberValue)) { + throw new RangeStartMustBeNumberError({ + resource: { + start, + }, + }) + } - throw new RangeStartMustBeNumberError({ - position: this.tokens[0].position, - resource: { - start, - }, - }) + if (!Number.isInteger(start.value)) { + throw new RangeStartMustBeIntegerError({ + resource: { + start, + }, + }) + } } private assertProperEndType(end: ValueType): asserts end is NumberValue { - if (end instanceof NumberValue) return + if (!(end instanceof NumberValue)) { + throw new RangeEndMustBeNumberError({ + resource: { + end, + }, + }) + } - throw new RangeEndMustBeNumberError({ - position: this.tokens[0].position, - resource: { - end, - }, - }) + if (!Number.isInteger(end.value)) { + throw new RangeEndMustBeIntegerError({ + resource: { + end, + }, + }) + } } private assertRangeStartLessThanEnd(start: number, end: number) { diff --git a/deno.json b/deno.json index d44aa9b..35c733f 100644 --- a/deno.json +++ b/deno.json @@ -22,7 +22,7 @@ "test", "monaco-language-provider" ], - "version": "0.2.0-RC.3", + "version": "0.2.0-RC.4", "tasks": { "apply-version": "deno run --allow-read --allow-write apply-version.ts", "publish": "deno task --recursive test && deno publish --allow-dirty" diff --git a/monaco-language-provider/deno.json b/monaco-language-provider/deno.json index d460d2e..379e675 100644 --- a/monaco-language-provider/deno.json +++ b/monaco-language-provider/deno.json @@ -4,5 +4,5 @@ }, "name": "@dalbit-yaksok/monaco-language-provider", "exports": "./mod.ts", - "version": "0.2.0-RC.3" + "version": "0.2.0-RC.4" } \ No newline at end of file diff --git a/quickjs/deno.json b/quickjs/deno.json index ccd7d2b..126ab26 100644 --- a/quickjs/deno.json +++ b/quickjs/deno.json @@ -9,5 +9,5 @@ "check-deploy": "deno publish --dry-run --allow-dirty", "test": "deno test --quiet --allow-net --allow-read --parallel & deno lint & deno task check-deploy" }, - "version": "0.2.0-RC.3" + "version": "0.2.0-RC.4" } \ No newline at end of file diff --git a/runtest.ts b/runtest.ts index e3e2533..62ec98d 100644 --- a/runtest.ts +++ b/runtest.ts @@ -1,9 +1,5 @@ import { yaksok } from '@dalbit-yaksok/core' await yaksok(` -약속, (10) 말하기 -반복 - 결과: "안녕하세요" - -말하기 보여주기 +3 ~ 8.3 보여주기 `) diff --git a/test/errors/loop.test.ts b/test/errors/loop.test.ts index 2ca7031..c3e0879 100644 --- a/test/errors/loop.test.ts +++ b/test/errors/loop.test.ts @@ -8,6 +8,8 @@ import { RangeEndMustBeNumberError, RangeStartMustBeLessThanEndError, RangeStartMustBeNumberError, + RangeStartMustBeIntegerError, + RangeEndMustBeIntegerError, TargetIsNotIndexedValueError, ListIndexMustBeGreaterThan1Error, } from '../../core/error/index.ts' @@ -75,6 +77,31 @@ Deno.test('Range end must be number', async () => { } }) +Deno.test('Range start must be an integer', async () => { + try { + await yaksok(`1.5 ~ 5`) + unreachable() + } catch (e) { + assertIsError(e, RangeStartMustBeIntegerError) + } + + try { + await yaksok(`1.5 ~ 3.2`) + unreachable() + } catch (e) { + assertIsError(e, RangeStartMustBeIntegerError) + } +}) + +Deno.test('Range end must be an integer', async () => { + try { + await yaksok(`1 ~ 5.5`) + unreachable() + } catch (e) { + assertIsError(e, RangeEndMustBeIntegerError) + } +}) + Deno.test('Index set target is must be indexable', async () => { try { await yaksok(`목록: 5