1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Dallgoot\Yaml\Nodes; |
4
|
|
|
|
5
|
|
|
use Dallgoot\Yaml\NodeFactory; |
6
|
|
|
use Dallgoot\Yaml\TagFactory; |
7
|
|
|
use Dallgoot\Yaml\NodeList; |
8
|
|
|
use Dallgoot\Yaml\Regex; |
9
|
|
|
use Dallgoot\Yaml\Loader; |
10
|
|
|
|
11
|
|
|
/** |
12
|
|
|
* |
13
|
|
|
* @author Stéphane Rebai <[email protected]> |
14
|
|
|
* @license Apache 2.0 |
15
|
|
|
* @link https://github.com/dallgoot/yaml |
16
|
|
|
*/ |
17
|
|
|
class Scalar extends NodeGeneric |
18
|
|
|
{ |
19
|
7 |
|
public function __construct(string $nodeString, int $line) |
20
|
|
|
{ |
21
|
7 |
|
parent::__construct($nodeString, $line); |
22
|
7 |
|
$value = trim($nodeString); |
23
|
7 |
|
if ($value !== '') { |
24
|
7 |
|
$hasComment = strpos($value, ' #'); |
25
|
7 |
|
if (!is_bool($hasComment)) { |
26
|
1 |
|
$realValue = trim(substr($value, 0, $hasComment)); |
27
|
1 |
|
$commentValue = trim(substr($value, $hasComment)); |
28
|
1 |
|
$realNode = NodeFactory::get($realValue, $line); |
29
|
1 |
|
$realNode->indent = null; |
30
|
1 |
|
$commentNode = NodeFactory::get($commentValue, $line); |
31
|
1 |
|
$commentNode->indent = null; |
32
|
1 |
|
$this->add($realNode); |
33
|
1 |
|
$this->add($commentNode); |
34
|
|
|
} |
35
|
|
|
} |
36
|
7 |
|
} |
37
|
|
|
|
38
|
2 |
|
public function build(&$parent = null) |
39
|
|
|
{ |
40
|
2 |
|
if (!is_null($this->tag)) { |
41
|
1 |
|
$tagged = TagFactory::transform($this->tag, $this); |
42
|
1 |
|
if ($tagged instanceof NodeGeneric || $tagged instanceof NodeList) { |
43
|
|
|
return $tagged->build(); |
44
|
|
|
} |
45
|
1 |
|
return $tagged; |
46
|
|
|
} |
47
|
1 |
|
return is_null($this->value) ? $this->getScalar(trim($this->raw)) : $this->value->build(); |
48
|
|
|
} |
49
|
|
|
|
50
|
1 |
|
public function getTargetOnLessIndent(NodeGeneric &$node):NodeGeneric |
51
|
|
|
{ |
52
|
1 |
|
if ($node instanceof Scalar || $node instanceof Blank ) { |
53
|
1 |
|
return $this->getParent(); |
54
|
|
|
} else { |
55
|
1 |
|
return $this->getParent($node->indent); |
56
|
|
|
} |
57
|
|
|
} |
58
|
|
|
|
59
|
1 |
|
public function getTargetOnMoreIndent(NodeGeneric &$node):NodeGeneric |
60
|
|
|
{ |
61
|
1 |
|
return $this->getParent(); |
62
|
|
|
} |
63
|
|
|
|
64
|
|
|
|
65
|
|
|
|
66
|
|
|
/** |
67
|
|
|
* Returns the correct PHP type according to the string value |
68
|
|
|
* |
69
|
|
|
* @param string $v a string value |
70
|
|
|
* |
71
|
|
|
* @return mixed The value with appropriate PHP type |
72
|
|
|
* @throws \Exception if it happens in Regex::isDate or Regex::isNumber |
73
|
|
|
* @todo implement date as DateTime Object |
74
|
|
|
*/ |
75
|
2 |
|
public function getScalar(string $v, bool $onlyScalar = false) |
76
|
|
|
{ |
77
|
|
|
/* |
78
|
|
|
10.3.2. Tag Resolution |
79
|
|
|
|
80
|
|
|
The core schema tag resolution is an extension of the JSON schema tag resolution. |
81
|
|
|
|
82
|
|
|
All nodes with the “!” non-specific tag are resolved, by the standard convention, to “tag:yaml.org,2002:seq”, “tag:yaml.org,2002:map”, or “tag:yaml.org,2002:str”, according to their kind. |
83
|
|
|
|
84
|
|
|
Collections with the “?” non-specific tag (that is, untagged collections) are resolved to “tag:yaml.org,2002:seq” or “tag:yaml.org,2002:map” according to their kind. |
85
|
|
|
|
86
|
|
|
Scalars with the “?” non-specific tag (that is, plain scalars) are matched with an extended list of regular expressions. However, in this case, if none of the regular expressions matches, the scalar is resolved to tag:yaml.org,2002:str (that is, considered to be a string). |
87
|
|
|
Regular expression Resolved to tag |
88
|
|
|
null | Null | NULL | ~ tag:yaml.org,2002:null |
89
|
|
|
Empty tag:yaml.org,2002:null |
90
|
|
|
true | True | TRUE | false | False | FALSE tag:yaml.org,2002:bool |
91
|
|
|
[-+]? [0-9]+ tag:yaml.org,2002:int (Base 10) |
92
|
|
|
0o [0-7]+ tag:yaml.org,2002:int (Base 8) |
93
|
|
|
0x [0-9a-fA-F]+ tag:yaml.org,2002:int (Base 16) |
94
|
|
|
[-+]? ( \. [0-9]+ | [0-9]+ ( \. [0-9]* )? ) ( [eE] [-+]? [0-9]+ )? tag:yaml.org,2002:float (Number) |
95
|
|
|
[-+]? ( \.inf | \.Inf | \.INF ) tag:yaml.org,2002:float (Infinity) |
96
|
|
|
\.nan | \.NaN | \.NAN tag:yaml.org,2002:float (Not a number) |
97
|
|
|
* tag:yaml.org,2002:str (Default) |
98
|
|
|
*/ |
99
|
2 |
|
if (Regex::isDate($v)) return ($this->getRoot()->getYamlObject()->getOptions() & Loader::NO_OBJECT_FOR_DATE) && !$onlyScalar ? date_create($v) : $v; |
100
|
2 |
|
if (Regex::isNumber($v)) return $this->getNumber($v); |
101
|
2 |
|
$types = ['yes' => true, |
102
|
|
|
'no' => false, |
103
|
|
|
'true' => true, |
104
|
|
|
'false' => false, |
105
|
|
|
'null' => null, |
106
|
|
|
'.inf' => \INF, |
107
|
|
|
'-.inf' => -\INF, |
108
|
|
|
'.nan' => \NAN |
109
|
|
|
]; |
110
|
2 |
|
return array_key_exists(strtolower($v), $types) ? $types[strtolower($v)] : $this->replaceSequences($v); |
111
|
|
|
} |
112
|
|
|
|
113
|
1 |
|
public function replaceSequences($value='') |
114
|
|
|
{ |
115
|
|
|
$replaceUnicodeSeq = function ($matches) { |
116
|
|
|
return json_decode('"'.$matches[1].'"'); |
117
|
1 |
|
}; |
118
|
|
|
$replaceNonPrintable = function ($matches) { |
119
|
|
|
// var_dump($matches[1]); |
120
|
|
|
return $matches[1].""; |
121
|
1 |
|
}; |
122
|
|
|
// preg_match( "/[^\x{06F0}-\x{06F9}\x]+/u" , '۱۲۳۴۵۶۷۸۹۰' ); |
123
|
1 |
|
return preg_replace_callback_array( |
124
|
|
|
[ |
125
|
1 |
|
'/((?<![\\\\])\\\\x[0-9a-f]{2})/i' => $replaceUnicodeSeq, |
126
|
1 |
|
'/((?<![\\\\])\\\\u[0-9a-f]{4,})/i' => $replaceUnicodeSeq, |
127
|
1 |
|
'/(\\\\b|\\\\n|\\\\t|\\\\r)/' => $replaceNonPrintable |
128
|
|
|
], |
129
|
|
|
$value |
130
|
|
|
); |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
|
134
|
|
|
/** |
135
|
|
|
* Returns the correct PHP type according to the string value |
136
|
|
|
* |
137
|
|
|
* @param string $v a string value |
138
|
|
|
* |
139
|
|
|
* @return int|float The scalar value with appropriate PHP type |
140
|
|
|
* @todo or scientific notation matching the regular expression -? [1-9] ( \. [0-9]* [1-9] )? ( e [-+] [1-9] [0-9]* )? |
141
|
|
|
*/ |
142
|
2 |
|
private function getNumber(string $v) |
143
|
|
|
{ |
144
|
2 |
|
if ((bool) preg_match(Regex::OCTAL_NUM, $v)) return intval(base_convert($v, 8, 10)); |
145
|
2 |
|
if ((bool) preg_match(Regex::HEX_NUM, $v)) return intval(base_convert($v, 16, 10)); |
146
|
2 |
|
return is_bool(strpos($v, '.')) || substr_count($v, '.') > 1 ? intval($v) : floatval($v); |
147
|
|
|
} |
148
|
|
|
|
149
|
|
|
} |