Skip to content

Commit 11b631d

Browse files
committed
Add ability to evaluate dictionaries
1 parent 2136e64 commit 11b631d

File tree

3 files changed

+153
-5
lines changed

3 files changed

+153
-5
lines changed

evaluator/evaluator.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ func Eval(node ast.Node, env *object.Environment) object.Object {
103103
return index
104104
}
105105
return evalIndexExpression(left, index)
106+
case *ast.DictLiteral:
107+
return evalDictLiteral(node, env)
106108

107109
}
108110

@@ -351,6 +353,8 @@ func evalIndexExpression(left, index object.Object) object.Object {
351353
switch {
352354
case left.Type() == object.ARRAY_OBJ && index.Type() == object.INTEGER_OBJ:
353355
return evalArrayIndexExpression(left, index)
356+
case left.Type() == object.DICT_OBJ:
357+
return evalDictIndexExpression(left, index)
354358
default:
355359
return newError("Operesheni hii haiwezekani kwa: %s", left.Type())
356360
}
@@ -367,3 +371,45 @@ func evalArrayIndexExpression(array, index object.Object) object.Object {
367371

368372
return arrayObject.Elements[idx]
369373
}
374+
375+
func evalDictLiteral(node *ast.DictLiteral, env *object.Environment) object.Object {
376+
pairs := make(map[object.HashKey]object.DictPair)
377+
378+
for keyNode, valueNode := range node.Pairs {
379+
key := Eval(keyNode, env)
380+
if isError(key) {
381+
return key
382+
}
383+
384+
hashKey, ok := key.(object.Hashable)
385+
if !ok {
386+
return newError("Hashing imeshindikana: %s", key.Type())
387+
}
388+
389+
value := Eval(valueNode, env)
390+
if isError(value) {
391+
return value
392+
}
393+
394+
hashed := hashKey.HashKey()
395+
pairs[hashed] = object.DictPair{Key: key, Value: value}
396+
}
397+
398+
return &object.Dict{Pairs: pairs}
399+
}
400+
401+
func evalDictIndexExpression(dict, index object.Object) object.Object {
402+
dictObject := dict.(*object.Dict)
403+
404+
key, ok := index.(object.Hashable)
405+
if !ok {
406+
return newError("Samahani, %s haitumiki kama key", index.Type())
407+
}
408+
409+
pair, ok := dictObject.Pairs[key.HashKey()]
410+
if !ok {
411+
return NULL
412+
}
413+
414+
return pair.Value
415+
}

evaluator/evaluator_test.go

Lines changed: 95 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,10 @@ kama (10 > 1) {
216216
`"Habari" - "Habari"`,
217217
"Operesheni Haielweki: NENO - NENO",
218218
},
219+
{
220+
`{"jina": "Avi"}[fn(x) {x}];`,
221+
"Samahani, FUNCTION haitumiki kama key",
222+
},
219223
}
220224

221225
for _, tt := range tests {
@@ -337,11 +341,11 @@ func TestBuiltinFunctions(t *testing.T) {
337341
input string
338342
expected interface{}
339343
}{
340-
{`len("")`, 0},
341-
{`len("four")`, 4},
342-
{`len("hello world")`, 11},
343-
{`len(1)`, "Samahani, hii function haitumiki na NAMBARI"},
344-
{`len("one", "two")`, "Hoja hazilingani, tunahitaji=1, tumepewa=2"},
344+
{`idadi("")`, 0},
345+
{`idadi("four")`, 4},
346+
{`idadi("hello world")`, 11},
347+
{`idadi(1)`, "Samahani, hii function haitumiki na NAMBARI"},
348+
{`idadi("one", "two")`, "Hoja hazilingani, tunahitaji=1, tumepewa=2"},
345349
}
346350

347351
for _, tt := range tests {
@@ -426,3 +430,89 @@ func TestArrayIndexExpressions(t *testing.T) {
426430
}
427431
}
428432
}
433+
434+
func TestDictLiterals(t *testing.T) {
435+
input := `acha two = "two";
436+
{
437+
"one": 10 - 9,
438+
two: 1 +1,
439+
"thr" + "ee": 6 / 2,
440+
4: 4,
441+
kweli: 5,
442+
sikweli: 6
443+
}`
444+
445+
evaluated := testEval(input)
446+
result, ok := evaluated.(*object.Dict)
447+
if !ok {
448+
t.Fatalf("Eval didn't return a dict, got=%T(%+v)", evaluated, evaluated)
449+
}
450+
451+
expected := map[object.HashKey]int64{
452+
(&object.String{Value: "one"}).HashKey(): 1,
453+
(&object.String{Value: "two"}).HashKey(): 2,
454+
(&object.String{Value: "three"}).HashKey(): 3,
455+
(&object.Integer{Value: 4}).HashKey(): 4,
456+
TRUE.HashKey(): 5,
457+
FALSE.HashKey(): 6,
458+
}
459+
460+
if len(result.Pairs) != len(expected) {
461+
t.Fatalf("Dict has wrong number of pairs, got=%d", len(result.Pairs))
462+
}
463+
464+
for expectedKey, expectedValue := range expected {
465+
pair, ok := result.Pairs[expectedKey]
466+
if !ok {
467+
t.Errorf("No pair for give key")
468+
}
469+
470+
testIntegerObject(t, pair.Value, expectedValue)
471+
}
472+
}
473+
474+
func TestDictIndexExpression(t *testing.T) {
475+
tests := []struct {
476+
input string
477+
expected interface{}
478+
}{
479+
{
480+
`{"foo": 5}["foo"]`,
481+
5,
482+
},
483+
{
484+
`{"foo": 5}["bar"]`,
485+
nil,
486+
},
487+
{
488+
`acha key = "foo"; {"foo": 5}[key]`,
489+
5,
490+
},
491+
{
492+
`{}["foo"]`,
493+
nil,
494+
},
495+
{
496+
`{5: 5}[5]`,
497+
5,
498+
},
499+
{
500+
`{kweli: 5}[kweli]`,
501+
5,
502+
},
503+
{
504+
`{sikweli: 5}[sikweli]`,
505+
5,
506+
},
507+
}
508+
509+
for _, tt := range tests {
510+
evaluated := testEval(tt.input)
511+
integer, ok := tt.expected.(int)
512+
if ok {
513+
testIntegerObject(t, evaluated, int64(integer))
514+
} else {
515+
testNullObject(t, evaluated)
516+
}
517+
}
518+
}

examples/example.nr

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,15 @@ acha salamu = fn() {
7676
}
7777

7878
chapa(salamu());
79+
80+
/*
81+
Multiline comment
82+
*/
83+
84+
// test dictionaries
85+
86+
chapa("Testing dictionaries...")
87+
88+
acha watu = [{"jina": "Mojo", "kabila": "Mnyakusa"}, {"jina": "Avi", "kabila": "Mwarabu wa dubai"}]
89+
90+
chapa(watu, watu[0], watu[0]["jina"], watu[0]["kabila"])

0 commit comments

Comments
 (0)