Alpha of new version

This commit is contained in:
Alexander Kiryukhin 2012-08-28 18:03:50 +04:00
parent 2490707e5c
commit 136e5b6a94
3 changed files with 138 additions and 92 deletions

219
nyaml.php
View file

@ -1,106 +1,141 @@
<?php <?php
class nyaml { namespace NXP;
private $lines;
public function file($fileName) { class nyaml
{
/**
* Состояния
*/
const PARSE_KEY = 0;
const PARSE_VALUE = 1;
const PARSE_INDENT = 2;
const PARSE_KEY_IN_QUOTE = 3;
const PARSE_KEY_IN_DQUOTE = 4;
const PARSE_VALUE_IN_QUOTE = 5;
const PARSE_VALUE_IN_DQUOTE = 6;
/**
* Термы
*/
const T_SPACE = 0;
const T_NEWLINE = 1;
const T_CHAR = 2;
const T_QUOTE = 3;
const T_DQUOTE = 4;
private $state = 0, $result = array();
/**
* Термы
* @var array
*/
private $terms = array(
self::T_SPACE => '/[\s|\t]/',
self::T_NEWLINE => '/[\n]/',
self::T_CHAR => '/[a-zA-Zа-яА-Я0-9]/',
self::T_QUOTE => '/[\']/',
self::T_DQUOTE => '/[\"]/'
);
/**
* Таблица переходов состояния
* @var array
*/
private $actions = array(
array(self::PARSE_KEY, self::T_CHAR, self::PARSE_KEY),
array(self::PARSE_KEY, self::T_SPACE, self::PARSE_VALUE),
array(self::PARSE_KEY, self::T_NEWLINE, self::PARSE_VALUE),
array(self::PARSE_VALUE, self::T_NEWLINE, self::PARSE_KEY),
array(self::PARSE_VALUE, self::T_SPACE, self::PARSE_VALUE),
array(self::PARSE_VALUE, self::T_CHAR, self::PARSE_VALUE),
array(self::PARSE_KEY, self::T_QUOTE, self::PARSE_KEY_IN_QUOTE),
array(self::PARSE_KEY, self::T_DQUOTE, self::PARSE_KEY_IN_DQUOTE),
array(self::PARSE_VALUE, self::T_QUOTE, self::PARSE_VALUE_IN_QUOTE),
array(self::PARSE_VALUE, self::T_DQUOTE, self::PARSE_VALUE_IN_DQUOTE),
array(self::PARSE_KEY_IN_QUOTE, self::T_QUOTE, self::PARSE_KEY),
array(self::PARSE_KEY_IN_DQUOTE, self::T_DQUOTE, self::PARSE_KEY),
array(self::PARSE_VALUE_IN_QUOTE, self::T_QUOTE, self::PARSE_VALUE),
array(self::PARSE_VALUE_IN_DQUOTE, self::T_DQUOTE, self::PARSE_VALUE),
array(self::PARSE_KEY_IN_QUOTE, self::T_CHAR, self::PARSE_KEY_IN_QUOTE),
array(self::PARSE_KEY_IN_DQUOTE, self::T_CHAR, self::PARSE_KEY_IN_DQUOTE),
array(self::PARSE_VALUE_IN_QUOTE, self::T_CHAR, self::PARSE_VALUE_IN_QUOTE),
array(self::PARSE_VALUE_IN_DQUOTE, self::T_CHAR, self::PARSE_VALUE_IN_DQUOTE),
array(self::PARSE_KEY_IN_QUOTE, self::T_SPACE, self::PARSE_KEY_IN_QUOTE),
array(self::PARSE_KEY_IN_DQUOTE, self::T_SPACE, self::PARSE_KEY_IN_DQUOTE),
array(self::PARSE_VALUE_IN_QUOTE, self::T_SPACE, self::PARSE_VALUE_IN_QUOTE),
array(self::PARSE_VALUE_IN_DQUOTE, self::T_SPACE, self::PARSE_VALUE_IN_DQUOTE),
array(self::PARSE_KEY_IN_QUOTE, self::T_NEWLINE, self::PARSE_KEY_IN_QUOTE),
array(self::PARSE_KEY_IN_DQUOTE, self::T_NEWLINE, self::PARSE_KEY_IN_DQUOTE),
array(self::PARSE_VALUE_IN_QUOTE, self::T_NEWLINE, self::PARSE_VALUE_IN_QUOTE),
array(self::PARSE_VALUE_IN_DQUOTE, self::T_NEWLINE, self::PARSE_VALUE_IN_DQUOTE),
);
public function file($fileName)
{
//Parse file //Parse file
return $this->string(file_get_contents($fileName)); return $this->string(file_get_contents($fileName));
} }
public function string($nyaml) { public function string($nyaml)
//Parse string {
//Preprocessing
$nyaml = preg_replace("/(\n|^)\s*\#.*?\n/", "\n", $nyaml); //Cleaning from one-line comments
$nyaml = str_replace("\r", "", $nyaml); //Fix new lines
$nyaml = str_replace("\n\n", "\n", $nyaml); //Cleaning clear lines
$nyaml = trim($nyaml,"\n");
$this->lines = explode("\n", $nyaml);
//Parsing
return $this->parse(0);
}
private function parse($level) {
$return=array();
$linelevel = $level;
while (count($this->lines)>0) {
$line = array_shift($this->lines);
$linelevel = $this->countLevel($line);
if ($linelevel<$level) { //If next line from root node stop parsing
array_unshift($this->lines, $line);
return $return;
}
if (substr($line,-1,1)==":") { //If new node
$key = substr($line, 0, strlen($line)-1);
$value = $this->parse($linelevel+1);
$return[trim($key)] = $value;
} elseif (strpos($line,":")!==false) { //If key-value pair
list($key, $value) = explode(":", $line, 2);
$return[trim($key)] = $this->parseValue($value);
} else { //If just value
$return[] = trim($line);
}
}
return $return;
}
private function parseValue($value) {
$value = trim($value);
switch (substr($value,0,1)) {
case "\"":
return substr($value,1,(strlen($value)-2));
break;
case "'":
return substr($value,1,(strlen($value)-2));
break;
case "[":
$result = $this->explode(",", substr($value,1,(strlen($value)-2)));
$result = array_map(array($this, "parseValue"), $result);
return $result;
break;
default:
return $value;
}
}
private function explode($letter, $string) {
//smart exploding string
$quotes = array("\"","'","[","]");
$quote = '';
$result = array(); $result = array();
$token = ""; $key = '';
for ($i = 0; $i<strlen($string); $i++) { $value = '';
$symbol = substr($string,$i,1); for ($i = 0; $i < strlen($nyaml); $i++) {
if ((in_array($symbol, $quotes)) && ($quote == '')) {
if ($symbol == '[') { $char = substr($nyaml, $i, 1);
$symbol = ']'; $oldState = $this->state;
} $newState = $this->getState($char);
$quote = $symbol; $this->state = $newState;
} elseif ((in_array($symbol, $quotes)) && ($quote == $symbol)) { if (($newState == self::PARSE_KEY) && ($oldState == self::PARSE_VALUE)) {
if ($quote == ']') { $result[$key] = $value;
$token = "[$token]"; $key = '';
} $value = '';
$quote = '';
} elseif (($symbol == $letter) && ($quote=='')) { }
$result[] = $token; if (($newState == self::PARSE_KEY) && ($oldState == self::PARSE_KEY) && ($oldState != self::PARSE_VALUE_IN_QUOTE) && ($oldState != self::PARSE_VALUE_IN_DQUOTE)) {
$token = ''; $key.=$char;
} else { }
$token .= $symbol; if ( ($newState == self::PARSE_VALUE) && ($oldState != self::PARSE_VALUE_IN_QUOTE) && ($oldState != self::PARSE_VALUE_IN_DQUOTE) ) {
$value.=$char;
}
if (($newState == self::PARSE_KEY_IN_QUOTE) && ($oldState != self::PARSE_KEY)) {
$key.=$char;
}
if (($newState == self::PARSE_KEY_IN_DQUOTE) && ($oldState != self::PARSE_KEY)) {
$key.=$char;
}
if (($newState == self::PARSE_VALUE_IN_QUOTE) && ($oldState != self::PARSE_VALUE)) {
$value.=$char;
}
if (($newState == self::PARSE_VALUE_IN_DQUOTE) && ($oldState != self::PARSE_VALUE)) {
$value.=$char;
} }
} }
if ($token!='') {
$result[] = $token; $result[$key] = $value;
}
return $result; return $result;
} }
private function countLevel($string) { public function getState($char)
//Counting level by indenting {
return (strlen($string) - strlen(ltrim($string,"\t "))); $currentTerm = null;
foreach ($this->terms as $key => $term) {
if (preg_match($term, $char)) {
$currentTerm = $key;
}
}
if ($currentTerm === null) {
throw new Exception('Parse error');
}
foreach ($this->actions as $action) {
if (( $action[0] == $this->state ) && ( $action[1] == $currentTerm )) {
return $action[2];
}
}
} }
} }

3
test.nyaml Normal file
View file

@ -0,0 +1,3 @@
node1 value 1
'node 2' value 2
'node 3' "value 3"

8
test.php Normal file
View file

@ -0,0 +1,8 @@
<?php
include 'nyaml.php';
$nyaml = new NXP\nyaml();
print_r($nyaml->file('test.nyaml'));