Runtime   A
last analyzed

Complexity

Total Complexity 17

Size/Duplication

Total Lines 115
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 30
dl 0
loc 115
rs 10
c 0
b 0
f 0
wmc 17

12 Methods

Rating   Name   Duplication   Size   Complexity  
A shiftCommandIndex() 0 3 1
A setDataIndex() 0 6 2
A addCommand() 0 4 1
A __construct() 0 7 2
A inputData() 0 3 1
A getOutput() 0 3 1
A outputData() 0 3 1
A setCommandIndex() 0 6 3
A shiftDataIndex() 0 3 1
A exec() 0 4 2
A shiftDataValue() 0 3 1
A isValueZero() 0 3 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Remorhaz\UniLex\Example\Brainfuck;
6
7
use Remorhaz\UniLex\Example\Brainfuck\Command\AbstractCommand;
8
9
class Runtime
10
{
11
    private const DEFAULT_MEMORY = 30000;
12
13
    private $memory;
14
15
    private $dataList;
16
17
    private $dataIndex = 0;
18
19
    private $commandIndex = 0;
20
21
    private $output = '';
22
23
    /**
24
     * @var AbstractCommand[]
25
     */
26
    private $commandList = [];
27
28
    private $nextCommandIndex = 0;
29
30
    /**
31
     * Runtime constructor.
32
     * @param int $memory
33
     * @throws Exception
34
     */
35
    public function __construct(int $memory = self::DEFAULT_MEMORY)
36
    {
37
        if (0 >= $memory) {
38
            throw new Exception("Memory amount must be positive");
39
        }
40
        $this->memory = $memory;
41
        $this->dataList = array_fill(0, $this->memory, 0);
42
    }
43
44
    public function getOutput(): string
45
    {
46
        return $this->output;
47
    }
48
49
    public function addCommand(AbstractCommand $command): void
50
    {
51
        $this->commandList[$this->nextCommandIndex] = $command;
52
        $command->setIndex($this->nextCommandIndex++);
53
    }
54
55
    /**
56
     * @param int $index
57
     * @throws Exception
58
     */
59
    public function shiftDataIndex(int $index): void
60
    {
61
        $this->setDataIndex($this->dataIndex + $index);
62
    }
63
64
    /**
65
     * @param int $index
66
     * @throws Exception
67
     */
68
    private function setDataIndex(int $index): void
69
    {
70
        if (!isset($this->dataList[$index])) {
71
            throw new Exception("Failed to move data pointer to position {$index}");
72
        }
73
        $this->dataIndex = $index;
74
    }
75
76
    public function shiftDataValue(int $value): void
77
    {
78
        $this->dataList[$this->dataIndex] += $value;
79
    }
80
81
    /**
82
     * @param int $index
83
     * @throws Exception
84
     */
85
    public function setCommandIndex(int $index): void
86
    {
87
        if (!isset($this->commandList[$index]) && $index != $this->nextCommandIndex) {
88
            throw new Exception("Failed to move command pointer to position {$index}");
89
        }
90
        $this->commandIndex = $index;
91
    }
92
93
    /**
94
     * @param int $index
95
     * @throws Exception
96
     */
97
    public function shiftCommandIndex(int $index): void
98
    {
99
        $this->setCommandIndex($this->commandIndex + $index);
100
    }
101
102
    public function isValueZero(): bool
103
    {
104
        return 0 == $this->dataList[$this->dataIndex];
105
    }
106
107
    public function outputData(): void
108
    {
109
        $this->output .= chr($this->dataList[$this->dataIndex]);
110
    }
111
112
    /**
113
     * @throws Exception
114
     */
115
    public function inputData(): void
116
    {
117
        throw new Exception("Data input is not implemented yet");
118
    }
119
120
    public function exec(): void
121
    {
122
        while ($this->commandIndex < $this->nextCommandIndex) {
123
            $this->commandList[$this->commandIndex]->exec();
124
        }
125
    }
126
}
127