~patrix-sbs/oraculum/git

« back to all changes in this revision

Viewing changes to library/components/doctrine/lib/Doctrine/Parser/YamlSf/Inline.php

  • Committer: Patrick Kaminski
  • Date: 2009-09-02 02:33:07 UTC
  • Revision ID: git-v1:943803254fca67bfb4c0374422b1b836b14dc518
Tags: v0.1a
Sending Oraculum Framework v0.1 alpha

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<?php
 
2
 
 
3
/*
 
4
 * This file is part of the symfony package.
 
5
 * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
 
6
 *
 
7
 * For the full copyright and license information, please view the LICENSE
 
8
 * file that was distributed with this source code.
 
9
 */
 
10
 
 
11
/**
 
12
 * YamlSfInline implements a YAML parser/dumper for the YAML inline syntax.
 
13
 *
 
14
 * @package    symfony
 
15
 * @subpackage util
 
16
 * @author     Fabien Potencier <fabien.potencier@symfony-project.com>
 
17
 * @version    SVN: $Id: YamlSfInline.class.php 9186 2008-05-22 15:19:18Z FabianLange $
 
18
 */
 
19
class Doctrine_Parser_YamlSf_Inline
 
20
{
 
21
  /**
 
22
   * Load YAML into a PHP array.
 
23
   *
 
24
   * @param string YAML
 
25
   *
 
26
   * @return array PHP array
 
27
   */
 
28
  static public function load($value)
 
29
  {
 
30
    $value = trim($value);
 
31
 
 
32
    if (0 == strlen($value))
 
33
    {
 
34
      return '';
 
35
    }
 
36
 
 
37
    switch ($value[0])
 
38
    {
 
39
      case '[':
 
40
        return self::parseSequence($value);
 
41
      case '{':
 
42
        return self::parseMapping($value);
 
43
      default:
 
44
        return self::parseScalar($value);
 
45
    }
 
46
  }
 
47
 
 
48
  /**
 
49
   * Dumps PHP array to YAML.
 
50
   *
 
51
   * @param mixed   PHP
 
52
   *
 
53
   * @return string YAML
 
54
   */
 
55
  static public function dump($value)
 
56
  {
 
57
    switch (true)
 
58
    {
 
59
      case is_resource($value):
 
60
        throw new InvalidArgumentException('Unable to dump PHP resources in a YAML file.');
 
61
      case is_object($value):
 
62
        return '!!php/object:'.serialize($value);
 
63
      case is_array($value):
 
64
        return self::dumpArray($value);
 
65
      case is_null($value):
 
66
        return 'null';
 
67
      case true === $value:
 
68
        return 'true';
 
69
      case false === $value:
 
70
        return 'false';
 
71
      case ctype_digit($value):
 
72
        return is_string($value) ? "'$value'" : (int) $value;
 
73
      case is_numeric($value):
 
74
        return is_infinite($value) ? str_ireplace('INF', '.Inf', strval($value)) : (is_string($value) ? "'$value'" : $value);
 
75
      case false !== strpos($value, "\n"):
 
76
        return sprintf('"%s"', str_replace(array('"', "\n", "\r"), array('\\"', '\n', ''), $value));
 
77
      case preg_match('/[ \s \' " \: \{ \} \[ \] , & \*]/x', $value):
 
78
        return sprintf("'%s'", str_replace('\'', '\'\'', $value));
 
79
      case '' == $value:
 
80
        return "''";
 
81
      case preg_match(self::getTimestampRegex(), $value):
 
82
        return "'$value'";
 
83
      case in_array(strtolower($value), array('true', 'on', '+', 'yes', 'y')):
 
84
        return "'$value'";
 
85
      case in_array(strtolower($value), array('false', 'off', '-', 'no', 'n')):
 
86
        return "'$value'";
 
87
      default:
 
88
        return $value;
 
89
    }
 
90
  }
 
91
 
 
92
  /**
 
93
   * Dumps PHP array to YAML
 
94
   *
 
95
   * @param array   The array to dump
 
96
   *
 
97
   * @return string YAML
 
98
   */
 
99
  static protected function dumpArray($value)
 
100
  {
 
101
    // array
 
102
    $keys = array_keys($value);
 
103
    if (
 
104
      (1 == count($keys) && '0' == $keys[0])
 
105
      ||
 
106
      (count($keys) > 1 && array_reduce($keys, create_function('$v,$w', 'return (integer) $v + $w;'), 0) == count($keys) * (count($keys) - 1) / 2))
 
107
    {
 
108
      $output = array();
 
109
      foreach ($value as $val)
 
110
      {
 
111
        $output[] = self::dump($val);
 
112
      }
 
113
 
 
114
      return sprintf('[%s]', implode(', ', $output));
 
115
    }
 
116
 
 
117
    // mapping
 
118
    $output = array();
 
119
    foreach ($value as $key => $val)
 
120
    {
 
121
      $output[] = sprintf('%s: %s', self::dump($key), self::dump($val));
 
122
    }
 
123
 
 
124
    return sprintf('{ %s }', implode(', ', $output));
 
125
  }
 
126
 
 
127
  /**
 
128
   * Parses scalar to yaml
 
129
   *
 
130
   * @param scalar $scalar
 
131
   * @param string $delimiters
 
132
   * @param array  String delimiter
 
133
   * @param integer $i
 
134
   * @param boolean $evaluate
 
135
   *
 
136
   * @return string YAML
 
137
   */
 
138
  static public function parseScalar($scalar, $delimiters = null, $stringDelimiters = array('"', "'"), &$i = 0, $evaluate = true)
 
139
  {
 
140
    if (in_array($scalar[$i], $stringDelimiters))
 
141
    {
 
142
      // quoted scalar
 
143
      $output = self::parseQuotedScalar($scalar, $i);
 
144
 
 
145
      // skip next delimiter
 
146
      ++$i;
 
147
    }
 
148
    else
 
149
    {
 
150
      // "normal" string
 
151
      if (!$delimiters)
 
152
      {
 
153
        $output = substr($scalar, $i);
 
154
        $i += strlen($output);
 
155
 
 
156
        // remove comments
 
157
        if (false !== $strpos = strpos($output, ' #'))
 
158
        {
 
159
          $output = rtrim(substr($output, 0, $strpos));
 
160
        }
 
161
      }
 
162
      else if (preg_match('/^(.+?)('.implode('|', $delimiters).')/', substr($scalar, $i), $match))
 
163
      {
 
164
        $output = $match[1];
 
165
        $i += strlen($output);
 
166
      }
 
167
      else
 
168
      {
 
169
        throw new InvalidArgumentException(sprintf('Malformed inline YAML string (%s).', $scalar));
 
170
      }
 
171
 
 
172
      $output = $evaluate ? self::evaluateScalar($output) : $output;
 
173
    }
 
174
 
 
175
    return $output;
 
176
  }
 
177
 
 
178
  /**
 
179
   * Parses quotes scalar
 
180
   *
 
181
   * @param string $scalar
 
182
   * @param integer $i
 
183
   *
 
184
   * @return string YAML
 
185
   */
 
186
  static protected function parseQuotedScalar($scalar, &$i)
 
187
  {
 
188
    $delimiter = $scalar[$i];
 
189
    ++$i;
 
190
    $buffer = '';
 
191
    $len = strlen($scalar);
 
192
    $escaped = '"' == $delimiter ? '\\"' : "''";
 
193
 
 
194
    while ($i < $len)
 
195
    {
 
196
      if (isset($scalar[$i + 1]) && $escaped == $scalar[$i].$scalar[$i + 1])
 
197
      {
 
198
        $buffer .= $delimiter;
 
199
        ++$i;
 
200
      }
 
201
      else if ($delimiter == $scalar[$i])
 
202
      {
 
203
        break;
 
204
      }
 
205
      else
 
206
      {
 
207
        $buffer .= $scalar[$i];
 
208
      }
 
209
 
 
210
      ++$i;
 
211
    }
 
212
 
 
213
    if ('"' == $delimiter)
 
214
    {
 
215
      // evaluate the string
 
216
      $buffer = str_replace('\\n', "\n", $buffer);
 
217
    }
 
218
 
 
219
    return $buffer;
 
220
  }
 
221
 
 
222
  /**
 
223
   * Parse sequence to yaml
 
224
   *
 
225
   * @param string $sequence
 
226
   * @param integer $i
 
227
   *
 
228
   * @return string YAML
 
229
   */
 
230
  static protected function parseSequence($sequence, &$i = 0)
 
231
  {
 
232
    $output = array();
 
233
    $len = strlen($sequence);
 
234
    $i += 1;
 
235
 
 
236
    // [foo, bar, ...]
 
237
    while ($i < $len)
 
238
    {
 
239
      switch ($sequence[$i])
 
240
      {
 
241
        case '[':
 
242
          // nested sequence
 
243
          $output[] = self::parseSequence($sequence, $i);
 
244
          break;
 
245
        case '{':
 
246
          // nested mapping
 
247
          $output[] = self::parseMapping($sequence, $i);
 
248
          break;
 
249
        case ']':
 
250
          return $output;
 
251
        case ',':
 
252
        case ' ':
 
253
          break;
 
254
        default:
 
255
          $isQuoted = in_array($sequence[$i], array('"', "'"));
 
256
          $value = self::parseScalar($sequence, array(',', ']'), array('"', "'"), $i);
 
257
 
 
258
          if (!$isQuoted && false !== strpos($value, ': '))
 
259
          {
 
260
            // embedded mapping?
 
261
            try
 
262
            {
 
263
              $value = self::parseMapping('{'.$value.'}');
 
264
            }
 
265
            catch (InvalidArgumentException $e)
 
266
            {
 
267
              // no, it's not
 
268
            }
 
269
          }
 
270
 
 
271
          $output[] = $value;
 
272
 
 
273
          --$i;
 
274
      }
 
275
 
 
276
      ++$i;
 
277
    }
 
278
 
 
279
    throw new InvalidArgumentException(sprintf('Malformed inline YAML string %s', $sequence));
 
280
  }
 
281
 
 
282
  /**
 
283
   * Parses mapping.
 
284
   *
 
285
   * @param string $mapping
 
286
   * @param integer $i
 
287
   *
 
288
   * @return string YAML
 
289
   */
 
290
  static protected function parseMapping($mapping, &$i = 0)
 
291
  {
 
292
    $output = array();
 
293
    $len = strlen($mapping);
 
294
    $i += 1;
 
295
 
 
296
    // {foo: bar, bar:foo, ...}
 
297
    while ($i < $len)
 
298
    {
 
299
      switch ($mapping[$i])
 
300
      {
 
301
        case ' ':
 
302
        case ',':
 
303
          ++$i;
 
304
          continue 2;
 
305
        case '}':
 
306
          return $output;
 
307
      }
 
308
 
 
309
      // key
 
310
      $key = self::parseScalar($mapping, array(':', ' '), array('"', "'"), $i, false);
 
311
 
 
312
      // value
 
313
      $done = false;
 
314
      while ($i < $len)
 
315
      {
 
316
        switch ($mapping[$i])
 
317
        {
 
318
          case '[':
 
319
            // nested sequence
 
320
            $output[$key] = self::parseSequence($mapping, $i);
 
321
            $done = true;
 
322
            break;
 
323
          case '{':
 
324
            // nested mapping
 
325
            $output[$key] = self::parseMapping($mapping, $i);
 
326
            $done = true;
 
327
            break;
 
328
          case ':':
 
329
          case ' ':
 
330
            break;
 
331
          default:
 
332
            $output[$key] = self::parseScalar($mapping, array(',', '}'), array('"', "'"), $i);
 
333
            $done = true;
 
334
            --$i;
 
335
        }
 
336
 
 
337
        ++$i;
 
338
 
 
339
        if ($done)
 
340
        {
 
341
          continue 2;
 
342
        }
 
343
      }
 
344
    }
 
345
 
 
346
    throw new InvalidArgumentException(sprintf('Malformed inline YAML string %s', $mapping));
 
347
  }
 
348
 
 
349
  /**
 
350
   * Evaluates scalars and replaces magic values.
 
351
   *
 
352
   * @param string $scalar
 
353
   *
 
354
   * @return string YAML
 
355
   */
 
356
  static protected function evaluateScalar($scalar)
 
357
  {
 
358
    $scalar = trim($scalar);
 
359
 
 
360
    switch (true)
 
361
    {
 
362
      case 'null' == strtolower($scalar):
 
363
      case '' == $scalar:
 
364
      case '~' == $scalar:
 
365
        return null;
 
366
      case 0 === strpos($scalar, '!str'):
 
367
        return (string) substr($scalar, 5);
 
368
      case 0 === strpos($scalar, '! '):
 
369
        return intval(self::parseScalar(substr($scalar, 2)));
 
370
      case 0 === strpos($scalar, '!!php/object:'):
 
371
        return unserialize(substr($scalar, 13));
 
372
      case ctype_digit($scalar):
 
373
        $raw = $scalar;
 
374
        $cast = intval($scalar);
 
375
 
 
376
        return '0' == $scalar[0]
 
377
          ? octdec($scalar) : (((string) $raw == (string) $cast) ? strval($cast) : $raw);
 
378
      case in_array(strtolower($scalar), array('true', 'on', '+', 'yes', 'y')):
 
379
        return true;
 
380
      case in_array(strtolower($scalar), array('false', 'off', '-', 'no', 'n')):
 
381
        return false;
 
382
      case is_numeric($scalar):
 
383
        return '0x' == $scalar[0].$scalar[1] ? hexdec($scalar) : floatval($scalar);
 
384
      case 0 == strcasecmp($scalar, '.inf'):
 
385
      case 0 == strcasecmp($scalar, '.NaN'):
 
386
        return -log(0);
 
387
      case 0 == strcasecmp($scalar, '-.inf'):
 
388
        return log(0);
 
389
      case preg_match('/^(-|\+)?[0-9,]+(\.[0-9]+)?$/', $scalar):
 
390
        return floatval(str_replace(',', '', $scalar));
 
391
      case preg_match(self::getTimestampRegex(), $scalar):
 
392
        return strtotime($scalar);
 
393
      default:
 
394
        return (string) $scalar;
 
395
    }
 
396
  }
 
397
 
 
398
  static protected function getTimestampRegex()
 
399
  {
 
400
    return <<<EOF
 
401
    ~^
 
402
    (?P<year>[0-9][0-9][0-9][0-9])
 
403
    -(?P<month>[0-9][0-9]?)
 
404
    -(?P<day>[0-9][0-9]?)
 
405
    (?:(?:[Tt]|[ \t]+)
 
406
    (?P<hour>[0-9][0-9]?)
 
407
    :(?P<minute>[0-9][0-9])
 
408
    :(?P<second>[0-9][0-9])
 
409
    (?:\.(?P<fraction>[0-9]*))?
 
410
    (?:[ \t]*(?P<tz>Z|(?P<tz_sign>[-+])(?P<tz_hour>[0-9][0-9]?)
 
411
    (?::(?P<tz_minute>[0-9][0-9]))?))?)?
 
412
    $~x
 
413
EOF;
 
414
  }
 
415
}
 
 
b'\\ No newline at end of file'