Add support for TOML version 0.4.0

This commit is contained in:
Leonel Quinteros 2015-03-27 13:46:10 -03:00
parent 1c3eafd203
commit 2fb5908103
2 changed files with 141 additions and 13 deletions

View File

@ -7,7 +7,7 @@ PHP parser for TOML language ( https://github.com/toml-lang/toml )
Support Support
------- -------
TOML version: 0.2.0 TOML version: [v0.4.0](https://github.com/mojombo/toml/blob/master/versions/en/toml-v0.4.0.md)
Requirements Requirements

View File

@ -77,10 +77,12 @@ class Toml
// Split lines // Split lines
$aToml = explode("\n", $toml); $aToml = explode("\n", $toml);
print_r($aToml);
foreach($aToml as $line) //foreach($aToml as $line)
for($ln = 0; $ln < count($aToml); $ln++)
{ {
$line = trim($line); $line = trim($aToml[$ln]);
// Skip commented and empty lines // Skip commented and empty lines
if(empty($line) || $line[0] == '#') if(empty($line) || $line[0] == '#')
@ -148,7 +150,35 @@ class Toml
$kv = explode('=', $line, 2); $kv = explode('=', $line, 2);
if(!isset($pointer[ trim($kv[0]) ])) if(!isset($pointer[ trim($kv[0]) ]))
{ {
$pointer[ trim($kv[0]) ] = self::parseValue( $kv[1] ); // Multi-line strings
if(substr(trim($kv[1]), 0, 3) == '"""')
{
if(strlen(trim($kv[1])) > 3 && substr(trim($kv[1]), -3) != '"""' || strlen(trim($kv[1])) == 3)
{
do
{
$ln++;
$kv[1] .= "\n" . $aToml[$ln];
}
while(strpos($aToml[$ln], '"""') === false);
}
}
// Multi-line literal strings
if(substr(trim($kv[1]), 0, 3) == "'''")
{
if(strlen(trim($kv[1])) > 3 && substr(trim($kv[1]), -3) != "'''" || strlen(trim($kv[1])) == 3)
{
do
{
$ln++;
$kv[1] .= "\n" . $aToml[$ln];
}
while(strpos($aToml[$ln], "'''") === false);
}
}
$pointer[ trim($kv[0]) ] = self::parseValue( trim($kv[1]) );
} }
else else
{ {
@ -188,6 +218,9 @@ class Toml
// Run, char by char. // Run, char by char.
$normalized = ''; $normalized = '';
$openString = false; $openString = false;
$openLString = false;
$openMString = false;
$openMLString = false;
$openBrackets = 0; $openBrackets = 0;
$openKeygroup = false; $openKeygroup = false;
$lineBuffer = ''; $lineBuffer = '';
@ -241,15 +274,59 @@ class Toml
// EOLs inside string should throw error. // EOLs inside string should throw error.
throw new Exception("Multi-line strings are not allowed on: " . $lineBuffer); throw new Exception("Multi-line strings are not allowed on: " . $lineBuffer);
} }
elseif($toml[$i] == '"' && $toml[$i - 1] != "\\") elseif($toml[$i] == '"' && $toml[$i - 1] != "\\") // String handling, allow escaped quotes.
{ {
// String handling, allow escaped quotes. // Check multi-line strings
$openString = !$openString; if($toml[$i+1] == '"' && $toml[$i+2] == '"')
{
// Include the token inmediately.
$i += 2;
$normalized .= '"""';
$lineBuffer .= '"""';;
$keep = false;
$openMString = !$openMString;
}
else // Simple strings
{
$openString = !$openString;
}
} }
elseif($toml[$i] == "\\" && !in_array($toml[$i+1], array('0', 't', 'n', 'r', '"', "\\"))) elseif($toml[$i] == "'") // Literal string handling.
{ {
// Reserved special characters should produce error // Check multi-line strings
throw new Exception('Reserved special characters inside strings are not allowed: ' . $toml[$i] . $toml[$i+1]); if($toml[$i+1] == "'" && $toml[$i+2] == "'")
{
// Include the token inmediately.
$i += 2;
$normalized .= "'''";
$lineBuffer .= "'''";
$keep = false;
$openMLString = !$openMLString;
}
else // Simple strings
{
$openLString = !$openLString;
}
}
elseif($toml[$i] == "\\" && !in_array($toml[$i+1], array('0', 't', 'n', 'r', "u", '"', "\\")))
{
// Reserved special characters inside strings should produce error
if($openString)
{
throw new Exception('Reserved special characters inside strings are not allowed: ' . $toml[$i] . $toml[$i+1]);
}
// Cleanup escaped new lines and whitespaces from multi-line strings
if($openMString)
{
while($toml[$i+1] == "\n" || $toml[$i+1] == " ")
{
$i++;
}
$keep = false;
}
} }
elseif($toml[$i] == '#' && !$openString && !$openKeygroup) elseif($toml[$i] == '#' && !$openString && !$openKeygroup)
{ {
@ -277,7 +354,7 @@ class Toml
} }
// Something went wrong. // Something went wrong.
if($openBrackets || $openString || $openKeygroup) if($openBrackets || $openString || $openLString || $openMString || $openMLString || $openKeygroup)
{ {
throw new Exception('Syntax error found on TOML document.'); throw new Exception('Syntax error found on TOML document.');
} }
@ -300,7 +377,7 @@ class Toml
// Cleanup // Cleanup
$val = trim($val); $val = trim($val);
if(empty($val)) if($val === '')
{ {
throw new Exception('Empty value not allowed'); throw new Exception('Empty value not allowed');
} }
@ -310,6 +387,42 @@ class Toml
{ {
$parsedVal = (bool) $val; $parsedVal = (bool) $val;
} }
// Literal multi-line string
elseif(substr($val, 0, 3) == "'''" && substr($val, -3) == "'''")
{
$parsedVal = substr($val, 3, -3);
// Trim first newline on multi-line string definition
if($parsedVal[0] == "\n")
{
$parsedVal = substr($parsedVal, 1);
}
}
// Literal string
elseif($val[0] == "'" && substr($val, -1) == "'")
{
// No newlines allowed
if(strpos($val, "\n") !== false)
{
throw new Exception('New lines not allowed on single line string literals.');
}
$parsedVal = substr($val, 1, -1);
}
// Multi-line string
elseif(substr($val, 0, 3) == '"""' && substr($val, -3) == '"""')
{
$parsedVal = substr($val, 3, -3);
// Trim first newline on multi-line string definition
if($parsedVal[0] == "\n")
{
$parsedVal = substr($parsedVal, 1);
}
// Use json_decode to finally parse the string.
$parsedVal = json_decode('"' . str_replace("\n", '\n', $parsedVal) . '"');
}
// String // String
elseif($val[0] == '"' && substr($val, -1) == '"') elseif($val[0] == '"' && substr($val, -1) == '"')
{ {
@ -317,8 +430,10 @@ class Toml
$parsedVal = json_decode($val); $parsedVal = json_decode($val);
} }
// Numbers // Numbers
elseif(is_numeric($val)) elseif(is_numeric(str_replace('_', '', $val)))
{ {
$val = str_replace('_', '', $val);
if(is_int($val)) if(is_int($val))
{ {
$parsedVal = (int) $val; $parsedVal = (int) $val;
@ -338,6 +453,11 @@ class Toml
{ {
$parsedVal = self::parseArray($val); $parsedVal = self::parseArray($val);
} }
// Inline table (normalized)
elseif($val[0] == '{' && substr($val, -1) == '}')
{
$parsedVal = self::parseInlineTable($val);
}
else else
{ {
throw new Exception('Unknown value type: ' . $val); throw new Exception('Unknown value type: ' . $val);
@ -419,6 +539,14 @@ class Toml
throw new Exception('Wrong array definition: ' . $val); throw new Exception('Wrong array definition: ' . $val);
} }
/**
* Parse inline tables into common table array
*/
private static function parseInlineTable($val)
{
return $val;
}
/** /**
* Function that checks the data type of the first and last elements of an array, * Function that checks the data type of the first and last elements of an array,
* and returns false if they don't match * and returns false if they don't match