Passed
Branch master (7315b7)
by Scott
02:53
created

Evaluator::getNamespaceValue()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 15
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 15
ccs 11
cts 11
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 12
nc 2
nop 1
crap 2
1
<?php
2
namespace Desmond;
3
use Desmond\functions\EnvLoader;
4
use Desmond\data_types\ListType;
5
use Desmond\data_types\VectorType;
6
use Desmond\data_types\HashType;
7
use Desmond\data_types\SymbolType;
8
use Desmond\data_types\LambdaType;
9
use Desmond\DesmondNamespace as NS;
10
use Exception;
11
12
class Evaluator
13
{
14
    private $coreEnv;
15
    public $currentEnv;
16
17 284
    public function __construct()
18
    {
19 284
        $this->coreEnv = new Environment();
20 284
        NS::setRoot($this->coreEnv);
21 284
        $this->currentEnv = $this->coreEnv;
22 284
        EnvLoader::loadInto($this->coreEnv, 'core');
23 284
    }
24
25 282
    public function getReturn($ast)
26
    {
27 282
        if ($ast instanceof ListType) {
28 278
            return $this->evalForm($ast);
29 282
        } else if ($ast instanceof VectorType || $ast instanceof HashType) {
30 48
            return $this->evalCollection($ast);
31
        } else {
32 282
            return $this->evalAtom($ast);
33
        }
34
    }
35
36 278
    private function evalForm($form)
37
    {
38 278
        if ($form->get(0) instanceof ListType || $this->getReturn($form->get(0)) instanceof LambdaType) {
39 5
            $function = $this->getReturn($form->get(0));
40
        } else {
41 278
            $function = $form->getFunction()->value();
42
        }
43 278
        return $this->doSpecialForm($function, $form->getArgs());
44
    }
45
46 48
    public function evalCollection($ast)
47
    {
48 48
        $collection = $ast;
49 48
        foreach ($collection->value() as $key => $value) {
50 30
            $collection->set($this->getReturn($value), $key);
51
        }
52 48
        return $collection;
53
    }
54
55 278
    private function doSpecialForm($function, $args)
56
    {
57 278
        $possibilities = $this->specialFunctionList($function);
58 278
        $functionName = null;
59 278
        foreach ($possibilities as $possibility) {
60 278
            if ($possibility[0]) {
61 79
                $functionName = $possibility[1];
62 278
                break;
63
            }
64
        }
65 278
        $functionName = $functionName ? $functionName : 'EnvironmentFunction';
66 278
        $class = "Desmond\\functions\\special\\{$functionName}";
67 278
        $object = new $class();
68 278
        $object->function = $function;
69 278
        $object->currentEnv = &$this->currentEnv;
70 278
        $object->eval = $this;
71 278
        return $object->run($args);
72
    }
73
74 278
    private function specialFunctionList($function)
75
    {
76
        return [
77 278
            [$function == 'quote', 'Quote'],
78 278
            [$function == 'quasiquote', 'Quasiquote'],
79 278
            [$function == 'namespace', 'NamespaceBlock'],
80 278
            [$function == 'define', 'DefineSymbol'],
81 278
            [$function == 'let', 'Let'],
82 278
            [$function == 'do', 'DoBlock'],
83 278
            [$function == 'if', 'Conditional'],
84 278
            [$function == 'lambda', 'CreateLambda'],
85 278
            [($function instanceof LambdaType), 'RunLambda'],
86 278
            [$function == 'load-file', 'LoadFile'],
87 278
            [$function == 'eval', 'EvalBlock'],
88 278
            [$function == 'try', 'TryCatch']
89
        ];
90
    }
91
92 282
    private function evalAtom($atom)
93
    {
94 282
        if (!($atom instanceof SymbolType)) {
95 167
            return $atom;
96
        }
97
        try {
98 279
            if (false !== strpos($atom->value(), '/')) {
99 8
                $value = $this->getNamespaceValue($atom);
100
            } else {
101 274
                $value = $this->currentEnv->get($atom->value());
102
            }
103 244
            return $value;
104 108
        } catch (Exception $exeption) {
105 108
            return $atom;
106
        }
107
    }
108
109 8
    private function getNamespaceValue($atom)
110
    {
111 8
        $fullName = preg_replace('/^\//', '', $atom->value());
112 8
        $pieces = explode('/', $fullName);
113 8
        $symbol = end($pieces);
114 8
        array_pop($pieces);
115 8
        $namespace = implode('/', $pieces);
116 8
        if (NS::exists($namespace)) {
117 2
            $env = NS::get($namespace);
118 2
            $value = $env->get($symbol);
119
        } else {
120 6
            $value = $atom;
121
        }
122 8
        return $value;
123
    }
124
}
125