1
1
function parseAdd ( expression : string ) : Expression {
2
2
const content = expression . slice ( "(add " . length , - 1 ) ;
3
3
const list = parseList ( "(" + content + ")" ) ;
4
- console . log ( list ) ;
4
+ // console.log(list);
5
5
if ( Array . isArray ( list ) && list . length !== 2 ) {
6
6
throw Error ( "Invalid expression" ) ;
7
7
}
@@ -10,7 +10,7 @@ function parseAdd(expression: string): Expression {
10
10
function parseLet ( expression : string ) : Expression {
11
11
const content = expression . slice ( "(let " . length , - 1 ) ;
12
12
const list = parseList ( "(" + content + ")" ) ;
13
- console . log ( list ) ;
13
+ // console.log(list);
14
14
if ( Array . isArray ( list ) && list . length == 0 ) {
15
15
throw Error ( "Invalid expression" ) ;
16
16
}
@@ -20,14 +20,40 @@ function parseLet(expression: string): Expression {
20
20
function parseMult ( expression : string ) : Expression {
21
21
const content = expression . slice ( "(mult " . length , - 1 ) ;
22
22
const list = parseList ( "(" + content + ")" ) ;
23
- console . log ( list ) ;
23
+ // console.log(list);
24
24
if ( Array . isArray ( list ) && list . length !== 2 ) {
25
25
throw Error ( "Invalid expression" ) ;
26
26
}
27
27
return buildExpression ( [ "mult" , ...list ] ) ;
28
28
}
29
29
function buildExpression ( list : string | number | ListArray ) : Expression {
30
- console . log ( list ) ;
30
+ // console.log(list);
31
+ if ( Array . isArray ( list ) && list [ 0 ] === "let" ) {
32
+ const variables = list . slice ( 1 , - 1 ) . map ( buildExpression ) ;
33
+ // console.log(variables);
34
+ const declarations : VariableDeclarator [ ] = Array ( variables . length / 2 )
35
+ . fill ( 0 )
36
+ . map ( ( _ , i ) => {
37
+ const ident = variables [ i * 2 ] ;
38
+ if ( ident . type !== "Identifier" ) {
39
+ throw Error ( "Invalid identifier" ) ;
40
+ }
41
+ return {
42
+ type : "VariableDeclarator" ,
43
+ id : ident ,
44
+ init : variables [ i * 2 + 1 ] ,
45
+ } ;
46
+ } ) ;
47
+ return {
48
+ type : "LetExpression" ,
49
+
50
+ declarations : declarations ,
51
+ return : {
52
+ type : "ReturnStatement" ,
53
+ argument : buildExpression ( list [ list . length - 1 ] ) ,
54
+ } ,
55
+ } ;
56
+ }
31
57
if ( typeof list === "string" ) {
32
58
return { type : "Identifier" , name : list } ;
33
59
}
@@ -72,9 +98,9 @@ function parseNumeric(expression: string | number): Expression {
72
98
}
73
99
74
100
function evaluate ( expression : string ) : number {
75
- console . log ( expression ) ;
101
+ // console.log(expression);
76
102
const ast = parse ( expression ) ;
77
- console . log ( ast ) ;
103
+ // console.log(ast);
78
104
return calculate ( ast , new ScopeList ( ) ) ;
79
105
}
80
106
function parse ( expression : string ) : Expression {
@@ -102,8 +128,10 @@ function parseIdentifier(expression: string): Expression {
102
128
}
103
129
104
130
function calculate ( expression : Expression , scope : ScopeList ) : number {
105
- console . log ( expression , scope ) ;
131
+ // console.log(expression, scope);
106
132
switch ( expression . type ) {
133
+ case "Identifier" :
134
+ return getVariable ( scope , expression . name ) ;
107
135
case "NumericLiteral" :
108
136
return expression . value ;
109
137
case "MultExpression" :
@@ -116,8 +144,17 @@ function calculate(expression: Expression, scope: ScopeList): number {
116
144
calculate ( expression . left , scope ) +
117
145
calculate ( expression . right , scope )
118
146
) ;
147
+ case "LetExpression" : {
148
+ const newScope = new ScopeList ( new Map ( ) , scope ) ;
149
+ expression . declarations . forEach ( ( declaration ) => {
150
+ newScope . variables . set (
151
+ declaration . id . name ,
152
+ calculate ( declaration . init , newScope ) ,
153
+ ) ;
154
+ } ) ;
155
+ return calculate ( expression . return . argument , newScope ) ;
156
+ }
119
157
}
120
- throw Error ( "Not implemented" ) ;
121
158
}
122
159
export type Expression =
123
160
| Identifier
@@ -165,3 +202,15 @@ export interface Identifier {
165
202
name : string ;
166
203
}
167
204
export default evaluate ;
205
+
206
+ function getVariable ( scope : ScopeList , name : string ) : number {
207
+ if ( ! scope . parent && ! scope . variables . has ( name ) ) {
208
+ throw Error ( "Variable not found:" + name ) ;
209
+ }
210
+ const value = scope . variables . get ( name ) ;
211
+ if ( scope . variables . has ( name ) && typeof value !== "undefined" ) {
212
+ return value ;
213
+ }
214
+ if ( scope . parent ) return getVariable ( scope . parent , name ) ;
215
+ throw Error ( "Variable not found:" + name ) ;
216
+ }
0 commit comments