PageRenderTime 42ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 1ms

/CatExecutor.cs

http://cat-language.googlecode.com/
C# | 602 lines | 517 code | 68 blank | 17 comment | 71 complexity | 792f87f47bf5294db8cb3c773570df25 MD5 | raw file
  1. /// Dedicated to the public domain by Christopher Diggins
  2. /// http://creativecommons.org/licenses/publicdomain/
  3. using System;
  4. using System.Reflection;
  5. using System.Reflection.Emit;
  6. using System.Collections;
  7. using System.Collections.Generic;
  8. using System.IO;
  9. using System.Diagnostics;
  10. using System.ComponentModel;
  11. using System.Text.RegularExpressions;
  12. namespace Cat
  13. {
  14. public interface INameLookup
  15. {
  16. Function Lookup(string s);
  17. Function ThrowingLookup(string s);
  18. }
  19. public class Executor : INameLookup
  20. {
  21. public TextReader input = Console.In;
  22. public TextWriter output = Console.Out;
  23. private Dictionary<string, Function> dictionary = new Dictionary<string, Function>();
  24. INameLookup otherNames;
  25. List<Object> stack = new List<Object>();
  26. public int testCount = 0;
  27. public bool bTrace = false;
  28. public Executor()
  29. {
  30. }
  31. public Executor(INameLookup other)
  32. {
  33. otherNames = other;
  34. }
  35. public Object Peek()
  36. {
  37. if (stack.Count == 0)
  38. throw new Exception("stack underflow occured");
  39. return stack[stack.Count - 1];
  40. }
  41. public void Push(Object o)
  42. {
  43. stack.Add(o);
  44. }
  45. public Object Pop()
  46. {
  47. Object o = Peek();
  48. stack.RemoveAt(stack.Count - 1);
  49. return o;
  50. }
  51. public Object PeekBelow(int n)
  52. {
  53. if (stack.Count <= n)
  54. throw new Exception("stack underflow occured");
  55. return stack[stack.Count - 1 - n];
  56. }
  57. public int Count()
  58. {
  59. return stack.Count;
  60. }
  61. public Object[] GetStackAsArray()
  62. {
  63. return stack.ToArray();
  64. }
  65. public void Dup()
  66. {
  67. if (Peek() is CatList)
  68. Push((Peek() as CatList).Clone());
  69. else
  70. Push(Peek());
  71. }
  72. public void Swap()
  73. {
  74. if (stack.Count < 2)
  75. throw new Exception("stack underflow occured");
  76. Object tmp = stack[stack.Count - 2];
  77. stack[stack.Count - 2] = stack[stack.Count - 1];
  78. stack[stack.Count - 1] = tmp;
  79. }
  80. public bool IsEmpty()
  81. {
  82. return Count() == 0;
  83. }
  84. public void Clear()
  85. {
  86. stack.Clear();
  87. }
  88. public string StackToString()
  89. {
  90. if (IsEmpty()) return "_empty_";
  91. string s = "";
  92. int nMax = 5;
  93. if (Count() > nMax) s = "...";
  94. if (Count() < nMax) nMax = Count();
  95. for (int i = nMax - 1; i >= 0; --i)
  96. {
  97. Object o = PeekBelow(i);
  98. s += Output.ObjectToString(o) + " ";
  99. }
  100. return s;
  101. }
  102. public T TypedPop<T>()
  103. {
  104. T result = TypedPeek<T>();
  105. Pop();
  106. return result;
  107. }
  108. public T TypedPeek<T>()
  109. {
  110. Object o = Peek();
  111. if (!(o is T))
  112. throw new Exception("Expected type " + typeof(T).Name + " but instead found " + o.GetType().Name);
  113. return (T)o;
  114. }
  115. public void PushInt(int n)
  116. {
  117. Push(n);
  118. }
  119. public void PushBool(bool x)
  120. {
  121. Push(x);
  122. }
  123. public void PushString(string x)
  124. {
  125. Push(x);
  126. }
  127. public void PushFxn(Function x)
  128. {
  129. Push(x);
  130. }
  131. public int PopInt()
  132. {
  133. return TypedPop<int>();
  134. }
  135. public bool PopBool()
  136. {
  137. return TypedPop<bool>();
  138. }
  139. public QuotedFunction PopFxn()
  140. {
  141. return TypedPop<QuotedFunction>();
  142. }
  143. public String PopString()
  144. {
  145. return TypedPop<String>();
  146. }
  147. public CatList PopList()
  148. {
  149. return TypedPop<CatList>();
  150. }
  151. public Function PeekFxn()
  152. {
  153. return TypedPeek<Function>();
  154. }
  155. public String PeekString()
  156. {
  157. return TypedPeek<String>();
  158. }
  159. public int PeekInt()
  160. {
  161. return TypedPeek<int>();
  162. }
  163. public bool PeekBool()
  164. {
  165. return TypedPeek<bool>();
  166. }
  167. public CatList PeekList()
  168. {
  169. return TypedPeek<CatList>();
  170. }
  171. public void Import()
  172. {
  173. LoadModule(PopString());
  174. }
  175. public void LoadModule(string s)
  176. {
  177. bool b1 = Config.gbVerboseInference;
  178. bool b2 = Config.gbShowInferredType;
  179. Config.gbVerboseInference = Config.gbVerboseInferenceOnLoad;
  180. Config.gbShowInferredType = false;
  181. try
  182. {
  183. Execute(Util.FileToString(s));
  184. }
  185. catch (Exception e)
  186. {
  187. Output.WriteLine("Failed to load \"" + s + "\" with message: " + e.Message);
  188. }
  189. Config.gbVerboseInference = b1;
  190. Config.gbShowInferredType = b2;
  191. }
  192. public void Execute(string s)
  193. {
  194. List<CatAstNode> nodes = CatParser.Parse(s + "\n");
  195. Execute(nodes);
  196. }
  197. public void OutputStack()
  198. {
  199. Output.WriteLine("stack: " + StackToString());
  200. }
  201. public Function LiteralToFunction(string name, AstLiteral literal)
  202. {
  203. switch (literal.GetLabel())
  204. {
  205. case AstLabel.Int:
  206. {
  207. AstInt tmp = literal as AstInt;
  208. return new PushInt(tmp.GetValue());
  209. }
  210. case AstLabel.Bin:
  211. {
  212. AstBin tmp = literal as AstBin;
  213. return new PushInt(tmp.GetValue());
  214. }
  215. case AstLabel.Char:
  216. {
  217. AstChar tmp = literal as AstChar;
  218. return new PushValue<char>(tmp.GetValue());
  219. }
  220. case AstLabel.String:
  221. {
  222. AstString tmp = literal as AstString;
  223. return new PushValue<string>(tmp.GetValue());
  224. }
  225. case AstLabel.Float:
  226. {
  227. AstFloat tmp = literal as AstFloat;
  228. return new PushValue<double>(tmp.GetValue());
  229. }
  230. case AstLabel.Hex:
  231. {
  232. AstHex tmp = literal as AstHex;
  233. return new PushInt(tmp.GetValue());
  234. }
  235. case AstLabel.Quote:
  236. {
  237. AstQuote tmp = literal as AstQuote;
  238. CatExpr fxns = NodesToFxns(name, tmp.GetTerms());
  239. if (Config.gbOptimizeQuotations)
  240. MetaCat.ApplyMacros(this, fxns);
  241. return new PushFunction(fxns);
  242. }
  243. case AstLabel.Lambda:
  244. {
  245. AstLambda tmp = literal as AstLambda;
  246. CatLambdaConverter.Convert(tmp);
  247. CatExpr fxns = NodesToFxns(name, tmp.GetTerms());
  248. if (Config.gbOptimizeLambdas)
  249. MetaCat.ApplyMacros(this, fxns);
  250. return new PushFunction(fxns);
  251. }
  252. default:
  253. throw new Exception("unhandled literal " + literal.ToString());
  254. }
  255. }
  256. void Trace(string s)
  257. {
  258. if (bTrace) Output.WriteLine("trace: " + s);
  259. }
  260. /// <summary>
  261. /// This function is optimized to handle tail-calls with increasing the stack size.
  262. /// </summary>
  263. /// <param name="fxns"></param>
  264. public void Execute(CatExpr fxns)
  265. {
  266. int i = 0;
  267. while (i < fxns.Count)
  268. {
  269. Function f = fxns[i];
  270. // Check if this is a tail call
  271. // if so then we are going to avoid creating a new stack frame
  272. if (i == fxns.Count - 1 && f.GetSubFxns() != null)
  273. {
  274. Trace("tail-call of '" + f.GetName() + "' function");
  275. fxns = f.GetSubFxns();
  276. i = 0;
  277. }
  278. else if (i == fxns.Count - 1 && f is Primitives.If)
  279. {
  280. Trace("tail-call of 'if' function");
  281. QuotedFunction onfalse = PopFxn();
  282. QuotedFunction ontrue = PopFxn();
  283. if (PopBool())
  284. fxns = ontrue.GetSubFxns(); else
  285. fxns = onfalse.GetSubFxns();
  286. i = 0;
  287. }
  288. else if (i == fxns.Count - 1 && f is Primitives.ApplyFxn)
  289. {
  290. Trace("tail-call of 'apply' function");
  291. QuotedFunction q = PopFxn();
  292. fxns = q.GetSubFxns();
  293. i = 0;
  294. }
  295. else
  296. {
  297. Trace(f.ToString());
  298. f.Eval(this);
  299. ++i;
  300. }
  301. }
  302. }
  303. public CatExpr NodesToFxns(string name, List<CatAstNode> nodes)
  304. {
  305. CatExpr result = new CatExpr();
  306. for (int i = 0; i < nodes.Count; ++i)
  307. {
  308. CatAstNode node = nodes[i];
  309. if (node.GetLabel().Equals(AstLabel.Name))
  310. {
  311. string s = node.ToString();
  312. if (s.Equals(name))
  313. result.Add(new SelfFunction(name));
  314. else
  315. result.Add(ThrowingLookup(s));
  316. }
  317. else if (node is AstLiteral)
  318. {
  319. result.Add(LiteralToFunction(name, node as AstLiteral));
  320. }
  321. else if (node is AstDef)
  322. {
  323. MakeFunction(node as AstDef);
  324. }
  325. else if (node is AstMacro)
  326. {
  327. MetaCat.AddMacro(node as AstMacro);
  328. }
  329. else
  330. {
  331. throw new Exception("unable to convert node to function: " + node.ToString());
  332. }
  333. }
  334. return result;
  335. }
  336. public void Execute(List<CatAstNode> nodes)
  337. {
  338. Execute(NodesToFxns("self", nodes));
  339. }
  340. public void ClearTo(int n)
  341. {
  342. while (Count() > n)
  343. Pop();
  344. }
  345. public CatList GetStackAsList()
  346. {
  347. return new CatList(stack);
  348. }
  349. #region dictionary management
  350. public void RegisterType(Type t)
  351. {
  352. foreach (Type memberType in t.GetNestedTypes())
  353. {
  354. // Is is it a function object
  355. if (typeof(Function).IsAssignableFrom(memberType))
  356. {
  357. ConstructorInfo ci = memberType.GetConstructor(new Type[] { });
  358. Object o = ci.Invoke(null);
  359. if (!(o is Function))
  360. throw new Exception("Expected only function objects in " + t.ToString());
  361. Function f = o as Function;
  362. AddFunction(f);
  363. }
  364. else
  365. {
  366. RegisterType(memberType);
  367. }
  368. }
  369. foreach (MemberInfo mi in t.GetMembers())
  370. {
  371. if (mi is MethodInfo)
  372. {
  373. MethodInfo meth = mi as MethodInfo;
  374. if (meth.IsStatic) {
  375. Function f = AddMethod(null, meth);
  376. if (f != null)
  377. f.msTags = "level2";
  378. }
  379. }
  380. }
  381. }
  382. /// <summary>
  383. /// Creates an ObjectBoundMethod for each public function in the object
  384. /// </summary>
  385. /// <param name="o"></param>
  386. public void RegisterObject(Object o)
  387. {
  388. foreach (MemberInfo mi in o.GetType().GetMembers())
  389. {
  390. if (mi is MethodInfo)
  391. {
  392. MethodInfo meth = mi as MethodInfo;
  393. AddMethod(o, meth);
  394. }
  395. }
  396. }
  397. #region INameLookup implementation
  398. public Function Lookup(string s)
  399. {
  400. if (s.Length < 1)
  401. throw new Exception("trying to lookup a function with no name");
  402. if (dictionary.ContainsKey(s))
  403. return dictionary[s];
  404. if (otherNames != null)
  405. return otherNames.Lookup(s);
  406. return null;
  407. }
  408. public Function ThrowingLookup(string s)
  409. {
  410. Function f = Lookup(s);
  411. if (f == null)
  412. throw new Exception("could not find function " + s);
  413. return f;
  414. }
  415. #endregion
  416. /// <summary>
  417. /// Methods allow overloading of function definitions.
  418. /// </summary>
  419. public Function AddMethod(Object o, MethodInfo mi)
  420. {
  421. // Does not add public methods.
  422. if (!mi.IsPublic)
  423. return null;
  424. if (mi.IsStatic)
  425. o = null;
  426. Method f = new Method(o, mi);
  427. AddFunction(f);
  428. return f;
  429. }
  430. public List<Function> GetAllFunctions()
  431. {
  432. List<Function> fxns = new List<Function>(dictionary.Values);
  433. fxns.Sort(delegate(Function x, Function y) {
  434. return x.GetName().CompareTo(y.GetName());
  435. });
  436. return fxns;
  437. }
  438. public Dictionary<string, List<Function>> GetFunctionsByTag()
  439. {
  440. Dictionary<string, List<Function> > ret = new Dictionary<string, List<Function>>();
  441. foreach (Function f in GetAllFunctions())
  442. {
  443. foreach (string s in f.GetTags())
  444. {
  445. string s2 = s.Trim();
  446. if (s.Length > 0)
  447. {
  448. if (!ret.ContainsKey(s2))
  449. ret.Add(s2, new List<Function>());
  450. ret[s2].Add(f);
  451. }
  452. }
  453. }
  454. return ret;
  455. }
  456. public bool TestFunction(Function f)
  457. {
  458. bool bRet = true;
  459. testCount += 1;
  460. CatMetaDataBlock md = f.GetMetaData();
  461. if (md != null)
  462. {
  463. List<CatMetaData> tests = md.FindAll("test");
  464. foreach (CatMetaData test in tests)
  465. {
  466. CatMetaData input = test.Find("in");
  467. CatMetaData output = test.Find("out");
  468. if (input == null || output == null)
  469. {
  470. Output.WriteLine("ill-formed test in " + f.GetName());
  471. return false;
  472. }
  473. try
  474. {
  475. Executor aux = new Executor(this);
  476. aux.Execute(input.GetContent());
  477. CatList listInput = aux.GetStackAsList();
  478. aux.Clear();
  479. aux.Execute(output.GetContent());
  480. CatList listOutput = aux.GetStackAsList();
  481. aux.Clear();
  482. if (!listInput.Equals(listOutput))
  483. {
  484. Output.WriteLine("failed test for instruction " + f.GetName());
  485. Output.WriteLine("test input program = " + input.GetContent());
  486. Output.WriteLine("test output program = " + output.GetContent());
  487. Output.WriteLine("input program result = " + listInput.ToString());
  488. Output.WriteLine("output program result = " + listOutput.ToString());
  489. bRet = false;
  490. }
  491. }
  492. catch (Exception e)
  493. {
  494. Output.WriteLine("failed test for instruction " + f.GetName());
  495. Output.WriteLine("exception occured: " + e.Message);
  496. bRet = false;
  497. }
  498. }
  499. }
  500. return bRet;
  501. }
  502. public Function MakeFunction(AstDef def)
  503. {
  504. bool bLambda = def.mParams.Count > 0 || def.mLocals.Count > 0;
  505. if (bLambda)
  506. CatLambdaConverter.Convert(def);
  507. CatExpr fxns = NodesToFxns(def.mName, def.mTerms);
  508. Function ret = new DefinedFunction(def.mName, fxns);
  509. if (def.mpMetaData != null) {
  510. ret.SetMetaData(new CatMetaDataBlock(def.mpMetaData));
  511. }
  512. if (bLambda && Config.gbOptimizeLambdas)
  513. MetaCat.ApplyMacros(this, fxns);
  514. AddFunction(ret);
  515. return ret;
  516. }
  517. public Function AddFunction(Function f)
  518. {
  519. string s = f.GetName();
  520. if (dictionary.ContainsKey(s))
  521. {
  522. if (!Config.gbAllowRedefines)
  523. throw new Exception("can not overload functions " + s);
  524. dictionary[s] = f;
  525. }
  526. else
  527. {
  528. dictionary.Add(s, f);
  529. }
  530. return f;
  531. }
  532. #endregion
  533. }
  534. }