151 lines
5.3 KiB
PHP
151 lines
5.3 KiB
PHP
<?php
|
|
namespace XaiCorp\AbcParser;
|
|
|
|
use XaiCorp\AbcParser\Interfaces\Builder;
|
|
|
|
class Parser {
|
|
/**
|
|
* the abc passed to the parser might be a single tune or
|
|
* it might be a collection of tunes, with extra data outside
|
|
* of each tune. This external data should be applied to each
|
|
* tune and the collection.
|
|
*
|
|
* When reading the abc, the parser should create a new collection
|
|
* and a new Tune object for each tune encountered in the abc.
|
|
* External tools can then deal with that collection as they like.
|
|
*
|
|
*/
|
|
|
|
//regexp patterns for different lines
|
|
const LN_VERSION = '/^%abc(-\d\.\d)?$/';
|
|
const LN_BLANK = '/^\s*$/';
|
|
const LN_FIELD = '/^\w:(.+)$/';
|
|
|
|
const MODE_NO_DATA = 0;
|
|
const MODE_FILE_HEADER = 1;
|
|
const MODE_TUNE_HEADER = 2;
|
|
const MODE_TUNE_BODY = 3;
|
|
|
|
const SINGLE_VALUE_KEYS = ['P','Q','L','M','K'];
|
|
|
|
public function __construct(Builder $builder)
|
|
{
|
|
$this->builder = $builder;
|
|
}
|
|
|
|
/**
|
|
* extract the attributes from the raw abc
|
|
* @param <string> $abc string containing the raw abc
|
|
*
|
|
* @return
|
|
*/
|
|
public function parseABC($abc)
|
|
{
|
|
//tune is either new or existing data has been loaded
|
|
//create new setting
|
|
$mode = self::MODE_FILE_HEADER;
|
|
$this->builder->newCollection();
|
|
$tune = null;
|
|
$setting = null;
|
|
$inHistory = false;
|
|
$inTunes = false;
|
|
$music = "";
|
|
$keys_for_Settings = '/K|L|M|P|Q|B|N|D|S|W|Z|F/';
|
|
$keys_for_Tunes = '/H|A|C|G|R|T|O/';
|
|
//scan abc by line and see what the first char is
|
|
foreach (preg_split("/(\r?\n)/", $abc) as $line) {
|
|
|
|
if (preg_match(self::LN_BLANK, $line)) {
|
|
if ($mode === self::MODE_TUNE_BODY || $mode === self::MODE_TUNE_HEADER) {
|
|
$this->builder->storeTune($music);
|
|
$music = '';
|
|
}
|
|
|
|
$mode = self::MODE_NO_DATA;
|
|
} elseif ($mode === self::MODE_TUNE_BODY) {
|
|
$music .= $line . PHP_EOL;
|
|
} elseif (preg_match(self::LN_VERSION, $line)) {
|
|
//this line might contain the abc version.
|
|
//What do we want to do with it?
|
|
} elseif (preg_match(self::LN_FIELD, $line) || $inHistory) {
|
|
if (preg_match(self::LN_FIELD, $line)) { $inHistory = FALSE; }
|
|
//split the line "key:data"
|
|
if($inHistory) {
|
|
$key = 'H';
|
|
$data = $line;
|
|
} else {
|
|
$key = substr($line, 0, 1);
|
|
$data = trim(substr($line, 2));
|
|
}
|
|
|
|
if ($key === 'X') {
|
|
$mode = self::MODE_TUNE_HEADER;
|
|
$inTunes = true;
|
|
$this->builder->newTune();
|
|
$this->builder->newSetting();
|
|
$music = '';
|
|
|
|
$this->builder->setOnTune('X', $data);
|
|
|
|
} elseif (preg_match($keys_for_Tunes, $key)) {
|
|
if ($key === 'H') {
|
|
$inHistory = TRUE;
|
|
} else {
|
|
$inHistory = FALSE;
|
|
}
|
|
if ($key === 'A' || $key === 'C') {
|
|
$data = $this->builder->newPerson(['name'=>$data]);
|
|
}
|
|
if ($mode === self::MODE_FILE_HEADER) {
|
|
if (in_array($key, self::SINGLE_VALUE_KEYS)) {
|
|
$this->builder->setOnCollection($key, $data);
|
|
} else {
|
|
$this->builder->appendToCollection($key, $data);
|
|
}
|
|
} elseif($inTunes) {
|
|
if (in_array($key, self::SINGLE_VALUE_KEYS)) {
|
|
$this->builder->setOnTune($key, $data);
|
|
} else {
|
|
$this->builder->appendToTune($key, $data);
|
|
}
|
|
}
|
|
|
|
} elseif (preg_match($keys_for_Settings, $key)) {
|
|
if ($key === 'K' && $mode === self::MODE_TUNE_HEADER) {
|
|
$mode = self::MODE_TUNE_BODY;
|
|
}
|
|
|
|
if ($key === 'Z') {
|
|
$data = $this->builder->newPerson(['name'=>$data]);
|
|
}
|
|
|
|
|
|
if ($mode == self::MODE_FILE_HEADER) {
|
|
if (in_array($key, self::SINGLE_VALUE_KEYS)) {
|
|
$this->builder->setOnCollection($key, $data);
|
|
} else {
|
|
$this->builder->appendToCollection($key, $data);
|
|
}
|
|
} elseif($inTunes){
|
|
if (in_array($key, self::SINGLE_VALUE_KEYS)) {
|
|
$this->builder->setOnSetting($key, $data);
|
|
} else {
|
|
$this->builder->appendToSetting($key, $data);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
return $this->builder->getCollection();
|
|
}
|
|
|
|
// private static function _storeTune($music, &$setting, &$tune, &$tuneCollection) {
|
|
// $setting -> set('music', trim($music));
|
|
// $tune -> append('collection', $setting);
|
|
// $tuneCollection -> append('collection', $tune);
|
|
// }
|
|
|
|
}
|