Commit | Line | Data |
---|---|---|
31690700 JM |
1 | <?php |
2 | ||
31690700 | 3 | |
ea81a808 JM |
4 | // Errors/Exceptions |
5 | class Error extends Exception { | |
6 | public $obj = null; | |
7 | public function __construct($obj) { | |
8 | parent::__construct("Mal Error", 0, null); | |
9 | $this->obj = $obj; | |
10 | } | |
31690700 JM |
11 | } |
12 | ||
31690700 | 13 | |
ea81a808 | 14 | // General functions |
31690700 | 15 | |
ea81a808 | 16 | function _equal_Q($a, $b) { |
31690700 JM |
17 | $ota = gettype($a) === "object" ? get_class($a) : gettype($a); |
18 | $otb = gettype($b) === "object" ? get_class($b) : gettype($b); | |
ea81a808 | 19 | if (!($ota === $otb or (_sequential_Q($a) and _sequential_Q($b)))) { |
31690700 | 20 | return false; |
ea81a808 | 21 | } elseif (_symbol_Q($a)) { |
31690700 JM |
22 | #print "ota: $ota, otb: $otb\n"; |
23 | return $a->value === $b->value; | |
ea81a808 | 24 | } elseif (_list_Q($a) or _vector_Q($a)) { |
31690700 JM |
25 | if ($a->count() !== $b->count()) { return false; } |
26 | for ($i=0; $i<$a->count(); $i++) { | |
ea81a808 | 27 | if (!_equal_Q($a[$i], $b[$i])) { return false; } |
31690700 JM |
28 | } |
29 | return true; | |
30 | } else { | |
31 | return $a === $b; | |
32 | } | |
33 | } | |
34 | ||
ea81a808 | 35 | function _sequential_Q($seq) { return _list_Q($seq) or _vector_Q($seq); } |
31690700 JM |
36 | |
37 | ||
ea81a808 JM |
38 | // Scalars |
39 | function _nil_Q($obj) { return $obj === NULL; } | |
40 | function _true_Q($obj) { return $obj === true; } | |
41 | function _false_Q($obj) { return $obj === false; } | |
42 | function _string_Q($obj) { return is_string($obj); } | |
43 | ||
44 | ||
45 | // Symbols | |
31690700 JM |
46 | class SymbolClass { |
47 | public $value = NULL; | |
48 | public $meta = NULL; | |
49 | public function __construct($value) { | |
50 | $this->value = $value; | |
51 | } | |
52 | } | |
ea81a808 JM |
53 | function _symbol($name) { return new SymbolClass($name); } |
54 | function _symbol_Q($obj) { return ($obj instanceof SymbolClass); } | |
31690700 | 55 | |
b8ee29b2 JM |
56 | // Keywords |
57 | function _keyword($name) { return chr(0x7f).$name; } | |
58 | function _keyword_Q($obj) { | |
59 | return is_string($obj) && strpos($obj, chr(0x7f)) === 0; | |
60 | } | |
61 | ||
62 | ||
31690700 JM |
63 | |
64 | // Functions | |
65 | class FunctionClass { | |
66 | public $func = NULL; | |
67 | public $type = 'native'; // 'native' or 'platform' | |
68 | public $meta = NULL; | |
a34b0200 JM |
69 | public $ast = NULL; |
70 | public $env = NULL; | |
71 | public $params = NULL; | |
31690700 | 72 | public $ismacro = False; |
a34b0200 JM |
73 | public function __construct($func, $type, |
74 | $ast, $env, $params, $ismacro=False) { | |
31690700 JM |
75 | $this->func = $func; |
76 | $this->type = $type; | |
a34b0200 JM |
77 | $this->ast = $ast; |
78 | #print_r($ast); | |
79 | $this->env = $env; | |
80 | $this->params = $params; | |
31690700 JM |
81 | $this->ismacro = $ismacro; |
82 | } | |
83 | public function __invoke() { | |
84 | $args = func_get_args(); | |
85 | if ($this->type === 'native') { | |
a34b0200 JM |
86 | $fn_env = new Env($this->env, |
87 | $this->params, $args); | |
31690700 | 88 | $evalf = $this->func; |
a34b0200 | 89 | return $evalf($this->ast, $fn_env); |
31690700 JM |
90 | } else { |
91 | return call_user_func_array($this->func, $args); | |
92 | } | |
93 | } | |
a34b0200 JM |
94 | public function gen_env($args) { |
95 | return new Env($this->env, $this->params, $args); | |
96 | } | |
31690700 JM |
97 | public function apply($args) { |
98 | return call_user_func_array(array(&$this, '__invoke'),$args); | |
99 | } | |
100 | } | |
101 | ||
a34b0200 JM |
102 | function _function($func, $type='platform', |
103 | $ast=NULL, $env=NULL, $params=NULL, $ismacro=False) { | |
104 | return new FunctionClass($func, $type, $ast, $env, $params, $ismacro); | |
31690700 | 105 | } |
ea81a808 | 106 | function _function_Q($obj) { return $obj instanceof FunctionClass; } |
31690700 | 107 | |
31690700 JM |
108 | |
109 | // Parent class of list, vector, hash-map | |
110 | // http://www.php.net/manual/en/class.arrayobject.php | |
111 | class SeqClass extends ArrayObject { | |
112 | public function slice($start, $length=NULL) { | |
113 | $sc = new $this(); | |
114 | if ($start >= count($this)) { | |
115 | $arr = array(); | |
116 | } else { | |
117 | $arr = array_slice($this->getArrayCopy(), $start, $length); | |
118 | } | |
119 | $sc->exchangeArray($arr); | |
120 | return $sc; | |
121 | } | |
122 | } | |
123 | ||
124 | ||
ea81a808 JM |
125 | // Lists |
126 | class ListClass extends SeqClass { | |
127 | public $meta = NULL; | |
128 | } | |
129 | ||
130 | function _list() { | |
131 | $v = new ListClass(); | |
132 | $v->exchangeArray(func_get_args()); | |
133 | return $v; | |
134 | } | |
135 | function _list_Q($obj) { return $obj instanceof ListClass; } | |
136 | ||
137 | ||
138 | // Vectors | |
139 | class VectorClass extends SeqClass { | |
140 | public $meta = NULL; | |
141 | } | |
142 | ||
143 | function _vector() { | |
144 | $v = new VectorClass(); | |
145 | $v->exchangeArray(func_get_args()); | |
146 | return $v; | |
147 | } | |
148 | function _vector_Q($obj) { return $obj instanceof VectorClass; } | |
149 | ||
150 | ||
31690700 JM |
151 | // Hash Maps |
152 | class HashMapClass extends ArrayObject { | |
153 | public $meta = NULL; | |
154 | } | |
155 | ||
ea81a808 | 156 | function _hash_map() { |
31690700 JM |
157 | $args = func_get_args(); |
158 | if (count($args) % 2 === 1) { | |
159 | throw new Exception("Odd number of hash map arguments"); | |
160 | } | |
161 | $hm = new HashMapClass(); | |
162 | array_unshift($args, $hm); | |
ea81a808 | 163 | return call_user_func_array('_assoc_BANG', $args); |
31690700 | 164 | } |
ea81a808 | 165 | function _hash_map_Q($obj) { return $obj instanceof HashMapClass; } |
31690700 | 166 | |
ea81a808 | 167 | function _assoc_BANG($hm) { |
31690700 JM |
168 | $args = func_get_args(); |
169 | if (count($args) % 2 !== 1) { | |
170 | throw new Exception("Odd number of assoc arguments"); | |
171 | } | |
172 | for ($i=1; $i<count($args); $i+=2) { | |
173 | $ktoken = $args[$i]; | |
174 | $vtoken = $args[$i+1]; | |
175 | // TODO: support more than string keys | |
176 | if (gettype($ktoken) !== "string") { | |
177 | throw new Exception("expected hash-map key string, got: " . gettype($ktoken)); | |
178 | } | |
179 | $hm[$ktoken] = $vtoken; | |
180 | } | |
181 | return $hm; | |
182 | } | |
183 | ||
ea81a808 | 184 | function _dissoc_BANG($hm) { |
31690700 JM |
185 | $args = func_get_args(); |
186 | for ($i=1; $i<count($args); $i++) { | |
187 | $ktoken = $args[$i]; | |
b079f510 JM |
188 | if ($hm && $hm->offsetExists($ktoken)) { |
189 | unset($hm[$ktoken]); | |
190 | } | |
31690700 JM |
191 | } |
192 | return $hm; | |
193 | } | |
194 | ||
31690700 JM |
195 | |
196 | // Atoms | |
31690700 JM |
197 | class Atom { |
198 | public $value = NULL; | |
199 | public $meta = NULL; | |
200 | public function __construct($value) { | |
201 | $this->value = $value; | |
202 | } | |
203 | } | |
ea81a808 JM |
204 | function _atom($val) { return new Atom($val); } |
205 | function _atom_Q($atm) { return $atm instanceof Atom; } | |
31690700 JM |
206 | |
207 | ?> |