Skip to content

Commit

Permalink
Merge pull request #70 from rycont/fix-range-operator
Browse files Browse the repository at this point in the history
Fix: range operator to handle non-integer numbers
  • Loading branch information
rycont authored Jan 12, 2025
2 parents 1bc6ed0 + 71a6c20 commit 072350e
Show file tree
Hide file tree
Showing 10 changed files with 108 additions and 31 deletions.
2 changes: 1 addition & 1 deletion core/deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
},
"name": "@dalbit-yaksok/core",
"exports": "./mod.ts",
"version": "0.2.0-RC.3"
"version": "0.2.0-RC.4"
}
28 changes: 28 additions & 0 deletions core/error/calculation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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}는 정수가 아니에요.`
}
}
4 changes: 1 addition & 3 deletions core/error/indexed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export class ListIndexMustBeGreaterThan1Error extends YaksokError {

export class RangeEndMustBeNumberError extends YaksokError {
constructor(props: {
position?: Position
tokens?: Token[]
resource: {
end: ValueType
}
Expand Down Expand Up @@ -86,7 +86,6 @@ export class ListIndexTypeError extends YaksokError {

export class RangeStartMustBeNumberError extends YaksokError {
constructor(props: {
position?: Position
tokens?: Token[]
resource: {
start: ValueType
Expand All @@ -102,7 +101,6 @@ export class RangeStartMustBeNumberError extends YaksokError {
export class TargetIsNotIndexedValueError extends YaksokError {
constructor(props: {
tokens: Token[]

resource: {
target: Evaluable
}
Expand Down
16 changes: 13 additions & 3 deletions core/node/calculation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down
50 changes: 34 additions & 16 deletions core/node/operator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import {
RangeEndMustBeNumberError,
RangeStartMustBeLessThanEndError,
RangeStartMustBeNumberError,
RangeStartMustBeIntegerError,
RangeEndMustBeIntegerError,
} from '../error/index.ts'
import { Token } from '../prepare/tokenize/token.ts'

Expand Down Expand Up @@ -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)
}
Expand All @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
2 changes: 1 addition & 1 deletion monaco-language-provider/deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
2 changes: 1 addition & 1 deletion quickjs/deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
6 changes: 1 addition & 5 deletions runtest.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import { yaksok } from '@dalbit-yaksok/core'

await yaksok(`
약속, (10) 말하기
반복
결과: "안녕하세요"
말하기 보여주기
3 ~ 8.3 보여주기
`)
27 changes: 27 additions & 0 deletions test/errors/loop.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import {
RangeEndMustBeNumberError,
RangeStartMustBeLessThanEndError,
RangeStartMustBeNumberError,
RangeStartMustBeIntegerError,
RangeEndMustBeIntegerError,
TargetIsNotIndexedValueError,
ListIndexMustBeGreaterThan1Error,
} from '../../core/error/index.ts'
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 072350e

Please sign in to comment.