/*
 * Bernoulli Compiler
 * Copyright (c) Cornell University
 * Department of Computer Science
 * 
 * Kamen Yotov (kamen@yotov.org)
 * 
 * $Source: C:/CVS/kyotov/kyotov/Research/BC/Core/Lexers/Lexer.cs,v $
 * $Revision: 1.8 $
 * $Date: 2002/08/09 02:35:53 $
 */

using System;
using System.IO;
using System.Collections;
using System.Text.RegularExpressions;

namespace BC.Core
{
	using Exceptions;
	using Grammars;
	using Grammars.Symbols;

	namespace Lexers
	{
		[Serializable]
		public abstract class Lexer
		{
			public const string WhiteSpace = "_whitespace";

			private Packet t;
			private Regex r;

			protected Lexer ()
			{
				t = new Packet("token");

				Configure();

				string b = string.Format("(?<token>{0})*", Build(t).Substring(1));

				r = new Regex(b, RegexOptions.Compiled | RegexOptions.Multiline);

				RegexCompilationInfo ci = new RegexCompilationInfo(b, RegexOptions.Compiled | RegexOptions.Multiline, this.GetType().Name, "test", true);

				r.Match("");
			}

			protected ICollection ParseTokenName (string name)
			{
				return new Regex(@"(_(?<node>[^_]+))*").Match(name).Groups["node"].Captures;
			}

			protected string this [string name]
			{
				get
				{
					Packet h = t;

					foreach (object o in ParseTokenName(name))
						h = h[o.ToString()];

					return h.Pattern;
				}
				set
				{
					Packet h = t;

					foreach (object o in ParseTokenName(name))
					{
						string k = o.ToString();

						if (!h.Children.Contains(k))
							h[k] = new Packet(k);

						h = h[k];
					}

					h.Pattern = value;
				}
			}

			protected string this [Terminal t]
			{
				get
				{
					return this[t.Name];
				}
				set
				{
					this[t.Name] = value;
				}
			}

			protected abstract void Configure ();

			protected string Build (Packet t)
			{
				string r = "";

				foreach (string k in t.Children.Keys)
					r += Build(t[k]);

				if (t.Pattern != null)
					r += string.Format("|(?<{0}>{1})", t.FullName, t.Pattern);

				return r;
			}

			protected void Inspect (Packet t, ref Source s, ref Match m, ref Sequence l)
			{
				foreach (string k in t.Names)
					Inspect(t[k], ref s, ref m, ref l);

				if (t.FullName.IndexOf(WhiteSpace) < 0)
					foreach (Capture c in m.Groups[t.FullName].Captures)
						l.Add(new Terminal(t.FullName, c.Value, s[c.Index, c.Value.Length]));
			}

			public Sequence Execute (string f)
			{
				return Execute(f, true);
			}

			public Sequence Execute (string f, bool e)
			{
				Source s = new Source(f);

				Match m = r.Match(s.Content);

				if (e && m.Value.Length != s.Content.Length)
					throw new BCException(ExceptionType.Lexical, UI.Code.bc_lexical, s[m.Value.Length, 0]);

				Sequence l = new Sequence();

				Inspect(t, ref s, ref m, ref l);

				l.Sort();

				return l;
			}
		}
	}
}