PageRenderTime 53ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/lisp/Lisp.cs

http://github.com/toshok/shelisp
C# | 1300 lines | 1034 code | 215 blank | 51 comment | 178 complexity | 6e41679842b84fd5f1a8b00d705de1fb MD5 | raw file
Possible License(s): GPL-3.0
  1. using System;
  2. using SysArray = System.Array;
  3. using System.Diagnostics;
  4. using System.Collections.Generic;
  5. using System.Reflection;
  6. using System.Text.RegularExpressions;
  7. namespace Shelisp {
  8. public class L {
  9. static Vector obarray;
  10. static Vector current_obarray;
  11. static L ()
  12. {
  13. obarray = new Vector (65, new Number (0));
  14. current_obarray = obarray;
  15. // must come first
  16. Qunbound = Symbol.Unbound;
  17. Qcdr = DEFSYM ("cdr");
  18. Qcar = DEFSYM ("car");
  19. Qlambda = DEFSYM ("lambda");
  20. Qclosure = DEFSYM ("closure");
  21. Qmacro = DEFSYM ("macro");
  22. Qquote = DEFSYM ("quote");
  23. Qautoload = DEFSYM ("autoload");
  24. Qtest = DEFSYM (":test");
  25. Qweakness = DEFSYM (":weakness");
  26. Qsize = DEFSYM (":size");
  27. Qrehash_size = DEFSYM (":rehash-size");
  28. Qrehash_threshold = DEFSYM (":rehash-threshold");
  29. Qkey = DEFSYM ("key");
  30. Qvalue = DEFSYM ("value");
  31. Qkey_or_value = DEFSYM ("key-or-value");
  32. Qkey_and_value = DEFSYM ("key-and-value");
  33. Qt = DEFSYM ("t");
  34. ((Symbol)Qt).Value = Qt;
  35. Qnil = DEFSYM ("nil");
  36. ((Symbol)Qnil).Value = Qnil;
  37. variable_container_types = new List<Type>();
  38. root_environment = Qnil;
  39. RegisterGlobalBuiltins (typeof (L).Assembly);
  40. }
  41. public void DumpEnvironment ()
  42. {
  43. if (!L.NILP(Environment)) {
  44. foreach (var binding in (List)Environment) {
  45. if (NILP(binding))
  46. break;
  47. Debug.Print ("{0}", CAR(binding));
  48. }
  49. }
  50. }
  51. public L ()
  52. {
  53. Environment = root_environment;
  54. variable_containers = new List<object>();
  55. foreach (var t in variable_container_types) {
  56. object o;
  57. if (t == GetType())
  58. o = this;
  59. else
  60. o = Activator.CreateInstance (t);
  61. RegisterVariables (t, o);
  62. variable_containers.Add (o);
  63. }
  64. }
  65. public static void RegisterGlobalBuiltins (Assembly assembly)
  66. {
  67. foreach (var t in assembly.GetTypes())
  68. RegisterGlobalBuiltins (t);
  69. }
  70. static bool IsLispOptional (ParameterInfo p)
  71. {
  72. return Attribute.GetCustomAttribute (p, typeof (LispOptionalAttribute), true) != null;
  73. }
  74. static bool IsLispRest (ParameterInfo p)
  75. {
  76. return Attribute.GetCustomAttribute (p, typeof (LispRestAttribute), true) != null;
  77. }
  78. static bool IsParams (ParameterInfo p)
  79. {
  80. return Attribute.GetCustomAttribute (p, typeof (ParamArrayAttribute), true) != null;
  81. }
  82. public static void RegisterGlobalBuiltins (Type t)
  83. {
  84. foreach (var method in t.GetMethods()) {
  85. var builtin_attrs = method.GetCustomAttributes (typeof (LispBuiltinAttribute), true);
  86. if (builtin_attrs == null || builtin_attrs.Length == 0)
  87. continue;
  88. foreach (var ba in builtin_attrs) {
  89. LispBuiltinAttribute builtin_attr = (LispBuiltinAttribute)ba;
  90. var lisp_name = builtin_attr.Name ?? method.Name.Replace("_", "-");
  91. if (lisp_name.StartsWith ("F"))
  92. lisp_name = lisp_name.Substring (1);
  93. Debug.Print ("found [LispBuiltin({0})] on method '{1}.{2}'", lisp_name, method.DeclaringType, method.Name);
  94. string doc_string = builtin_attr.DocString ?? "";
  95. int min_args = builtin_attr.MinArgs;
  96. if (min_args == -1) {
  97. // compute the minimum args
  98. var parameters = method.GetParameters ();
  99. for (int i = 1/*we skip the `L l' first parameter*/; i < parameters.Length; i ++) {
  100. if (IsLispOptional (parameters[i])) {
  101. min_args = i-1; // -1 to remove the `L l' parameter
  102. break;
  103. }
  104. else if (IsParams (parameters[i])) {
  105. min_args = i-1; // -1 to remove the `L l' parameter
  106. break;
  107. }
  108. }
  109. }
  110. Symbol s = L.intern (lisp_name);
  111. s.Function = L.DEFUN_internal (lisp_name, doc_string, min_args, builtin_attr.Unevalled, method);
  112. root_environment = new List (new List (s, s), root_environment);
  113. }
  114. }
  115. bool has_instance_variables = false;
  116. bool has_static_variables = false;
  117. // check if the type defines any builtin properties or fields. if so, create an instance of it, register the builtins,
  118. // and add the instance to the variable_container_types list.
  119. foreach (var field in t.GetFields()) {
  120. var builtin_attrs = field.GetCustomAttributes (typeof (LispBuiltinAttribute), true);
  121. if (builtin_attrs != null && builtin_attrs.Length != 0) {
  122. if (field.IsStatic)
  123. has_static_variables = true;
  124. else
  125. has_instance_variables = true;
  126. if (has_static_variables && has_instance_variables)
  127. break;
  128. }
  129. }
  130. if (!has_static_variables || !has_instance_variables) {
  131. foreach (var property in t.GetProperties()) {
  132. var builtin_attrs = property.GetCustomAttributes (typeof (LispBuiltinAttribute), true);
  133. if (builtin_attrs != null && builtin_attrs.Length != 0) {
  134. if (property.GetGetMethod().IsStatic)
  135. has_static_variables = true;
  136. else
  137. has_instance_variables = true;
  138. if (has_static_variables && has_instance_variables)
  139. break;
  140. }
  141. }
  142. }
  143. if (has_instance_variables)
  144. variable_container_types.Add (t);
  145. if (has_static_variables)
  146. RegisterVariables (t, null);
  147. }
  148. public static void RegisterVariables (Type type, object o)
  149. {
  150. foreach (var field in type.GetFields()) {
  151. if (o == null && !field.IsStatic)
  152. continue;
  153. var builtin_attrs = field.GetCustomAttributes (typeof (LispBuiltinAttribute), true);
  154. if (builtin_attrs == null || builtin_attrs.Length == 0)
  155. continue;
  156. foreach (var ba in builtin_attrs) {
  157. LispBuiltinAttribute builtin_attr = (LispBuiltinAttribute)ba;
  158. var lisp_name = builtin_attr.Name ?? field.Name.Replace("_", "-");
  159. if (lisp_name.StartsWith ("V"))
  160. lisp_name = lisp_name.Substring (1);
  161. Debug.Print ("found [LispBuiltin({0})] on field '{1}.{2}'", lisp_name, field.DeclaringType, field.Name);
  162. string doc_string = builtin_attr.DocString ?? "";
  163. Symbol s = L.intern (lisp_name);
  164. if (field.FieldType == typeof(bool))
  165. s.native = new Symbol.NativeBoolFieldInfo (o, field);
  166. else if (field.FieldType == typeof(int))
  167. s.native = new Symbol.NativeIntFieldInfo (o, field);
  168. else if (field.FieldType == typeof(float))
  169. s.native = new Symbol.NativeFloatFieldInfo (o, field);
  170. else
  171. s.native = new Symbol.NativeFieldInfo (o, field);
  172. }
  173. }
  174. foreach (var property in type.GetProperties()) {
  175. if (o == null && !property.GetGetMethod().IsStatic)
  176. continue;
  177. var builtin_attrs = property.GetCustomAttributes (typeof (LispBuiltinAttribute), true);
  178. if (builtin_attrs == null || builtin_attrs.Length == 0)
  179. continue;
  180. foreach (var ba in builtin_attrs) {
  181. LispBuiltinAttribute builtin_attr = (LispBuiltinAttribute)ba;
  182. var lisp_name = builtin_attr.Name ?? property.Name.Replace("_", "-");
  183. if (lisp_name.StartsWith ("V"))
  184. lisp_name = lisp_name.Substring (1);
  185. Debug.Print ("found [LispBuiltin({0})] on property '{1}.{2}'", lisp_name, property.DeclaringType, property.Name);
  186. string doc_string = builtin_attr.DocString ?? "";
  187. Symbol s = L.intern (lisp_name);
  188. if (property.PropertyType == typeof(bool))
  189. s.native = new Symbol.NativeBoolPropertyInfo (o, property);
  190. else if (property.PropertyType == typeof(int))
  191. s.native = new Symbol.NativeIntPropertyInfo (o, property);
  192. else if (property.PropertyType == typeof(float))
  193. s.native = new Symbol.NativeFloatPropertyInfo (o, property);
  194. else
  195. s.native = new Symbol.NativePropertyInfo (o, property);
  196. }
  197. }
  198. }
  199. [LispBuiltin]
  200. public Shelisp.Object Vfeatures = L.make_list (L.intern ("emacs"));
  201. public bool IsFeatureLoaded (Symbol feature)
  202. {
  203. foreach (var feature_sym in (List)Vfeatures) {
  204. if (((Symbol)feature_sym).LispEq(feature))
  205. return true;
  206. }
  207. return false;
  208. }
  209. public void AddFeature (Symbol feature)
  210. {
  211. if (!IsFeatureLoaded (feature))
  212. Vfeatures = new List (feature, Vfeatures);
  213. }
  214. // the types we've made note of as having variables. these are
  215. // instantiated and registered when a new L instance is created.
  216. private static List<Type> variable_container_types;
  217. // this is the list containing the instantiated container types.
  218. // we don't care about them, we just need to protect them from being
  219. // GC'ed for the lifetime of this L.
  220. private List<object> variable_containers;
  221. // our current executing environment
  222. public Shelisp.Object Environment { get; set; }
  223. // the environment that contains all the builtin definitions
  224. static Shelisp.Object root_environment;
  225. public static Shelisp.Object Qcdr;
  226. public static Shelisp.Object Qcar;
  227. public static Shelisp.Object Qt;
  228. public static Shelisp.Object Qnil;
  229. public static Shelisp.Object Qlambda;
  230. public static Shelisp.Object Qmacro;
  231. public static Shelisp.Object Qunbound;
  232. public static Shelisp.Object Qquote;
  233. public static Shelisp.Object Qclosure;
  234. public static Shelisp.Object Qautoload;
  235. public static Shelisp.Symbol Qtest;
  236. public static Shelisp.Symbol Qweakness;
  237. public static Shelisp.Symbol Qsize;
  238. public static Shelisp.Symbol Qrehash_size;
  239. public static Shelisp.Symbol Qrehash_threshold;
  240. public static Shelisp.Symbol Qkey;
  241. public static Shelisp.Symbol Qvalue;
  242. public static Shelisp.Symbol Qkey_or_value;
  243. public static Shelisp.Symbol Qkey_and_value;
  244. // [i*2] = beginning of match
  245. // [i*2+1] = end of match
  246. public static int[] match_data;
  247. [LispBuiltin ("obarray")]
  248. public static Shelisp.Object CurrentObarray {
  249. get { return current_obarray; }
  250. }
  251. public static Shelisp.Symbol intern (string str)
  252. {
  253. return intern (str, obarray);
  254. }
  255. public static Shelisp.Symbol intern (string str, Vector obarray)
  256. {
  257. return Obarray.Intern (obarray, str);
  258. }
  259. public static Shelisp.Object intern_soft (string str)
  260. {
  261. return intern_soft (str, obarray);
  262. }
  263. public static Shelisp.Object intern_soft (string str, Vector obarray)
  264. {
  265. return Obarray.InternSoft (obarray, str);
  266. }
  267. public static Shelisp.Object string_array_to_list (string[] arr)
  268. {
  269. Object cons = Qnil;
  270. for (int i = arr.Length - 1; i >= 0; i --)
  271. cons = new List (new Shelisp.String (arr[i]), cons);
  272. return cons;
  273. }
  274. public static Shelisp.Object int_array_to_list (int[] arr)
  275. {
  276. Object cons = Qnil;
  277. for (int i = arr.Length - 1; i >= 0; i --)
  278. cons = new List (new Shelisp.Number (arr[i]), cons);
  279. return cons;
  280. }
  281. public static Shelisp.Object make_list_atom_tail (params Shelisp.Object[] arr)
  282. {
  283. if (arr.Length > 1) {
  284. Object cons = arr[arr.Length-1];
  285. for (int i = arr.Length - 2; i >= 0; i --)
  286. cons = new List (arr[i], cons);
  287. return cons;
  288. }
  289. else
  290. throw new Exception ("failed to make list with non-cons tail");
  291. }
  292. public static Shelisp.Object make_list (params Shelisp.Object[] arr)
  293. {
  294. Object cons = Qnil;
  295. for (int i = arr.Length - 1; i >= 0; i --)
  296. cons = new List (arr[i], cons);
  297. return cons;
  298. }
  299. private static Shelisp.Symbol DEFSYM (string lisp_name)
  300. {
  301. Symbol s = intern (lisp_name);
  302. return s;
  303. }
  304. private static Shelisp.Subr DEFUN_internal (string lisp_name, string doc, int min_args, bool unevalled, MethodInfo meth, object target = null)
  305. {
  306. Subr s = new Subr (lisp_name, doc, min_args, unevalled, meth);
  307. return s;
  308. }
  309. private static Shelisp.Subr DEFUN_internal (string lisp_name, string doc, int min_args, Delegate d)
  310. {
  311. return DEFUN_internal (lisp_name, doc, min_args, false, d.Method, d.Target);
  312. }
  313. public static Shelisp.Subr DEFUN (string lisp_name, string doc, Action func)
  314. {
  315. return DEFUN_internal (lisp_name, doc, 0, func);
  316. }
  317. public static Shelisp.Subr DEFUN<T> (string lisp_name, string doc, int min_args, Func<T> func)
  318. {
  319. return DEFUN_internal (lisp_name, doc, min_args, func);
  320. }
  321. public static Shelisp.Subr DEFUN<T1,T2> (string lisp_name, string doc, int min_args, Func<T1,T2> func)
  322. {
  323. return DEFUN_internal (lisp_name, doc, min_args, func);
  324. }
  325. public static Shelisp.Subr DEFUN<T1,T2,T3> (string lisp_name, string doc, int min_args, Func<T1,T2,T3> func)
  326. {
  327. return DEFUN_internal (lisp_name, doc, min_args, func);
  328. }
  329. public static Shelisp.Subr DEFUN<T1,T2,T3,T4> (string lisp_name, string doc, int min_args, Func<T1,T2,T3,T4> func)
  330. {
  331. return DEFUN_internal (lisp_name, doc, min_args, func);
  332. }
  333. public static Shelisp.Object CAR (Shelisp.Object cons)
  334. {
  335. if (!(cons is List))
  336. Console.WriteLine ("CAR {0}", cons);
  337. return ((List)cons).car;
  338. }
  339. public static Shelisp.Object CDR (Shelisp.Object cons)
  340. {
  341. return NILP(cons) ? Qnil : ((List)cons).cdr;
  342. }
  343. public static Shelisp.List CONS (Shelisp.Object cons)
  344. {
  345. return ((List)cons);
  346. }
  347. public static bool NILP (Shelisp.Object o)
  348. {
  349. return o == Qnil;
  350. }
  351. public static bool LISTP (Shelisp.Object o)
  352. {
  353. return o is List || o == Qnil;
  354. }
  355. public static bool CONSP (Shelisp.Object o)
  356. {
  357. return o is List;
  358. }
  359. // string foo
  360. public static int SCHARS (Shelisp.Object o)
  361. {
  362. return (o as String).native_string.Length;
  363. }
  364. public static char SREF (Shelisp.Object o, int c)
  365. {
  366. return (o as String).native_string[c];
  367. }
  368. static int eval_indent = 0;
  369. [LispBuiltin]
  370. public static bool enable_eval_spew = false;
  371. [Conditional ("EVAL_SPEW")]
  372. public static void EvalIndent (int specified_amount = -1)
  373. {
  374. if (specified_amount == -1)
  375. specified_amount = 2;
  376. eval_indent += specified_amount;
  377. }
  378. [Conditional ("EVAL_SPEW")]
  379. public static void EvalOutdent (int specified_amount = -1)
  380. {
  381. if (specified_amount == -1)
  382. specified_amount = 2;
  383. eval_indent -= specified_amount;
  384. }
  385. [Conditional ("EVAL_SPEW")]
  386. public static void EvalSpew (string format, params object[] args)
  387. {
  388. if (!enable_eval_spew)
  389. return;
  390. for (int i = 0; i < eval_indent; i ++)
  391. Console.Write (" ");
  392. Console.WriteLine (format, args);
  393. }
  394. [LispBuiltin]
  395. public static Shelisp.Object Ffuncall (L l, Shelisp.Object fun, params Shelisp.Object[] args)
  396. {
  397. try {
  398. if (l.eval_depth ++ >= L.max_lisp_eval_depth)
  399. throw new Exception ("max eval depth exceeded");
  400. if (fun is Symbol)
  401. fun = ((Symbol)fun).Function;
  402. if (fun is Subr) {
  403. L.EvalSpew ("funcall subr application, {0}", fun);
  404. L.EvalIndent();
  405. var rv = ((Subr)fun).Call (l, args);
  406. L.EvalOutdent();
  407. L.EvalSpew ("funcall subr {0} evaluated to {1}", fun, rv);
  408. return rv;
  409. }
  410. else {
  411. L.EvalSpew ("evaluating funcall, {0}", fun);
  412. L.EvalIndent();
  413. var rv = List.ApplyLambda (l, fun, L.make_list (args), null, false/*the args have already been evaluated*/);
  414. L.EvalOutdent();
  415. L.EvalSpew ("evaluating of {0} resulted in {1}", fun, rv);
  416. return rv;
  417. }
  418. }
  419. finally {
  420. l.eval_depth --;
  421. }
  422. }
  423. [LispBuiltin]
  424. public static Shelisp.Object Fapply (L l, Shelisp.Object fun, params Shelisp.Object[] args)
  425. {
  426. //XXX typecheck everything
  427. // fix up the args..
  428. Shelisp.Object rest_args = args[args.Length - 1];
  429. int rest_count = (L.NILP (rest_args)) ? 0 : ((List)rest_args).Length;
  430. Shelisp.Object[] real_args = new Shelisp.Object[args.Length - 1 + rest_count];
  431. System.Array.Copy (args, 0, real_args, 0, args.Length - 1);
  432. if (rest_count > 0) {
  433. int i = args.Length - 1;
  434. foreach (var arg in (List)rest_args) {
  435. real_args[i++] = arg;
  436. }
  437. }
  438. if (fun is Symbol)
  439. fun = L.Findirect_function (l, fun, L.Qnil);
  440. fun = fun.Eval(l);
  441. if (fun is Subr)
  442. return ((Subr)fun).Call (l, real_args);
  443. else
  444. return List.ApplyLambda (l, fun, L.make_list (real_args), null, false/*the args have already been evaluated*/);
  445. }
  446. [LispBuiltin]
  447. public static Shelisp.Object Feval (L l, Shelisp.Object obj, Shelisp.Object lexical)
  448. {
  449. return obj.Eval(l);
  450. }
  451. [LispBuiltin (Unevalled = true)]
  452. public static Shelisp.Object Ffunction (L l, Shelisp.Object args)
  453. {
  454. Shelisp.Object quoted = args;
  455. #if not_ported
  456. if (!L.NILP (L.CDR (args)))
  457. xsignal2 (Qwrong_number_of_arguments, Qfunction, Flength (args));
  458. #endif
  459. if (/*!L.NILP (l.Environment)
  460. &&*/ L.CONSP (quoted)
  461. && L.CAR (quoted).LispEq (L.Qlambda)) {
  462. /* This is a lambda expression within a lexical environment;
  463. return an interpreted closure instead of a simple lambda. */
  464. return new List (L.Qclosure, new List (l.Environment,
  465. L.CDR (quoted)));
  466. }
  467. else {
  468. /* Simply quote the argument. */
  469. return quoted;
  470. }
  471. }
  472. [LispBuiltin]
  473. public static Shelisp.Object Ffunctionp (L l, Shelisp.Object obj)
  474. {
  475. if ((obj is Symbol) && !L.NILP (Symbol.Ffboundp (l, obj))) {
  476. obj = Findirect_function (l, obj, L.Qt);
  477. if (L.CONSP (obj) && L.CAR(obj).LispEq (L.Qautoload)) {
  478. /* Autoloaded symbols are functions, except if they load macros or keymaps. */
  479. int i;
  480. for (i = 0; i < 4 && L.CONSP (obj); i++)
  481. obj = L.CDR (obj);
  482. return (L.CONSP (obj) && !L.NILP (L.CAR (obj))) ? L.Qnil : L.Qt;
  483. }
  484. }
  485. if (obj is Subr)
  486. return (((Subr)obj).unevalled) ? L.Qt : L.Qnil;
  487. #if notyet
  488. else if (COMPILEDP (obj))
  489. return L.Qt;
  490. #endif
  491. else if (L.CONSP (obj)) {
  492. Shelisp.Object car = L.CAR (obj);
  493. return (car.LispEq (L.Qlambda) || car.LispEq (L.Qclosure)) ? L.Qt : L.Qnil;
  494. }
  495. else
  496. return L.Qnil;
  497. }
  498. [LispBuiltin (Unevalled = true)]
  499. public static Shelisp.Object Finteractive (L l, params Shelisp.Object[] args)
  500. {
  501. #if DEBUG
  502. Debug.Print ("(interactive");
  503. foreach (var a in args)
  504. Debug.Print (" {0}", a);
  505. Debug.Print (")");
  506. #endif
  507. return L.Qnil;
  508. }
  509. [LispBuiltin]
  510. public static Shelisp.Object Ferror (L l, Shelisp.Object format, params Shelisp.Object[] args)
  511. {
  512. // we need a C-styled sprintf/string.Format here
  513. throw new Exception ((string)(Shelisp.String)format);
  514. }
  515. [LispBuiltin]
  516. public static Shelisp.Object Frun_hooks (L l, [LispRest] params Shelisp.Object[] hookvars)
  517. {
  518. foreach (var hookvar in hookvars) {
  519. if (!(hookvar is Symbol))
  520. throw new WrongTypeArgumentException ("symbolp", hookvar);
  521. if (L.NILP (Symbol.Fboundp (l, hookvar)))
  522. return L.Qnil;
  523. Shelisp.Object hooks = hookvar.Eval(l);
  524. if (!L.NILP (hooks)) {
  525. foreach (var hook in (List)hooks.Eval(l))
  526. new List (hook, L.Qnil).Eval (l);
  527. }
  528. }
  529. return L.Qnil;
  530. }
  531. [LispBuiltin]
  532. public static Shelisp.Object Findirect_function (L l, Shelisp.Object symorfunction, [LispOptional] Shelisp.Object noerror)
  533. {
  534. Shelisp.Object sym = symorfunction;
  535. while (true) {
  536. if (sym is Symbol) {
  537. if (sym.LispEq (L.Qunbound)) {
  538. return sym;
  539. }
  540. sym = ((Symbol)sym).Function;
  541. continue;
  542. }
  543. else {
  544. return sym;
  545. }
  546. }
  547. }
  548. [LispBuiltin (MinArgs = 3, Unevalled = true, DocString =
  549. @"Define NAME as a function.
  550. The definition is (lambda ARGLIST [DOCSTRING] BODY...).
  551. See also the function `interactive'.
  552. usage: (defun NAME ARGLIST [DOCSTRING] BODY...)")]
  553. public static Shelisp.Object Fdefun (L l, Shelisp.Object sym, Shelisp.Object arglist, params Shelisp.Object[] body_forms)
  554. {
  555. if (!(sym is Symbol))
  556. throw new WrongTypeArgumentException ("symbolp", sym);
  557. var doc_string = "";
  558. if (body_forms.Length > 0) {
  559. if (body_forms[0] is Shelisp.String) {
  560. doc_string = (Shelisp.String)body_forms[0];
  561. Shelisp.Object[] new_body_forms = new Shelisp.Object[body_forms.Length - 1];
  562. SysArray.Copy (body_forms, 1, new_body_forms, 0, new_body_forms.Length);
  563. body_forms = new_body_forms;
  564. }
  565. }
  566. if (body_forms.Length == 0)
  567. throw new Exception ("0 length body forms");
  568. Shelisp.Object defn = List.Fnconc (l, L.make_list (L.Qlambda, arglist), new List (body_forms));
  569. Symbol s = (Symbol)sym;
  570. Symbol.Ffset (l, s, defn);
  571. // XXX more here I'm sure... like what do we do with the doc string?
  572. //l.Environment = new List (new List(s, s), l.Environment);
  573. return sym;
  574. }
  575. [LispBuiltin]
  576. public static Shelisp.Object Fdefalias (L l, Shelisp.Object name, Shelisp.Object defn, [LispOptional] Shelisp.Object doc_string)
  577. {
  578. if (!(name is Symbol))
  579. throw new WrongTypeArgumentException ("symbolp", name);
  580. Shelisp.Object fun;
  581. if (defn is Symbol)
  582. fun = ((Symbol)defn).Function;
  583. else
  584. fun = defn;
  585. Symbol s = (Symbol)name;
  586. Symbol.Ffset (l, s, defn);
  587. // XXX more here I'm sure... like what do we do with the doc string?
  588. //l.Environment = new List (new List(s, s), l.Environment);
  589. return fun;
  590. }
  591. [LispBuiltin (Unevalled = true)]
  592. public static Shelisp.Object Fdefconst (L l, Shelisp.Object sym, Shelisp.Object value, [LispOptional] Shelisp.Object doc_string)
  593. {
  594. if (!(sym is Symbol))
  595. throw new WrongTypeArgumentException ("symbolp", sym);
  596. ((Symbol)sym).Value = value.Eval (l);
  597. return sym;
  598. }
  599. [LispBuiltin (MinArgs = 2, Unevalled = true)]
  600. public static Shelisp.Object Fdefmacro (L l, Shelisp.Object sym, Shelisp.Object arglist, params Shelisp.Object[] body_forms)
  601. {
  602. if (!(sym is Symbol))
  603. throw new WrongTypeArgumentException ("symbolp", sym);
  604. var doc_string = "";
  605. if (body_forms.Length > 0) {
  606. if (body_forms[0] is Shelisp.String) {
  607. doc_string = (Shelisp.String)body_forms[0];
  608. Shelisp.Object[] new_body_forms = new Shelisp.Object[body_forms.Length - 1];
  609. SysArray.Copy (body_forms, 1, new_body_forms, 0, new_body_forms.Length);
  610. body_forms = new_body_forms;
  611. }
  612. }
  613. Shelisp.Object defn = List.Fnconc (l, L.make_list (L.Qmacro, L.Qlambda, arglist), body_forms.Length == 0 ? L.Qnil : new List (body_forms));
  614. Symbol s = (Symbol)sym;
  615. Symbol.Ffset (l, s, defn);
  616. // XXX more here I'm sure... like what do we do with the doc string?
  617. //l.Environment = new List (new List(s, s), l.Environment);
  618. return sym;
  619. }
  620. [LispBuiltin (Unevalled = true)]
  621. public static Shelisp.Object Fdefvar (L l, Shelisp.Object sym, [LispOptional] Shelisp.Object value, Shelisp.Object docstring)
  622. {
  623. if (!(sym is Symbol))
  624. throw new WrongTypeArgumentException ("symbolp", sym);
  625. ((Symbol)sym).Value = L.NILP(value) ? L.Qnil : value.Eval (l);
  626. return sym;
  627. }
  628. [LispBuiltin]
  629. public static Shelisp.Object Fdefvaralias (L l, Shelisp.Object name, Shelisp.Object base_variable, [LispOptional] Shelisp.Object doc_string)
  630. {
  631. if (!(name is Symbol))
  632. throw new WrongTypeArgumentException ("symbolp", name);
  633. Shelisp.Object value;
  634. if (base_variable is Symbol)
  635. value = ((Symbol)base_variable).Value;
  636. else
  637. value = base_variable;
  638. ((Symbol)name).Value = value;
  639. // XXX more here I'm sure... like what do we do with the doc string?
  640. //l.Environment = new List (new List(s, s), l.Environment);
  641. return base_variable;
  642. }
  643. [LispBuiltin (Unevalled = true)]
  644. public static Shelisp.Object Fsetq_default (L l, params Shelisp.Object[] sym_vals)
  645. {
  646. Shelisp.Object evalled = L.Qnil;
  647. for (int i = 0; i < sym_vals.Length; i += 2) {
  648. var sym = sym_vals[i];
  649. if (!(sym is Symbol))
  650. throw new WrongTypeArgumentException ("symbolp", sym);
  651. var val = i < sym_vals.Length - 1 ? sym_vals[i+1] : L.Qnil;
  652. evalled = val.Eval(l);
  653. ((Symbol)sym).Value = evalled;
  654. }
  655. return evalled;
  656. }
  657. [LispBuiltin (Unevalled = true)]
  658. public static Shelisp.Object Fset_default (L l, params Shelisp.Object[] sym_vals)
  659. {
  660. Shelisp.Object val = L.Qnil;
  661. for (int i = 0; i < sym_vals.Length; i += 2) {
  662. var sym = sym_vals[i];
  663. if (!(sym is Symbol)) {
  664. sym = sym.Eval(l);
  665. if (!(sym is Symbol))
  666. throw new WrongTypeArgumentException ("symbolp", sym);
  667. }
  668. val = i < sym_vals.Length - 1 ? sym_vals[i+1] : L.Qnil;
  669. ((Symbol)sym).Value = val;
  670. }
  671. return val;
  672. }
  673. [LispBuiltin (Unevalled = true)]
  674. public static Shelisp.Object Fsetq (L l, params Shelisp.Object[] sym_vals)
  675. {
  676. Shelisp.Object evalled = L.Qnil;
  677. for (int i = 0; i < sym_vals.Length; i += 2) {
  678. var sym = sym_vals[i];
  679. if (!(sym is Symbol))
  680. throw new WrongTypeArgumentException ("symbolp", sym);
  681. var val = i < sym_vals.Length - 1 ? sym_vals[i+1] : L.Qnil;
  682. evalled = val.Eval(l);
  683. // if the symbol exists in our environment it there.
  684. // otherwise set the global (on the symbol).
  685. Shelisp.Object lex_binding = List.Fassq (l, sym, l.Environment);
  686. if (L.CONSP (lex_binding)) {
  687. ((List)lex_binding).cdr = evalled;
  688. }
  689. else {
  690. ((Shelisp.Symbol)sym).Value = evalled;
  691. }
  692. }
  693. return evalled;
  694. }
  695. [LispBuiltin]
  696. public static Shelisp.Object Fset (L l, Shelisp.Object sym, Shelisp.Object val)
  697. {
  698. if (!(sym is Symbol))
  699. throw new WrongTypeArgumentException ("symbolp", sym);
  700. // if the symbol exists in our environment it there.
  701. // otherwise set the global (on the symbol).
  702. Shelisp.Object lex_binding = List.Fassq (l, sym, l.Environment);
  703. if (L.CONSP (lex_binding)) {
  704. ((List)lex_binding).cdr = val;
  705. }
  706. else {
  707. ((Shelisp.Symbol)sym).Value = val;
  708. }
  709. return val;
  710. }
  711. [LispBuiltin (Unevalled = true)]
  712. public static Shelisp.Object Flet (L l, Shelisp.Object bindings, params Shelisp.Object[] forms)
  713. {
  714. Shelisp.Object prev_environment = l.Environment;
  715. Shelisp.Object new_environment = l.Environment;
  716. if (L.CONSP (bindings)) {
  717. foreach (var binding in (List)bindings) {
  718. Shelisp.Object sym, value;
  719. if (L.CONSP (binding)) {
  720. sym = L.CAR(binding);
  721. Debug.Print ("sym = {0}, binding = {1}", sym, L.CAR(L.CDR (binding)));
  722. value = L.CAR(L.CDR (binding)).Eval(l, prev_environment);
  723. }
  724. else {
  725. sym = binding;
  726. value = L.Qnil;
  727. }
  728. Debug.Print ("adding binding from {0} to {1}", sym, value);
  729. try {
  730. new_environment = new List (new List (sym, value), new_environment);
  731. }
  732. catch (Exception) {
  733. Console.WriteLine ("{0} = {1}", sym, value);
  734. }
  735. }
  736. }
  737. l.Environment = new_environment;
  738. Debug.Print ("evaluating body forms");
  739. Shelisp.Object rv = L.Qnil;
  740. foreach (var o in forms) {
  741. Debug.Print ("form = {0}", o);
  742. rv = o.Eval (l);
  743. }
  744. l.Environment = prev_environment;
  745. return rv;
  746. }
  747. [LispBuiltin ("let*", Unevalled = true)]
  748. public static Shelisp.Object Flet_star (L l, Shelisp.Object bindings, params Shelisp.Object[] forms)
  749. {
  750. Shelisp.Object prev_environment = l.Environment;
  751. if (L.CONSP (bindings)) {
  752. foreach (var binding in (List)bindings) {
  753. Shelisp.Object sym, value;
  754. if (L.CONSP (binding)) {
  755. sym = L.CAR(binding);
  756. value = L.CAR(L.CDR (binding)).Eval(l, l.Environment);
  757. }
  758. else {
  759. sym = binding;
  760. value = L.Qnil;
  761. }
  762. l.Environment = new List (new List (sym, value), l.Environment);
  763. }
  764. }
  765. Shelisp.Object rv = L.Qnil;
  766. foreach (var o in forms)
  767. rv = o.Eval (l);
  768. l.Environment = prev_environment;
  769. return rv;
  770. }
  771. [LispBuiltin]
  772. public static Shelisp.Object Fcurrent_time (L l)
  773. {
  774. DateTime unixRef = new DateTime(1970, 1, 1, 0, 0, 0);
  775. long ticks_unix = (DateTime.Now.Ticks - unixRef.Ticks);
  776. int high, low, microseconds;
  777. int seconds;
  778. seconds = (int)(ticks_unix / TimeSpan.TicksPerSecond);
  779. microseconds = (int)(ticks_unix % TimeSpan.TicksPerSecond);
  780. high = (int)(seconds / (2<<16));
  781. low = (int)(seconds % (2<<16));
  782. return L.make_list (high, low, microseconds);
  783. }
  784. [LispBuiltin]
  785. public static Shelisp.Object Fsystem_name (L l)
  786. {
  787. // XXX
  788. return (Shelisp.String)"localhost";
  789. }
  790. [LispBuiltin]
  791. public static Shelisp.Object Fgarbage_collect (L l)
  792. {
  793. GC.Collect();
  794. Console.WriteLine ("garbage-collect statistics not here yet");
  795. return L.Qnil;
  796. }
  797. [LispBuiltin]
  798. public Shelisp.Object Vgc_cons_threshold = new Number (Int32.MaxValue);
  799. [LispBuiltin]
  800. public bool Vgarbage_collection_messages = false;
  801. static Shelisp.Object find_matching_handler (LispException e, Shelisp.Object[] handlers)
  802. {
  803. foreach (var handler in handlers) {
  804. var error_match_list = L.CAR (handler);
  805. if (L.NILP (error_match_list))
  806. continue;
  807. if (L.CONSP (error_match_list)) {
  808. if (!L.NILP (List.Memq (e.Symbol, (Shelisp.List)error_match_list))) {
  809. return L.CDR (handler);
  810. }
  811. }
  812. else if (error_match_list.LispEq (e.Symbol)) {
  813. return L.CDR (handler);
  814. }
  815. }
  816. return L.Qnil;
  817. }
  818. [LispBuiltin (Unevalled = true, DocString = @"Eval BODY allowing nonlocal exits using `throw'.
  819. TAG is evalled to get the tag to use; it must not be nil.
  820. Then the BODY is executed.
  821. Within BODY, a call to `throw' with the same TAG exits BODY and this `catch'.
  822. If no throw happens, `catch' returns the value of the last BODY form.
  823. If a throw happens, it specifies the value to return from `catch'.
  824. usage: (catch TAG BODY...)")]
  825. public static Shelisp.Object Fcatch (L l, Shelisp.Object tag, [LispRest] params Shelisp.Object[] bodies)
  826. {
  827. if (L.NILP (tag))
  828. throw new Exception ();
  829. tag = tag.Eval (l);
  830. if (!(tag is Symbol))
  831. throw new Exception ();
  832. Shelisp.Object rv = L.Qnil;
  833. try {
  834. foreach (var body in bodies)
  835. rv = body.Eval(l);
  836. }
  837. catch (LispThrown e) {
  838. if (tag.LispEq (e.Tag))
  839. rv = e.Value;
  840. else
  841. throw;
  842. }
  843. return rv;
  844. }
  845. [LispBuiltin]
  846. public static Shelisp.Object Fthrow (L l, Shelisp.Object tag, Shelisp.Object val)
  847. {
  848. if (L.NILP (tag))
  849. throw new Exception ();
  850. throw new LispThrown (tag, val);
  851. }
  852. [LispBuiltin (Unevalled = true)]
  853. public static Shelisp.Object Fcondition_case (L l, Shelisp.Object var, Shelisp.Object protected_form, params Shelisp.Object[] handlers)
  854. {
  855. try {
  856. return protected_form.Eval(l);
  857. }
  858. catch (LispException e) {
  859. /* find a handler that handles the error symbol */
  860. Shelisp.Object handler_forms = find_matching_handler (e, handlers);
  861. if (!L.NILP (handler_forms)) {
  862. Shelisp.Object rv = L.Qnil;
  863. foreach (var handler_form in (List)handler_forms)
  864. rv = handler_form.Eval(l);
  865. return rv;
  866. }
  867. // if nothing matches, rethrow
  868. throw;
  869. }
  870. }
  871. [LispBuiltin (Unevalled = true, DocString = @"Do BODYFORM, protecting with UNWINDFORMS.
  872. If BODYFORM completes normally, its value is returned
  873. after executing the UNWINDFORMS.
  874. If BODYFORM exits nonlocally, the UNWINDFORMS are executed anyway.
  875. usage: (unwind-protect BODYFORM UNWINDFORMS...)")]
  876. public static Shelisp.Object Funwind_protect (L l, Shelisp.Object bodyform, params Shelisp.Object[] unwindforms)
  877. {
  878. Shelisp.Object rv = L.Qnil;
  879. try {
  880. return bodyform.Eval(l);
  881. }
  882. finally {
  883. foreach (var unwind in unwindforms)
  884. unwind.Eval (l);
  885. }
  886. }
  887. [LispBuiltin]
  888. public static Shelisp.Object Fgetenv (L l, Shelisp.Object variable)
  889. {
  890. return (Shelisp.String)(System.Environment.GetEnvironmentVariable ((string)(Shelisp.String)variable) ?? "");
  891. }
  892. [LispBuiltin]
  893. public Shelisp.Object Vload_path = L.string_array_to_list (new string[] {"/Users/toshok/src/shemacs/emacs/lisp", "/Users/toshok/src/shemacs/emacs/lisp/emacs-lisp" });
  894. [LispBuiltin]
  895. public static Shelisp.Object Feval_when_compile (L l, params Shelisp.Object[] forms)
  896. {
  897. Shelisp.Object rv = L.Qnil;
  898. foreach (var o in forms)
  899. rv = o.Eval(l);
  900. return rv;
  901. }
  902. [LispBuiltin]
  903. public static Shelisp.Object Fintern (L l, Shelisp.Object symname, [LispOptional] Shelisp.Object obarray)
  904. {
  905. if (L.NILP(obarray)) obarray = L.current_obarray;
  906. Shelisp.Symbol s = L.intern ((string)(Shelisp.String)symname, (Vector)obarray);
  907. return s;
  908. }
  909. [LispBuiltin]
  910. public static Shelisp.Object Fintern_soft (L l, Shelisp.Object symname, [LispOptional] Shelisp.Object obarray)
  911. {
  912. if (L.NILP(obarray)) obarray = L.current_obarray;
  913. Shelisp.Object s = L.intern_soft ((string)(Shelisp.String)symname, (Vector)obarray);
  914. return s;
  915. }
  916. [LispBuiltin]
  917. public static Shelisp.Object Funintern (L l, Shelisp.Object symname, [LispOptional] Shelisp.Object obarray)
  918. {
  919. if (L.NILP(obarray)) obarray = L.current_obarray;
  920. return Obarray.Unintern ((Vector)obarray, (string)(Shelisp.String)symname);
  921. }
  922. [LispBuiltin]
  923. public Shelisp.Object Vpurify_flag = L.Qt;
  924. [LispBuiltin]
  925. public static Shelisp.Object Fcalled_interactively_p (L l, Shelisp.Object kind = null)
  926. {
  927. Console.WriteLine ("called-interactively-p not implemented");
  928. return L.Qnil;
  929. }
  930. [LispBuiltin (DocString = @"Return the current local time, as a human-readable string.
  931. Programs can use this function to decode a time,
  932. since the number of columns in each field is fixed
  933. if the year is in the range 1000-9999.
  934. The format is `Sun Sep 16 01:03:52 1973'.
  935. However, see also the functions `decode-time' and `format-time-string'
  936. which provide a much more powerful and general facility.
  937. If SPECIFIED-TIME is given, it is a time to format instead of the
  938. current time. The argument should have the form (HIGH LOW . IGNORED).
  939. Thus, you can use times obtained from `current-time' and from
  940. `file-attributes'. SPECIFIED-TIME can also have the form (HIGH . LOW),
  941. but this is considered obsolete.")]
  942. public static Shelisp.Object Fcurrent_time_string (L l, [LispOptional] Shelisp.Object current_timestamp)
  943. {
  944. // XXX implement me...
  945. return (Shelisp.String)"hi";
  946. }
  947. [LispBuiltin (DocString = @"The value is a symbol indicating the type of operating system you are using.
  948. Special values:
  949. `gnu' compiled for a GNU Hurd system.
  950. `gnu/linux' compiled for a GNU/Linux system.
  951. `gnu/kfreebsd' compiled for a GNU system with a FreeBSD kernel.
  952. `darwin' compiled for Darwin (GNU-Darwin, Mac OS X, ...).
  953. `ms-dos' compiled as an MS-DOS application.
  954. `windows-nt' compiled as a native W32 application.
  955. `cygwin' compiled using the Cygwin library.
  956. Anything else (in Emacs 24.1, the possibilities are: aix, berkeley-unix,
  957. hpux, irix, usg-unix-v) indicates some sort of Unix system.")]
  958. public Shelisp.Object Vsystem_type = L.get_system_type();
  959. static Shelisp.Object get_system_type ()
  960. {
  961. // XXX punt wow now
  962. return L.intern ("darwin");
  963. }
  964. [LispBuiltin]
  965. public static int max_specpdl_size = 1300; /* 1000 is not enough for CEDET's c-by.el. */
  966. [LispBuiltin (DocString = @"*Non-nil means enter debugger if an error is signaled.
  967. Does not apply to errors handled by `condition-case' or those
  968. matched by `debug-ignored-errors'.
  969. If the value is a list, an error only means to enter the debugger
  970. if one of its condition symbols appears in the list.
  971. When you evaluate an expression interactively, this variable
  972. is temporarily non-nil if `eval-expression-debug-on-error' is non-nil.
  973. The command `toggle-debug-on-error' toggles this.
  974. See also the variable `debug-on-quit'.")]
  975. public static bool debug_on_error = false;
  976. [LispBuiltin (DocString = @"*List of errors for which the debugger should not be called.
  977. Each element may be a condition-name or a regexp that matches error messages.
  978. If any element applies to a given error, that error skips the debugger
  979. and just returns to top level.
  980. This overrides the variable `debug-on-error'.
  981. It does not apply to errors handled by `condition-case'.")]
  982. public static bool debug_ignored_errors = false;
  983. [LispBuiltin (DocString = @"*Non-nil means enter debugger if quit is signaled (C-g, for example).
  984. Does not apply if quit is handled by a `condition-case'.")]
  985. public static bool debug_on_quit = false;
  986. [LispBuiltin (DocString = @"Return result of expanding macros at top level of FORM.
  987. If FORM is not a macro call, it is returned unchanged.
  988. Otherwise, the macro is expanded and the expansion is considered
  989. in place of FORM. When a non-macro-call results, it is returned.
  990. The second optional arg ENVIRONMENT specifies an environment of macro
  991. definitions to shadow the loaded ones for use in file byte-compilation.")]
  992. public static Shelisp.Object Fmacroexpand (L l, Shelisp.Object form, Shelisp.Object environment)
  993. {
  994. /* With cleanups from Hallvard Furuseth. */
  995. Shelisp.Object expander, sym, def, tem;
  996. while (true) {
  997. /* Come back here each time we expand a macro call,
  998. in case it expands into another macro call. */
  999. if (!L.CONSP (form))
  1000. break;
  1001. /* Set SYM, give DEF and TEM right values in case SYM is not a symbol. */
  1002. def = sym = L.CAR (form);
  1003. tem = L.Qnil;
  1004. /* Trace symbols aliases to other symbols
  1005. until we get a symbol that is not an alias. */
  1006. while (def is Symbol) {
  1007. //QUIT;
  1008. sym = def;
  1009. tem = List.Fassq (l, sym, environment);
  1010. if (L.NILP (tem)) {
  1011. def = ((Symbol)sym).Function;
  1012. if (!def.LispEq (L.Qunbound))
  1013. continue;
  1014. }
  1015. break;
  1016. }
  1017. /* Right now TEM is the result from SYM in ENVIRONMENT,
  1018. and if TEM is nil then DEF is SYM's function definition. */
  1019. if (L.NILP (tem)) {
  1020. /* SYM is not mentioned in ENVIRONMENT.
  1021. Look at its function definition. */
  1022. if (def.LispEq (L.Qunbound) || !L.CONSP (def))
  1023. /* Not defined or definition not suitable. */
  1024. break;
  1025. if (L.Qautoload.LispEq(L.CAR (def))) {
  1026. /* Autoloading function: will it be a macro when loaded? */
  1027. tem = List.Fnth (l, new Number (4), def);
  1028. if (tem.LispEq (L.Qt) || tem.LispEq (L.Qmacro)) {
  1029. FileIO.DoAutoload (l, def, sym);
  1030. continue;
  1031. }
  1032. else
  1033. break;
  1034. }
  1035. else if (!L.Qmacro.LispEq (L.CAR (def)))
  1036. break;
  1037. else
  1038. expander = L.CDR (def);
  1039. }
  1040. else {
  1041. expander = L.CDR (tem);
  1042. if (L.NILP (expander))
  1043. break;
  1044. }
  1045. form = new List (new Shelisp.Object[] { expander, L.CDR(form) }).Eval(l);
  1046. }
  1047. return form;
  1048. }
  1049. [LispBuiltin (MinArgs = 1, Unevalled = true, DocString =
  1050. @"Return the argument, without evaluating it. `(quote x)' yields `x'.
  1051. Warning: `quote' does not construct its return value, but just returns
  1052. the value that was pre-constructed by the Lisp reader (see info node
  1053. `(elisp)Printed Representation').
  1054. This means that '(a . b) is not identical to (cons 'a 'b): the former
  1055. does not cons. Quoting should be reserved for constants that will
  1056. never be modified by side-effects, unless you like self-modifying code.
  1057. See the common pitfall in info node `(elisp)Rearrangement' for an example
  1058. of unexpected results when a quoted object is modified.
  1059. usage: (quote ARG) ")]
  1060. public static Shelisp.Object Fquote (L l, params Shelisp.Object[] args) {
  1061. #if not_ported
  1062. if (!L.NILP (L.CDR (args)))
  1063. xsignal2 (Qwrong_number_of_arguments, Qquote, Flength (args));
  1064. #endif
  1065. return args[0];
  1066. }
  1067. [LispBuiltin (DocString = "Return the argument unchanged")]
  1068. public static Shelisp.Object Fidentity (L l, Shelisp.Object arg)
  1069. {
  1070. return arg;
  1071. }
  1072. [LispBuiltin (DocString = @"*Limit on depth in `eval', `apply' and `funcall' before error.
  1073. This limit serves to catch infinite recursions for you before they cause
  1074. actual stack overflow in C, which would be fatal for Emacs.
  1075. You can safely make it considerably larger than its default value,
  1076. if that proves inconveniently small. However, if you increase it too far,
  1077. Emacs could overflow the real C stack, and crash.")]
  1078. public static int max_lisp_eval_depth = 1000;
  1079. public int eval_depth = 0;
  1080. }
  1081. }