This repository has been archived by the owner on Oct 10, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
interpreter.ts
64 lines (55 loc) · 2.39 KB
/
interpreter.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import registerOps from './expression/nonterminal/index.ts'
import Operator from './expression/nonterminal/operator.ts'
import logger from './common/logger.ts'
import Machine from './machine.ts'
registerOps()
/**
* 주어진 스크립트를 tokenize하고 실제 수행하는 클래스
*/
class Interpreter {
// (2023. 06. 18.) 테스트용 Interpreter 생성을 위해 machine 객체의 visibility를 protected로 완화
protected machine: Machine = new Machine() // 내부 Machine 객체
/**
* 주어진 스크립트 문자열을 operator 객체 배열로 토큰화
* @param script 입력받은 스크립트 문자열
*/
public tokenize(script: string): void {
logger.trace('Accepting script: %s', script)
let aa: any[] = [script]
Operator.getOps().forEach((Op) => {
logger.trace('Finding operators of %s', Op.toString())
aa = aa
.flatMap((x) => {
if (typeof x === 'string') {
// 토큰화 하기 전의 문자열인 경우
let ab = [...x.matchAll(new RegExp(Op.regexp, 'g'))] // x로부터 명령어 토큰을 찾음
return x
.split(new RegExp(Op.regexp.split(/\(|\)/).join(''))) // 토큰을 문자열에서 제거
.flatMap((y, i) => [y, ab[i] ? new Op(ab[i], this.machine) : '']) // 명령어 객체로 치환
} else return [x] // 이미 객체로 치환된 경우, 그대로 반환
})
.filter((x) => typeof x !== 'string' || x !== '') // 명령어 객체 또는 비어 있지 않은 문자만 남김
})
logger.trace('Finalizing tokenization')
aa.filter((x) => typeof x !== 'string') // 남은 모든 문자열을 제거
.forEach((x) => {
this.machine.push(x)
})
}
/**
* machine을 가동
*/
public async run(): Promise<void> {
let op: Operator | undefined
try {
while ((op = this.machine.next())) {
// machine으로부터 다음 명령어를 받아옴 (undefined이면 종료)
logger.trace('Got operator %s', op.constructor.name)
await op.asyncRun()
}
} catch (e) {
logger.error(e.toString())
}
}
}
export default Interpreter