PageRenderTime 38ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/lisp/Symbol.cs

http://github.com/toshok/shelisp
C# | 350 lines | 285 code | 53 blank | 12 comment | 29 complexity | 00282e0e46f2a9a8c2faa3f662d34b6d MD5 | raw file
Possible License(s): GPL-3.0
  1. using System;
  2. using System.Reflection;
  3. namespace Shelisp {
  4. public class Symbol : Object {
  5. public static readonly Symbol Unbound = new Symbol (PrimitiveSymbol.Unbound);
  6. enum PrimitiveSymbol {
  7. Unbound
  8. }
  9. private Symbol (PrimitiveSymbol prim)
  10. {
  11. switch (prim) {
  12. case PrimitiveSymbol.Unbound:
  13. this.name = "unbound";
  14. this.value = this.function = this;
  15. break;
  16. default:
  17. throw new NotSupportedException();
  18. }
  19. }
  20. public Symbol (string name)
  21. {
  22. this.name = name;
  23. this.value = Unbound;
  24. this.function = Unbound;
  25. }
  26. public override string ToString(string format_type)
  27. {
  28. switch (format_type) {
  29. case "princ":
  30. return name.ToString();
  31. case "prin1":
  32. return name.Replace(" ", "\\ ");
  33. default:
  34. return base.ToString(format_type);
  35. }
  36. }
  37. public string name;
  38. public Symbol next; /* used in Obarray.cs */
  39. internal INativeValue native;
  40. private Shelisp.Object value;
  41. public Shelisp.Object Value {
  42. get {
  43. return native != null ? native.Value : this.value;
  44. }
  45. set {
  46. if (native != null)
  47. native.Value = value;
  48. else
  49. this.value = value;
  50. }
  51. }
  52. private Shelisp.Object function;
  53. public Shelisp.Object Function {
  54. get { return function; }
  55. set { function = value; }
  56. }
  57. private Shelisp.Object _plist;
  58. private Shelisp.Object plist {
  59. get { return _plist ?? (_plist = L.Qnil); }
  60. set { if (value == null) throw new Exception (); _plist = value; }
  61. }
  62. public override Shelisp.Object Eval (L l, Shelisp.Object env = null)
  63. {
  64. /* Look up its binding in the lexical environment.
  65. We do not pay attention to the declared_special flag here, since we
  66. already did that when let-binding the variable. */
  67. Shelisp.Object lex_binding = List.Fassq (l, this, env ?? l.Environment);
  68. if (L.CONSP (lex_binding)) {
  69. Debug.Print ("list, returning {0}", L.CDR (lex_binding));
  70. return L.CDR (lex_binding);
  71. }
  72. else {
  73. Debug.Print ("symbol, returning {0}", Symbol.Fsymbol_value (l, this));
  74. return Symbol.Fsymbol_value (l, this);
  75. }
  76. }
  77. public override int GetHashCode ()
  78. {
  79. return name.GetHashCode();
  80. }
  81. public override bool Equals (object o)
  82. {
  83. if (!(o is Symbol))
  84. return false;
  85. return ((Symbol)o).name == name;
  86. }
  87. public static implicit operator Symbol (System.String str)
  88. {
  89. return new Symbol (str);
  90. }
  91. [LispBuiltin]
  92. public static Shelisp.Object Fmake_symbol (L l, Shelisp.Object astr)
  93. {
  94. if (!(astr is Shelisp.String))
  95. throw new WrongTypeArgumentException ("stringp", astr);
  96. return new Symbol ((string)(Shelisp.String)astr);
  97. }
  98. [LispBuiltin]
  99. public static Shelisp.Object Fsymbolp (L l, Shelisp.Object asym)
  100. {
  101. return asym is Symbol ? L.Qt : L.Qnil;
  102. }
  103. [LispBuiltin]
  104. public static Shelisp.Object Fboundp (L l, Shelisp.Object asym)
  105. {
  106. Shelisp.Symbol sym = (Shelisp.Symbol)asym;
  107. Shelisp.Object lex_binding = List.Fassq (l, sym, l.Environment);
  108. return L.CONSP (lex_binding) ? L.Qt : (sym.native == null ? (sym.value == L.Qunbound ? L.Qnil : L.Qt) : L.Qt);
  109. }
  110. [LispBuiltin]
  111. public static Shelisp.Object Ffboundp (L l, Shelisp.Object asym)
  112. {
  113. Shelisp.Symbol sym = (Shelisp.Symbol)asym;
  114. Shelisp.Object lex_binding = List.Fassq (l, sym, l.Environment);
  115. return L.CONSP (lex_binding) ? L.Qt : (sym.function.LispEq(L.Qunbound) ? L.Qnil : L.Qt);
  116. }
  117. [LispBuiltin]
  118. public static Shelisp.Object Fsymbol_name (L l, Shelisp.Object o)
  119. {
  120. if (!(o is Symbol))
  121. throw new WrongTypeArgumentException ("symbolp", o);
  122. return ((Symbol)o).name;
  123. }
  124. [LispBuiltin]
  125. public static Shelisp.Object Fsymbol_plist (L l, Shelisp.Object o)
  126. {
  127. if (!(o is Symbol))
  128. throw new WrongTypeArgumentException ("symbolp", o);
  129. return ((Symbol)o).plist;
  130. }
  131. [LispBuiltin]
  132. public static Shelisp.Object Fsymbol_value (L l, Shelisp.Object o)
  133. {
  134. if (!(o is Symbol))
  135. throw new WrongTypeArgumentException ("symbolp", o);
  136. // constant symbols have a value that is themselves
  137. if (((Symbol)o).name[0] == ':')
  138. return o;
  139. var value = ((Symbol)o).Value;
  140. if (value.LispEq (L.Qunbound))
  141. throw new LispVoidVariableException (o);
  142. return value;
  143. }
  144. [LispBuiltin]
  145. public static Shelisp.Object Fsymbol_function (L l, Shelisp.Object o)
  146. {
  147. if (!(o is Symbol))
  148. throw new WrongTypeArgumentException ("symbolp", o);
  149. var func = ((Symbol)o).Function;
  150. if (func.LispEq (L.Qunbound))
  151. throw new LispVoidFunctionException (o);
  152. return func;
  153. }
  154. [LispBuiltin]
  155. public static Shelisp.Object Ffset (L l, Shelisp.Object sym, Shelisp.Object defn)
  156. {
  157. if (!(sym is Symbol))
  158. throw new WrongTypeArgumentException ("symbolp", sym);
  159. //if (NILP (symbol) || EQ (symbol, Qt))
  160. // xsignal1 (Qsetting_constant, symbol);
  161. ((Symbol)sym).Function = defn;
  162. return defn;
  163. }
  164. [LispBuiltin]
  165. public static Shelisp.Object Ffmakunbound (L l, Shelisp.Object sym)
  166. {
  167. if (!(sym is Symbol))
  168. throw new WrongTypeArgumentException ("symbolp", sym);
  169. //if (NILP (symbol) || EQ (symbol, Qt))
  170. // xsignal1 (Qsetting_constant, symbol);
  171. ((Symbol)sym).Function = L.Qunbound;
  172. return sym;
  173. }
  174. [LispBuiltin]
  175. public static Shelisp.Object Fput (L l, Shelisp.Object asym, Shelisp.Object property, Shelisp.Object value)
  176. {
  177. if (!(asym is Symbol))
  178. throw new WrongTypeArgumentException ("symbolp", asym);
  179. Symbol sym = (Symbol)asym;
  180. sym.plist = Plist.Fplist_put (l, sym.plist, property, value);
  181. return value;
  182. }
  183. [LispBuiltin]
  184. public static Shelisp.Object Fget (L l, Shelisp.Object sym, Shelisp.Object property)
  185. {
  186. if (!(sym is Symbol))
  187. throw new WrongTypeArgumentException ("symbolp", sym);
  188. return Plist.Fplist_get (l, ((Symbol)sym).plist, property);
  189. }
  190. [LispBuiltin (DocString = @"Return t if SYMBOL has a non-void default value.
  191. This is the value that is seen in buffers that do not have their own values
  192. for this variable.")]
  193. public static Shelisp.Object Fdefault_boundp (L l, Shelisp.Object sym)
  194. {
  195. // XXX not implemented properly
  196. return ((Symbol)sym).Value.LispEq (L.Qunbound) ? L.Qnil : L.Qt;
  197. }
  198. [LispBuiltin (DocString = @"Return SYMBOL's default value.
  199. This is the value that is seen in buffers that do not have their own values
  200. for this variable. The default value is meaningful for variables with
  201. local bindings in certain buffers.")]
  202. public static Shelisp.Object Fdefault_value (L l, Shelisp.Object sym)
  203. {
  204. // XXX not implemented properly
  205. var val = ((Symbol)sym).Value;
  206. if (val.LispEq (L.Qunbound))
  207. throw new LispVoidVariableException (sym);
  208. return ((Symbol)sym).Value;
  209. }
  210. [LispBuiltin (DocString = @"Return t if OBJECT is a keyword.
  211. This means that it is a symbol with a print name beginning with `:'
  212. interned in the initial obarray.")]
  213. public static Shelisp.Object Fkeywordp (L l, Shelisp.Object sym)
  214. {
  215. // XXX initial obarray?
  216. return ((sym is Symbol) && ((Symbol)sym).name[0] == ':') ? L.Qt : L.Qnil;
  217. }
  218. // helper classes/interface for Symbol.native
  219. internal interface INativeValue {
  220. Shelisp.Object Value { get; set; }
  221. }
  222. internal class NativeFieldInfoBase {
  223. public NativeFieldInfoBase (object o, FieldInfo field)
  224. {
  225. this.o = o;
  226. this.field = field;
  227. }
  228. protected object o;
  229. protected FieldInfo field;
  230. }
  231. internal class NativeFieldInfo : NativeFieldInfoBase, INativeValue {
  232. public NativeFieldInfo (object o, FieldInfo field) : base (o, field) { }
  233. public Shelisp.Object Value {
  234. get { return (Shelisp.Object)field.GetValue (o); }
  235. set { field.SetValue (o, value); }
  236. }
  237. }
  238. internal class NativeBoolFieldInfo : NativeFieldInfoBase, INativeValue {
  239. public NativeBoolFieldInfo (object o, FieldInfo field) : base (o, field) { }
  240. public Shelisp.Object Value {
  241. get { return (bool)field.GetValue (o) ? L.Qt : L.Qnil; }
  242. set { field.SetValue (o, L.NILP(value) ? false : true); }
  243. }
  244. }
  245. internal class NativeIntFieldInfo : NativeFieldInfoBase, INativeValue {
  246. public NativeIntFieldInfo (object o, FieldInfo field) : base (o, field) { }
  247. public Shelisp.Object Value {
  248. get { return new Number((int)field.GetValue (o)); }
  249. set { field.SetValue (o, (int)((Number)value).boxed); }
  250. }
  251. }
  252. internal class NativeFloatFieldInfo : NativeFieldInfoBase, INativeValue {
  253. public NativeFloatFieldInfo (object o, FieldInfo field) : base (o, field) { }
  254. public Shelisp.Object Value {
  255. get { return new Number((float)field.GetValue (o)); }
  256. set { field.SetValue (o, (float)((Number)value).boxed); }
  257. }
  258. }
  259. internal class NativePropertyInfoBase {
  260. public NativePropertyInfoBase (object o, PropertyInfo property)
  261. {
  262. this.o = o;
  263. this.property = property;
  264. }
  265. protected object o;
  266. protected PropertyInfo property;
  267. }
  268. internal class NativePropertyInfo : NativePropertyInfoBase, INativeValue {
  269. public NativePropertyInfo (object o, PropertyInfo property) : base (o, property) { }
  270. public Shelisp.Object Value {
  271. get { return (Shelisp.Object)property.GetValue (o, new object[0]); }
  272. set { property.SetValue (o, value, new object[0]); }
  273. }
  274. }
  275. internal class NativeBoolPropertyInfo : NativePropertyInfoBase, INativeValue {
  276. public NativeBoolPropertyInfo (object o, PropertyInfo property) : base (o, property) { }
  277. public Shelisp.Object Value {
  278. get { return (bool)property.GetValue (o, new object[0]) ? L.Qt : L.Qnil; }
  279. set { property.SetValue (o, L.NILP(value) ? false : true, new object[0]); }
  280. }
  281. }
  282. internal class NativeIntPropertyInfo : NativePropertyInfoBase, INativeValue {
  283. public NativeIntPropertyInfo (object o, PropertyInfo property) : base (o, property) { }
  284. public Shelisp.Object Value {
  285. get { return new Number((int)property.GetValue (o, new object[0])); }
  286. set { property.SetValue (o, (int)((Number)value).boxed, new object[0]); }
  287. }
  288. }
  289. internal class NativeFloatPropertyInfo : NativePropertyInfoBase, INativeValue {
  290. public NativeFloatPropertyInfo (object o, PropertyInfo property) : base (o, property) { }
  291. public Shelisp.Object Value {
  292. get { return new Number((float)property.GetValue (o, new object[0])); }
  293. set { property.SetValue (o, (float)((Number)value).boxed, new object[0]); }
  294. }
  295. }
  296. }
  297. }