Skip to content

Commit 77cf3fd

Browse files
authored
enhance: 数値リテラルに指数表記を追加 (#954)
* 数値リテラルに指数表記を追加 * next()メソッドの呼び出し位置が気になるので変更
1 parent 343c820 commit 77cf3fd

3 files changed

Lines changed: 55 additions & 0 deletions

File tree

src/parser/scanner.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const spaceChars = [' ', '\t'];
1010
const lineBreakChars = ['\r', '\n'];
1111
const digit = /^[0-9]$/;
1212
const wordChar = /^[A-Za-z0-9_]$/;
13+
const exponentIndicatorPattern = /^[eE]$/;
1314

1415
/**
1516
* 入力文字列からトークンを読み取るクラス
@@ -436,12 +437,38 @@ export class Scanner implements ITokenStream {
436437
throw new AiScriptSyntaxError('digit expected', pos);
437438
}
438439
}
440+
441+
let exponentIndicator = '';
442+
let exponentSign = '';
443+
let exponentAbsolute = '';
444+
if (!this.stream.eof && exponentIndicatorPattern.test(this.stream.char as string)) {
445+
exponentIndicator = this.stream.char as string;
446+
this.stream.next();
447+
if (!this.stream.eof && (this.stream.char as string) === '-') {
448+
exponentSign = '-';
449+
this.stream.next();
450+
} else if (!this.stream.eof && (this.stream.char as string) === '+') {
451+
exponentSign = '+';
452+
this.stream.next();
453+
}
454+
while (!this.stream.eof && digit.test(this.stream.char)) {
455+
exponentAbsolute += this.stream.char;
456+
this.stream.next();
457+
}
458+
if (exponentAbsolute.length === 0) {
459+
throw new AiScriptSyntaxError('exponent expected', pos);
460+
}
461+
}
462+
439463
let value: string;
440464
if (fractional.length > 0) {
441465
value = wholeNumber + '.' + fractional;
442466
} else {
443467
value = wholeNumber;
444468
}
469+
if (exponentIndicator.length > 0) {
470+
value += exponentIndicator + exponentSign + exponentAbsolute;
471+
}
445472
return TOKEN(TokenKind.NumberLiteral, pos, { hasLeftSpacing, value });
446473
}
447474

test/literals.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,33 @@ describe('literal', () => {
5858
eq(res, NUM(0.5));
5959
});
6060

61+
test.concurrent('number (positive exponent without plus sign)', async () => {
62+
const res = await exe(`
63+
<: 1.2e3
64+
`);
65+
eq(res, NUM(1200));
66+
});
67+
68+
test.concurrent('number (positive exponent with plus sign)', async () => {
69+
const res = await exe(`
70+
<: 1.2e+3
71+
`);
72+
eq(res, NUM(1200));
73+
});
74+
75+
test.concurrent('number (negative exponent)', async () => {
76+
const res = await exe(`
77+
<: 1.2e-3
78+
`);
79+
eq(res, NUM(0.0012));
80+
});
81+
82+
test.concurrent('number (missing exponent)', async () => {
83+
assert.rejects(() => exe(`
84+
<: 1.2e+
85+
`), 'exponent expected');
86+
});
87+
6188
test.concurrent('arr (separated by comma)', async () => {
6289
const res = await exe(`
6390
<: [1, 2, 3]

unreleased/exponential-notation.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- 数値リテラルを指数表記で記述できるようになりました。

0 commit comments

Comments
 (0)