/* vim: set noexpandtab tabstop=4 shiftwidth=4 nowrap textwidth=100
*
* Echo Media Player
* Copyright (C) 2008 Shane O'Connell
*
* [ The original file includes a copyright header in this location describing
* the file as being released under the terms of the GNU General Public
* License. It has been removed in order to display the file as part of the
* archive. ]
*/
using Echo.Interfaces;
public abstract class Echo.Query.Expression : GLib.Object
{
public static Expression? create_from_string(string str)
{
assert(str != null);
var tokens = new GLib.SList<string>();
int ch = 0;
while (ch < str.length) {
// Skip whitespace
while (ch < str.length && str[ch] == ' ')
str++;
if (ch >= str.length)
break;
// Get a token
switch (str[ch]) {
case '(':
case ')':
case '-':
case ':':
tokens.append(str[ch]);
ch++;
break;
case '"':
ch++;
if (ch >= str.length)
break;
int start = ch;
while (ch < str.length && str[ch] != '"')
ch++;
tokens.append(str.substring(start, ch - start));
if (ch < str.length)
ch++;
break;
default:
int start = ch;
while (ch < str.length &&
str[ch] != ' ' &&
str[ch] != '"' &&
str[ch] != '(' &&
str[ch] != ')' &&
str[ch] != ':')
ch++;
tokens.append(str.substring(start, ch - start));
break;
}
}
string[] array_tokens = new string[tokens.length()];
int i = 0;
foreach (string token in tokens)
array_tokens[i++] = token;
return create_from_tokens(array_tokens, 0, array_tokens.length);
}
private static Expression? create_from_tokens(string[] tokens, int offset, int stop_offset)
{
if (offset >= stop_offset)
return null; // There's nothing else in this expression (maybe an unfinished AND/OR?)
// Get the left side of this assumed binary expression
Expression left_expression = parse_left_expression(tokens, ref offset);
// If there's nothing else then this wasn't a binary expression
if (offset >= stop_offset)
return left_expression;
switch (tokens[offset])
{
case "OR":
return new OrExpression(left_expression, create_from_tokens(tokens, offset + 1, stop_offset));
case "AND":
return new AndExpression(left_expression, create_from_tokens(tokens, offset + 1, stop_offset));
default:
return new AndExpression(left_expression, create_from_tokens(tokens, offset, stop_offset));
}
}
private static Expression parse_left_expression(string[] tokens, ref int offset)
{
if (tokens[offset] == "(") {
offset++;
int nest_count = 0;
for (int stop_offset = offset; stop_offset < tokens.length; stop_offset++) {
if (tokens[stop_offset] == "(")
nest_count++;
if (tokens[stop_offset] == ")")
if (nest_count == 0)
return create_from_tokens(tokens, offset, stop_offset);
else
nest_count--;
}
return create_from_tokens(tokens, offset, tokens.length);
}
if (tokens[offset] == "-" || tokens[offset] == "NOT") {
offset++; // Skip the - or NOT
return new NotExpression(parse_left_expression(tokens, ref offset));
}
if ((offset + 1) < tokens.length && tokens[offset + 1] == ':') {
switch (tokens[offset])
{
case "rating":
return new RatingExpression(tokens, ref offset);
case "artist":
return new ArtistMatchExpression(tokens, ref offset);
case "album":
return new AlbumMatchExpression(tokens, ref offset);
default: // Skip the unknown thing
offset += 2;
return new MatchExpression(tokens, ref offset);
}
}
else
return new MatchExpression(tokens, ref offset);
}
public bool evaluate_for_track(ITrack track)
{
}
}