- // FIXME: change StringBuilder to substrings
- if (source == null)
- throw new ArgumentNullException ("source");
-
- // FIXME: hack
- source = source.Replace ('/', Path.DirectorySeparatorChar);
- source = source.Replace ('\\', Path.DirectorySeparatorChar);
- StringBuilder temp = new StringBuilder ();
- CharEnumerator it = source.GetEnumerator ();
- EvaluationState eState = EvaluationState.Out;
- ParenState pState = ParenState.Out;
- ApostropheState aState = ApostropheState.Out;
- int start = 0;
- int current = -1;
-
- while (it.MoveNext ()) {
- current++;
- switch (eState) {
- case EvaluationState.Out:
- switch (it.Current) {
- case '@':
- if (temp.Length > 0) {
- objects.Add (temp.ToString ());
- temp = new StringBuilder ();
- }
- eState = EvaluationState.InItem;
- start = current;
- break;
- case '$':
- if (temp.Length > 0) {
- objects.Add (temp.ToString ());
- temp = new StringBuilder ();
- }
- eState = EvaluationState.InProperty;
- start = current;
- break;
- case '%':
- if (temp.Length > 0) {
- objects.Add (temp.ToString ());
- temp = new StringBuilder ();
- }
- eState = EvaluationState.InMetadata;
- start = current;
- break;
- default:
- temp.Append (it.Current);
- if (current == source.Length - 1)
- objects.Add (temp.ToString ());
- break;
- }
- break;
- case EvaluationState.InItem:
- switch (it.Current) {
- case '(':
- if (pState == ParenState.Out && aState == ApostropheState.Out)
- pState = ParenState.Left;
- else if (aState == ApostropheState.Out)
- throw new Exception ("'(' not expected.");
- break;
- case ')':
- if (pState == ParenState.Left && aState == ApostropheState.Out) {
- objects.Add (new ItemReference (this, source.Substring (start, current - start + 1)));
- eState = EvaluationState.Out;
- pState = ParenState.Out;
- }
- break;
- case '\'':
- if (aState == ApostropheState.In)
- aState = ApostropheState.Out;
- else
- aState = ApostropheState.In;
- break;
- default:
- break;
- }
- break;
- case EvaluationState.InProperty:
- switch (it.Current) {
- case '(':
- if (pState == ParenState.Out)
- pState = ParenState.Left;
- else
- throw new Exception ("'(' expected.");
- break;
- case ')':
- if (pState == ParenState.Left) {
- objects.Add (new PropertyReference (this, source.Substring (start, current - start + 1)));
- eState = EvaluationState.Out;
- pState = ParenState.Out;
- }
- break;
- default:
- break;
- }
- break;
- case EvaluationState.InMetadata:
- switch (it.Current) {
- case '(':
- if (pState == ParenState.Out)
- pState = ParenState.Left;
- break;
- case ')':
- if (pState == ParenState.Left) {
- objects.Add (new MetadataReference (this, source.Substring (start, current - start + 1)));
- eState = EvaluationState.Out;
- pState = ParenState.Out;
- }
- break;
- default:
- break;
- }
- break;
- default:
- throw new Exception ("Invalid evaluation state.");
- }
- }