123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218 |
- /*
- * Copyright (C) 2007-2008, Jeff Thompson
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of the copyright holder nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- using System;
- using System.Collections.Generic;
- using System.Text;
- namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
- {
- public class Atom : IUnifiable
- {
- private static Dictionary<string, Atom> _atomStore = new Dictionary<string, Atom>();
- public readonly string _name;
- public readonly Atom _module;
- /// <summary>
- /// You should not call this constructor, but use Atom.a instead.
- /// </summary>
- /// <param name="name"></param>
- /// <param name="module"></param>
- private Atom(string name, Atom module)
- {
- _name = name;
- _module = module;
- }
- /// <summary>
- /// Return the unique Atom object for name where module is null. You should use this to create
- /// an Atom instead of calling the Atom constructor.
- /// </summary>
- /// <param name="name"></param>
- /// <returns></returns>
- public static Atom a(string name)
- {
- Atom atom;
- if (!_atomStore.TryGetValue(name, out atom))
- {
- atom = new Atom(name, null);
- _atomStore[name] = atom;
- }
- return atom;
- }
- /// <summary>
- /// Return an Atom object with the name and module. If module is null or Atom.NIL,
- /// this behaves like Atom.a(name) and returns the unique object where the module is null.
- /// If module is not null or Atom.NIL, this may or may not be the same object as another Atom
- /// with the same name and module.
- /// </summary>
- /// <param name="name"></param>
- /// <param name="module"></param>
- /// <returns></returns>
- public static Atom a(string name, Atom module)
- {
- if (module == null || module == Atom.NIL)
- return a(name);
- return new Atom(name, module);
- }
- /// <summary>
- /// If Obj is an Atom unify its _module with Module. If the Atom's _module is null, use Atom.NIL.
- /// </summary>
- /// <param name="Atom"></param>
- /// <param name="Module"></param>
- /// <returns></returns>
- public static IEnumerable<bool> module(object Obj, object Module)
- {
- Obj = YP.getValue(Obj);
- if (Obj is Atom)
- {
- if (((Atom)Obj)._module == null)
- return YP.unify(Module, Atom.NIL);
- else
- return YP.unify(Module, ((Atom)Obj)._module);
- }
- return YP.fail();
- }
- public static readonly Atom NIL = Atom.a("[]");
- public static readonly Atom DOT = Atom.a(".");
- public static readonly Atom F = Atom.a("f");
- public static readonly Atom SLASH = Atom.a("/");
- public static readonly Atom HAT = Atom.a("^");
- public static readonly Atom RULE = Atom.a(":-");
- public IEnumerable<bool> unify(object arg)
- {
- arg = YP.getValue(arg);
- if (arg is Atom)
- return Equals(arg) ? YP.succeed() : YP.fail();
- else if (arg is Variable)
- return ((Variable)arg).unify(this);
- else
- return YP.fail();
- }
- public void addUniqueVariables(List<Variable> variableSet)
- {
- // Atom does not contain variables.
- }
- public object makeCopy(Variable.CopyStore copyStore)
- {
- // Atom does not contain variables that need to be copied.
- return this;
- }
- public bool termEqual(object term)
- {
- return Equals(YP.getValue(term));
- }
- public bool ground()
- {
- // Atom is always ground.
- return true;
- }
- public override bool Equals(object obj)
- {
- if (obj is Atom)
- {
- if (_module == null && ((Atom)obj)._module == null)
- // When _declaringClass is null, we always use an identical object from _atomStore.
- return this == obj;
- // Otherwise, ignore _declaringClass and do a normal string compare on the _name.
- return _name == ((Atom)obj)._name;
- }
- return false;
- }
- public override string ToString()
- {
- return _name;
- }
- public override int GetHashCode()
- {
- // Debug: need to check _declaringClass.
- return _name.GetHashCode();
- }
- public string toQuotedString()
- {
- if (_name.Length == 0)
- return "''";
- else if (this == Atom.NIL)
- return "[]";
- StringBuilder result = new StringBuilder(_name.Length);
- bool useQuotes = false;
- foreach (char c in _name)
- {
- int cInt = (int)c;
- if (c == '\'')
- {
- result.Append("''");
- useQuotes = true;
- }
- else if (c == '_' || cInt >= (int)'a' && cInt <= (int)'z' ||
- cInt >= (int)'A' && cInt <= (int)'Z' || cInt >= (int)'0' && cInt <= (int)'9')
- result.Append(c);
- else
- {
- // Debug: Need to handle non-printable chars.
- result.Append(c);
- useQuotes = true;
- }
- }
- if (!useQuotes && (int)_name[0] >= (int)'a' && (int)_name[0] <= (int)'z')
- return result.ToString();
- else
- {
- // Surround in single quotes.
- result.Append('\'');
- return "'" + result;
- }
- }
- /// <summary>
- /// Return true if _name is lexicographically less than atom._name.
- /// </summary>
- /// <param name="atom"></param>
- /// <returns></returns>
- public bool lessThan(Atom atom)
- {
- return _name.CompareTo(atom._name) < 0;
- }
- }
- }
|