Skip to content

Commit 778735d

Browse files
author
manash
committed
Object Implementation Complete.
1 parent fdeaf10 commit 778735d

File tree

7 files changed

+67
-25
lines changed

7 files changed

+67
-25
lines changed

lexer/lexer.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ export class Lexer {
130130
case '[': return Token.create(TOKEN.LBRACK);
131131

132132
case ']': return Token.create(TOKEN.RBRACK);
133+
134+
case ':': return Token.create(TOKEN.COLON);
133135

134136
default: return this.handleDefaultCase(ch);
135137
}

lexer/token.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export enum TOKEN {
3131
ELSE = "else",
3232
RETURN = "return",
3333
NULL = "NULL",
34+
COLON = ":"
3435
}
3536

3637
const keywords: Map<string, TOKEN> = new Map<string, TOKEN>();
@@ -109,6 +110,7 @@ export const TokenFactory = {
109110
BANG: Token.create(TOKEN.BANG),
110111
COMMA: Token.create(TOKEN.COMMA),
111112
SEMICOLON: Token.create(TOKEN.SEMICOLON),
113+
COLON: Token.create(TOKEN.COLON),
112114
FUNCTION: Token.create(TOKEN.FUNCTION),
113115
LET: Token.create(TOKEN.LET),
114116
TRUE: Token.create(TOKEN.TRUE),

parser/exprs/expr.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@ function argParsers(start: TOKEN, parsingFn : Function, end: TOKEN) {
1919
return args;
2020
}
2121

22-
while (p.nextTokenIs(TOKEN.COMMA)) {
22+
args.push(parsingFn(p));
23+
while (p.curTokenIs(TOKEN.COMMA)) {
24+
p.readToken();
2325
const iden = parsingFn(p)
2426
args.push(iden);
25-
p.readToken();
2627
}
27-
args.push(parsingFn(p));
2828
p.readExpectedToken(end, `Incorrect Function Expression, Missing ${end} for ${start}`);
2929
return args;
3030
}

parser/exprs/hashes.ts

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
import {TOKEN} from "../../lexer/token";
22
import {Parser} from "../parser";
33
import {Expr} from "./expr";
4-
import {Identifier} from "./identifier";
54
import {PRECEDENCE} from "./precedence";
65

76

87
export class Hash implements Expr {
9-
map: Map<string, Expr>;
8+
map: Map<Expr, Expr>;
109
isApplicable(token: TOKEN): boolean {
1110
return token === TOKEN.LBRACE;
1211
}
1312
parse(p: Parser): Expr {
14-
const mp = new Map<string, Expr>();
13+
const mp = new Map<Expr, Expr>();
1514
p.readExpectedToken(TOKEN.LBRACE);
1615
if (p.nextTokenIs(TOKEN.RBRACE)) {
1716
return Hash.empty();
@@ -25,24 +24,24 @@ export class Hash implements Expr {
2524
return Hash.create(mp);
2625
}
2726

28-
parseEntry(p: Parser, mp: Map<string, Expr>): void {
29-
const name = new Identifier().parse(p).toString();
30-
p.readExpectedToken(TOKEN.ASSIGN);
27+
parseEntry(p: Parser, mp: Map<Expr, Expr>): void {
28+
const name = p.parseExpr(PRECEDENCE.LOWEST);
29+
p.readExpectedToken(TOKEN.COLON);
3130
const val = p.parseExpr(PRECEDENCE.LOWEST);
3231
if (mp.has(name)) {
3332
throw Error(`${name} is already declared in the object`);
3433
}
3534
mp.set(name, val);
3635
}
3736

38-
static create(mp: Map<string, Expr>) {
37+
static create(mp: Map<Expr, Expr>) {
3938
const h = new Hash();
4039
h.map = mp;
4140
return h;
4241
}
4342

4443
static empty(): Expr {
45-
const mp = new Map<string, Expr>();
44+
const mp = new Map<Expr, Expr>();
4645
const h = new Hash();
4746
h.map = mp;
4847
return h;
@@ -62,9 +61,9 @@ export class Hash implements Expr {
6261
}
6362

6463
eval() {
65-
const mp: Map<string, any> = new Map<string, any>();
64+
const mp: Map<any, any> = new Map<any, any>();
6665
for(const [k, v] of this.map.entries()) {
67-
mp.set(k, v.eval());
66+
mp.set(k.eval(), v.eval());
6867
}
6968
return mp;
7069
}

parser/exprs/indexExpr.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ export class IndexExpr implements Expr {
1616
return IndexExpr.create(left, right);
1717
}
1818

19-
static create(left: Expr, right: any): Expr {
19+
static create(left: Expr, right: Expr): Expr {
2020
const ex = new IndexExpr();
21-
ex.left =left;
21+
ex.left = left;
2222
ex.right = right;
2323
return ex;
2424
}
@@ -29,9 +29,23 @@ export class IndexExpr implements Expr {
2929
eval() {
3030
const left = this.left.eval();
3131
const right = this.right.eval();
32-
if (!Array.isArray(left)) {
33-
throw new Error(`${this.left.toString()} is not an array`);
32+
if (Array.isArray(left)) {
33+
return this.evalArrayIndex(right, left);
3434
}
35+
if (left instanceof Map) {
36+
return this.evalHashIndex(left, right);
37+
}
38+
throw new Error(this.left.toString() + ' is not an element to be indexed');
39+
}
40+
41+
evalHashIndex(left: Map<any, any>, right: any) {
42+
if (!left.has(right)) {
43+
return null;
44+
}
45+
return left.get(right)!;
46+
}
47+
48+
private evalArrayIndex(right: any, left: any[]) {
3549
if (!Number.isInteger(right)) {
3650
throw new Error(`${this.right.toString()} doesn't evaluate to an integer for an index`);
3751
}

tests/eval/evaluator.test.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,5 +177,28 @@ describe("Evaluation Queries", () => {
177177
testInput(inp, exp);
178178
});
179179
});
180+
181+
describe('7. Objects', () => {
182+
test('1. Evaluation', () => {
183+
const inp = `let name = 'hi'; let obj = { name : 'Yo' }; obj['hi'];`
184+
const exp = 'Yo';
185+
testInput(inp, exp);
186+
});
187+
test('2. Complex Evaluation', () => {
188+
const inp = `let two = "two";
189+
let o = {
190+
"one": 10 - 9,
191+
two: 1 + 1,
192+
"thr" + "ee": 6 / 2,
193+
4: 4,
194+
true: 5,
195+
false: 6
196+
}
197+
return [o['one'], o[two], o['three'], o[4], o[true], o[false]];
198+
`
199+
const exp = [1, 2, 3, 4, 5, 6];
200+
testInput(inp, exp);
201+
});
202+
});
180203
});
181204

tests/parser/parser.test.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -194,19 +194,21 @@ describe("Expression Statements", () => {
194194

195195
describe('8. Objects', () => {
196196
test("a. Simple Objects", () => {
197-
const inp = `{ name = 'blah', val = 1 }`;
198-
const mp = new Map<string, any>();
199-
mp.set('name', 'blah');
200-
mp.set('val', 1);
201-
const actual = Parser.create(inp).parse().eval();
202-
expect(actual).toStrictEqual(mp);
197+
const inp = `{ 'name' : 'blah', 'val' : 1 }`;
198+
const actual = Parser.create(inp).parse().statements;
199+
const mp = new Map<any, any>();
200+
mp.set(StringExpr.create('name'), StringExpr.create('blah'));
201+
mp.set(StringExpr.create('val'), Integer.create(1));
202+
const exp = [
203+
ExprStatement.create(Hash.create(mp))
204+
];
205+
expect(actual).toStrictEqual(exp);
203206
});
204207
});
205208

206209
describe('9. Functions', () => {
207210
test('a. Functions?', () => {
208-
const inp = `add(a * b[2], b[1], 2 * [1, 2][1])`;
209-
const ac = Parser.create(inp).parse().getString();
211+
const inp = `add(a * b[2], b[1], 2 * [1, 2][1])`; const ac = Parser.create(inp).parse().getString();
210212
const exp = `add((a * (b[2])), (b[1]), (2 * ([1, 2][1])))`;
211213
expect(ac).toStrictEqual(exp);
212214
});

0 commit comments

Comments
 (0)