-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathenvironment.js
63 lines (54 loc) · 1.78 KB
/
environment.js
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
const { runtimeError } = require('./errors')
class Environment {
constructor(enclosing) {
this.map = new Map()
this.enclosing = enclosing
}
get(varToken) {
if (this.map.has(varToken.name.lexeme)) {
return this.map.get(varToken.name.lexeme)
}
if (this.enclosing) return this.enclosing.get(varToken)
throw runtimeError(`Undefined variable "${varToken.name.lexeme}"`, varToken.name)
}
set(token, value) {
if (this.map.has(token.lexeme)) {
throw runtimeError(`Duplicate variable declaration "${token.lexeme}"`, token)
// return this.map.set(token.lexeme, value)
}
return this.map.set(token.lexeme, value)
}
setBuiltin(name, func) {
this.map.set(name, typeof func === 'function' ? { call: func } : func)
}
setBuiltinClass(name, klass) {
this.map.set(name, JSClassToLoxClass(klass))
}
assign(token, value) {
if (!this.map.has(token.lexeme)) {
if (this.enclosing) return this.enclosing.assign(token, value)
throw runtimeError(`Undefined variable "${token.lexeme}"`, token)
}
return this.map.set(token.lexeme, value)
}
}
module.exports = Environment
// We do all this below the export to avoid a circular dependancy
const { LoxClass } = require('./interpreter')
class FakeInstance {
constructor(call) {
this.call = call
}
bind(instance) {
this.call = this.call.bind(instance)
return this
}
}
const JSClassToLoxClass = klass => {
const methodNames = Object.getOwnPropertyNames(klass.prototype)
const methods = new Map(methodNames.map(name => [name, new FakeInstance(klass.prototype[name])]))
// TODO: Throw an error if user passes in a constructor
if (methods.has('constructor')) methods.delete('constructor')
const newKlass = new LoxClass(klass.name, methods)
return newKlass
}