From 4a6eba2ab8e3862b8a1365545112c79f51dd0209 Mon Sep 17 00:00:00 2001 From: takejohn Date: Thu, 7 Aug 2025 15:48:20 +0900 Subject: [PATCH 1/2] =?UTF-8?q?=E6=95=B0=E5=80=A4=E3=83=AA=E3=83=86?= =?UTF-8?q?=E3=83=A9=E3=83=AB=E3=81=AB=E6=8C=87=E6=95=B0=E8=A1=A8=E8=A8=98?= =?UTF-8?q?=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/parser/scanner.ts | 27 +++++++++++++++++++++++++++ test/literals.ts | 27 +++++++++++++++++++++++++++ unreleased/exponential-notation.md | 1 + 3 files changed, 55 insertions(+) create mode 100644 unreleased/exponential-notation.md diff --git a/src/parser/scanner.ts b/src/parser/scanner.ts index cb86984f9..50dad9ada 100644 --- a/src/parser/scanner.ts +++ b/src/parser/scanner.ts @@ -10,6 +10,7 @@ const spaceChars = [' ', '\t']; const lineBreakChars = ['\r', '\n']; const digit = /^[0-9]$/; const wordChar = /^[A-Za-z0-9_]$/; +const exponentIndicatorPattern = /^[eE]$/; /** * 入力文字列からトークンを読み取るクラス @@ -436,12 +437,38 @@ export class Scanner implements ITokenStream { throw new AiScriptSyntaxError('digit expected', pos); } } + + let exponentIndicator = ''; + let exponentSign = ''; + let exponentAbsolute = ''; + if (!this.stream.eof && exponentIndicatorPattern.test(this.stream.char as string)) { + exponentIndicator = this.stream.char as string; + this.stream.next(); + if (!this.stream.eof && (this.stream.char as string) === '-') { + this.stream.next(); + exponentSign = '-'; + } else if (!this.stream.eof && (this.stream.char as string) === '+') { + this.stream.next(); + exponentSign = '+'; + } + while (!this.stream.eof && digit.test(this.stream.char)) { + exponentAbsolute += this.stream.char; + this.stream.next(); + } + if (exponentAbsolute.length === 0) { + throw new AiScriptSyntaxError('exponent expected', pos); + } + } + let value: string; if (fractional.length > 0) { value = wholeNumber + '.' + fractional; } else { value = wholeNumber; } + if (exponentIndicator.length > 0) { + value += exponentIndicator + exponentSign + exponentAbsolute; + } return TOKEN(TokenKind.NumberLiteral, pos, { hasLeftSpacing, value }); } diff --git a/test/literals.ts b/test/literals.ts index 462cb5b7e..a9f500d88 100644 --- a/test/literals.ts +++ b/test/literals.ts @@ -58,6 +58,33 @@ describe('literal', () => { eq(res, NUM(0.5)); }); + test.concurrent('number (positive exponent without plus sign)', async () => { + const res = await exe(` + <: 1.2e3 + `); + eq(res, NUM(1200)); + }); + + test.concurrent('number (positive exponent with plus sign)', async () => { + const res = await exe(` + <: 1.2e+3 + `); + eq(res, NUM(1200)); + }); + + test.concurrent('number (negative exponent)', async () => { + const res = await exe(` + <: 1.2e-3 + `); + eq(res, NUM(0.0012)); + }); + + test.concurrent('number (missing exponent)', async () => { + assert.rejects(() => exe(` + <: 1.2e+ + `), 'exponent expected'); + }); + test.concurrent('arr (separated by comma)', async () => { const res = await exe(` <: [1, 2, 3] diff --git a/unreleased/exponential-notation.md b/unreleased/exponential-notation.md new file mode 100644 index 000000000..15fb92137 --- /dev/null +++ b/unreleased/exponential-notation.md @@ -0,0 +1 @@ +- 数値リテラルを指数表記で記述できるようになりました。 From dbdd775916835cb13247c278f0e2970e337be8cd Mon Sep 17 00:00:00 2001 From: takejohn Date: Thu, 7 Aug 2025 15:54:24 +0900 Subject: [PATCH 2/2] =?UTF-8?q?next()=E3=83=A1=E3=82=BD=E3=83=83=E3=83=89?= =?UTF-8?q?=E3=81=AE=E5=91=BC=E3=81=B3=E5=87=BA=E3=81=97=E4=BD=8D=E7=BD=AE?= =?UTF-8?q?=E3=81=8C=E6=B0=97=E3=81=AB=E3=81=AA=E3=82=8B=E3=81=AE=E3=81=A7?= =?UTF-8?q?=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/parser/scanner.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/parser/scanner.ts b/src/parser/scanner.ts index 50dad9ada..ac55843fa 100644 --- a/src/parser/scanner.ts +++ b/src/parser/scanner.ts @@ -445,11 +445,11 @@ export class Scanner implements ITokenStream { exponentIndicator = this.stream.char as string; this.stream.next(); if (!this.stream.eof && (this.stream.char as string) === '-') { - this.stream.next(); exponentSign = '-'; - } else if (!this.stream.eof && (this.stream.char as string) === '+') { this.stream.next(); + } else if (!this.stream.eof && (this.stream.char as string) === '+') { exponentSign = '+'; + this.stream.next(); } while (!this.stream.eof && digit.test(this.stream.char)) { exponentAbsolute += this.stream.char;