Advertisement
lbruder

org.lb.Scheme.cs version 2013-01-11

Jan 13th, 2013
68
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 56.78 KB | None | 0 0
  1. // org.lb.Scheme.cs version 2013-01-11
  2. // A Scheme subset compiler and virtual machine in C#
  3. // Features: Tail calls, CL style macros
  4. // Copyright (c) 2013, Leif Bruder <leifbruder@gmail.com>
  5. //
  6. // Permission to use, copy, modify, and/or distribute this software for any
  7. // purpose with or without fee is hereby granted, provided that the above
  8. // copyright notice and this permission notice appear in all copies.
  9. //
  10. // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  11. // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  12. // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  13. // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  14. // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  15. // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  16. // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  17.  
  18. using System;
  19. using System.Collections;
  20. using System.Collections.Generic;
  21. using System.Globalization;
  22. using System.IO;
  23. using System.Linq;
  24. using System.Text;
  25. using System.Threading;
  26.  
  27. namespace org.lb.Scheme
  28. {
  29.     public interface VirtualMachine
  30.     {
  31.         int ProgramSize { get; }
  32.         void EmitLabel(string label);
  33.         void EmitArgsToValue();
  34.         void EmitBranchLabel(string label);
  35.         void EmitCall();
  36.         void EmitContinue();
  37.         void EmitDefineVariable(Symbol variable);
  38.         void EmitGetVariable(Symbol variable);
  39.         void EmitGotoLabel(string label);
  40.         void EmitInitArgs();
  41.         void EmitLdConst(object value);
  42.         void EmitLdCont(string label);
  43.         void EmitMakeClosure(string name, string label, bool hasRestParameter, Symbol[] parameterNames);
  44.         void EmitPushParam();
  45.         void EmitRestoreRegisters();
  46.         void EmitSaveRegisters();
  47.         void EmitSetVariable(Symbol variable);
  48.         void EmitValueToArgs();
  49.         string MakeLabel();
  50.         void SetVariable(string name, object value);
  51.         void SetVariable(Symbol name, object value);
  52.         bool HasVariable(Symbol name);
  53.         object GetVariable(Symbol name);
  54.         object Run(int startingPC = 0);
  55.     }
  56.  
  57.  
  58.     public sealed class VirtualMachineException : Exception { internal VirtualMachineException(string message) : base(message) { } }
  59.     public sealed class SchemeException : Exception { internal SchemeException(string message) : base(message) { } }
  60.     public sealed class SchemeError : Exception { internal SchemeError(Pair parameters) : base(new Writer().Write(parameters)) { } }
  61.  
  62.     public sealed class Pair : IEnumerable<object>
  63.     {
  64.         public object First;
  65.         public object Second;
  66.  
  67.         public Pair(object first, object second) { First = first; Second = second; }
  68.         IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
  69.  
  70.         public IEnumerator<object> GetEnumerator()
  71.         {
  72.             Pair i = this;
  73.             while (true)
  74.             {
  75.                 yield return i.First;
  76.                 if (i.Second == null) yield break;
  77.                 if (!(i.Second is Pair))
  78.                 {
  79.                     yield return i.Second;
  80.                     yield break;
  81.                 }
  82.                 i = (Pair)i.Second;
  83.             }
  84.         }
  85.  
  86.         public static Pair FromEnumerable(IEnumerable values)
  87.         {
  88.             Pair ret = null;
  89.             Pair current = null;
  90.             foreach (object o in values)
  91.             {
  92.                 var newPair = new Pair(o, null);
  93.                 if (current == null)
  94.                 {
  95.                     ret = current = newPair;
  96.                 }
  97.                 else
  98.                 {
  99.                     current.Second = newPair;
  100.                     current = newPair;
  101.                 }
  102.             }
  103.             return ret;
  104.         }
  105.  
  106.         public bool IsDottedList()
  107.         {
  108.             Pair i = this;
  109.             while (true)
  110.             {
  111.                 if (i.Second == null) return false;
  112.                 if (!(i.Second is Pair)) return true;
  113.                 i = (Pair)i.Second;
  114.             }
  115.         }
  116.     }
  117.  
  118.     public sealed class Symbol
  119.     {
  120.         private readonly string value;
  121.         private readonly int hashCode;
  122.  
  123.         private Symbol(string value) { this.value = value; this.hashCode = value.GetHashCode(); }
  124.         public override string ToString() { return value; }
  125.  
  126.         private static readonly Dictionary<string, Symbol> cache = new Dictionary<string, Symbol>();
  127.         public static Symbol FromString(string symbol)
  128.         {
  129.             lock (cache)
  130.             {
  131.                 if (cache.ContainsKey(symbol)) return cache[symbol];
  132.                 Symbol ret = new Symbol(symbol);
  133.                 cache[symbol] = ret;
  134.                 return ret;
  135.             }
  136.         }
  137.  
  138.         public override bool Equals(object obj) { return this == obj; }
  139.         public override int GetHashCode() { return hashCode; }
  140.     }
  141.  
  142.     internal sealed class Environment
  143.     {
  144.         private readonly Dictionary<Symbol, object> values = new Dictionary<Symbol, object>();
  145.         private readonly Environment parent;
  146.  
  147.         public Environment(Environment parent = null)
  148.         {
  149.             this.parent = parent;
  150.         }
  151.  
  152.         public object Get(Symbol variable)
  153.         {
  154.             object ret;
  155.             if (values.TryGetValue(variable, out ret)) return ret;
  156.             if (parent != null) return parent.Get(variable);
  157.             throw new VirtualMachineException("Unknown variable '" + variable + "'");
  158.         }
  159.  
  160.         public void Define(Symbol variable, object value)
  161.         {
  162.             values[variable] = value;
  163.         }
  164.  
  165.         public void Set(Symbol variable, object value)
  166.         {
  167.             if (values.ContainsKey(variable)) values[variable] = value;
  168.             else if (parent != null) parent.Set(variable, value);
  169.             else throw new VirtualMachineException("Unknown variable '" + variable + "'");
  170.         }
  171.  
  172.         public bool HasVariable(Symbol name)
  173.         {
  174.             return values.ContainsKey(name);
  175.         }
  176.     }
  177.  
  178.     public sealed class RegisterMachine : VirtualMachine
  179.     {
  180.         private int programCounter;
  181.         private Environment environmentRegister;
  182.         private int continueRegister;
  183.         private object valueRegister;
  184.         private object argumentsRegister;
  185.  
  186.         private readonly List<int> gotosWithoutLabelValue = new List<int>();
  187.         private readonly Dictionary<string, int> labelPositions = new Dictionary<string, int>();
  188.         private readonly List<Instruction> Instructions = new List<Instruction>();
  189.         public int ProgramSize { get { return Instructions.Count; } }
  190.  
  191.         private readonly Func<object, bool> IsTrue;
  192.         private readonly Stack<object> stack = new Stack<object>();
  193.         private readonly Environment globalEnvironment = new Environment();
  194.  
  195.         public RegisterMachine(Func<object, bool> isTrue)
  196.         {
  197.             IsTrue = isTrue;
  198.         }
  199.  
  200.         private void PerformArgsToValue() { valueRegister = argumentsRegister; programCounter++; }
  201.         private void PerformBranchLabel(int target) { programCounter = IsTrue(valueRegister) ? target : programCounter + 1; }
  202.         private void PerformContinue() { programCounter = continueRegister; }
  203.         private void PerformDefineVariable(Symbol variable) { environmentRegister.Define(variable, valueRegister); programCounter++; }
  204.         private void PerformGetVariable(Symbol variable) { valueRegister = environmentRegister.Get(variable); programCounter++; }
  205.         private void PerformGotoLabel(int target) { programCounter = target; }
  206.         private void PerformInitArgs() { argumentsRegister = null; programCounter++; }
  207.         private void PerformLdConst(object value) { valueRegister = value; programCounter++; }
  208.         private void PerformLdCont(int target) { continueRegister = target; programCounter++; }
  209.         private void PerformPushParam() { argumentsRegister = new Pair(valueRegister, argumentsRegister); programCounter++; }
  210.         private void PerformRestoreRegisters() { environmentRegister = (Environment)stack.Pop(); continueRegister = (int)stack.Pop(); argumentsRegister = stack.Pop(); programCounter++; }
  211.         private void PerformSaveRegisters() { stack.Push(argumentsRegister); stack.Push(continueRegister); stack.Push(environmentRegister); programCounter++; }
  212.         private void PerformSetVariable(Symbol variable) { environmentRegister.Set(variable, valueRegister); programCounter++; }
  213.         private void PerformMakeClosure(string name, int target, bool hasRestParameter, Symbol[] parameterNames) { valueRegister = new Closure(name, environmentRegister, target, parameterNames, hasRestParameter); programCounter++; }
  214.         private void PerformValueToArgs() { argumentsRegister = valueRegister; programCounter++; }
  215.  
  216.         private void PerformCall()
  217.         {
  218.             object[] args;
  219.             if (argumentsRegister == null) args = new object[0];
  220.             else if (argumentsRegister is Pair) args = ((Pair)argumentsRegister).ToArray();
  221.             else throw new VirtualMachineException("Invalid function application: Expected list of arguments, got " + argumentsRegister.GetType());
  222.  
  223.             argumentsRegister = null;
  224.  
  225.             if (valueRegister is Func<object[], object>)
  226.             {
  227.                 valueRegister = ((Func<object[], object>)valueRegister)(args);
  228.                 programCounter = continueRegister;
  229.                 return;
  230.             }
  231.  
  232.             if (valueRegister is Closure)
  233.             {
  234.                 var closure = (Closure)valueRegister;
  235.                 var env = new Environment((closure).Captured);
  236.  
  237.                 if (closure.HasRestParameter)
  238.                 {
  239.                     if (closure.ParameterNames.Length - 1 > args.Length)
  240.                         throw new VirtualMachineException("Invalid parameter count in call to '" + closure.Name + "': Expected " + (closure.ParameterNames.Length - 1) + " or more, got " + args.Length);
  241.                     for (int i = 0; i < closure.ParameterNames.Length - 1; ++i) env.Define(closure.ParameterNames[i], args[i]);
  242.                     env.Define(closure.ParameterNames.Last(), Pair.FromEnumerable(args.Skip(closure.ParameterNames.Length - 1)));
  243.                 }
  244.                 else
  245.                 {
  246.                     if (closure.ParameterNames.Length != args.Length)
  247.                         throw new VirtualMachineException("Invalid parameter count in call to '" + closure.Name + "': Expected " + closure.ParameterNames.Length + ", got " + args.Length);
  248.                     for (int i = 0; i < closure.ParameterNames.Length; ++i) env.Define(closure.ParameterNames[i], args[i]);
  249.                 }
  250.  
  251.                 environmentRegister = env;
  252.                 programCounter = closure.PC;
  253.                 return;
  254.             }
  255.  
  256.             throw new VirtualMachineException("Invalid CALL target");
  257.         }
  258.  
  259.         public void EmitLabel(string label)
  260.         {
  261.             if (labelPositions.ContainsKey(label)) throw new VirtualMachineException("Label defined twice: '" + label + "'");
  262.             int targetPC = Instructions.Count;
  263.             labelPositions[label] = targetPC;
  264.  
  265.             for (int i = 0; i < gotosWithoutLabelValue.Count; ++i)
  266.             {
  267.                 if (Instructions[gotosWithoutLabelValue[i]].Label == label)
  268.                 {
  269.                     Instructions[gotosWithoutLabelValue[i]].LabelTarget = targetPC;
  270.                     gotosWithoutLabelValue.RemoveAt(i);
  271.                     i--;
  272.                 }
  273.             }
  274.         }
  275.  
  276.         public void EmitArgsToValue() { Emit(new LambdaInstruction(PerformArgsToValue)); }
  277.         public void EmitBranchLabel(string label) { Emit(new BranchLabelInstruction(label)); }
  278.         public void EmitCall() { Emit(new LambdaInstruction(PerformCall)); }
  279.         public void EmitContinue() { Emit(new LambdaInstruction(PerformContinue)); }
  280.         public void EmitDefineVariable(Symbol variable) { Emit(new LambdaInstruction(() => PerformDefineVariable(variable))); }
  281.         public void EmitGetVariable(Symbol variable) { Emit(new LambdaInstruction(() => PerformGetVariable(variable))); }
  282.         public void EmitGotoLabel(string label) { Emit(new GotoLabelInstruction(label)); }
  283.         public void EmitInitArgs() { Emit(new LambdaInstruction(PerformInitArgs)); }
  284.         public void EmitLdConst(object value) { Emit(new LambdaInstruction(() => PerformLdConst(value))); }
  285.         public void EmitLdCont(string label) { Emit(new LdContInstruction(label)); }
  286.         public void EmitMakeClosure(string name, string label, bool hasRestParameter, Symbol[] parameterNames) { Emit(new MakeClosureInstruction(name, label, hasRestParameter, parameterNames)); }
  287.         public void EmitPushParam() { Emit(new LambdaInstruction(PerformPushParam)); }
  288.         public void EmitRestoreRegisters() { Emit(new LambdaInstruction(PerformRestoreRegisters)); }
  289.         public void EmitSaveRegisters() { Emit(new LambdaInstruction(PerformSaveRegisters)); }
  290.         public void EmitSetVariable(Symbol variable) { Emit(new LambdaInstruction(() => PerformSetVariable(variable))); }
  291.         public void EmitValueToArgs() { Emit(new LambdaInstruction(PerformValueToArgs)); }
  292.  
  293.         private void Emit(Instruction value)
  294.         {
  295.             if (value.Label != null)
  296.             {
  297.                 if (labelPositions.ContainsKey(value.Label)) value.LabelTarget = labelPositions[value.Label];
  298.                 else gotosWithoutLabelValue.Add(Instructions.Count);
  299.             }
  300.             Instructions.Add(value);
  301.         }
  302.  
  303.         private void AssertRunnable()
  304.         {
  305.             if (gotosWithoutLabelValue.Any()) throw new VirtualMachineException("Invalid program: Jump targets without valid label");
  306.         }
  307.  
  308.         private int nextLabelNo;
  309.         public string MakeLabel()
  310.         {
  311.             return "##label##" + nextLabelNo++ + "##";
  312.         }
  313.  
  314.         public void SetVariable(string name, object value) { globalEnvironment.Define(Symbol.FromString(name), value); }
  315.         public void SetVariable(Symbol name, object value) { globalEnvironment.Define(name, value); }
  316.         public bool HasVariable(Symbol name) { return globalEnvironment.HasVariable(name); }
  317.         public object GetVariable(Symbol name) { return globalEnvironment.Get(name); }
  318.  
  319.         public object Run(int startingPC = 0)
  320.         {
  321.             AssertRunnable();
  322.  
  323.             programCounter = startingPC;
  324.             environmentRegister = globalEnvironment;
  325.             continueRegister = -1;
  326.             valueRegister = null;
  327.             argumentsRegister = null;
  328.             stack.Clear();
  329.  
  330.             while (programCounter < Instructions.Count)
  331.             {
  332.                 Instructions[programCounter].Execute(this);
  333.                 if (programCounter == -1) break;
  334.             }
  335.  
  336.             if (stack.Any()) throw new VirtualMachineException("Bad program: Stack not empty after last instruction");
  337.             if (argumentsRegister != null) throw new VirtualMachineException("Bad program: Arguments register not empty after last instruction");
  338.             return valueRegister;
  339.         }
  340.  
  341.         public static bool IsCallable(object value)
  342.         {
  343.             return value is Func<object[], object> || value is Closure;
  344.         }
  345.  
  346.         private sealed class Closure
  347.         {
  348.             public readonly Environment Captured;
  349.             public readonly int PC;
  350.             public readonly Symbol[] ParameterNames;
  351.             public readonly bool HasRestParameter;
  352.             public readonly string Name;
  353.  
  354.             public Closure(string name, Environment captured, int pc, Symbol[] parameterNames, bool hasRestParameter)
  355.             {
  356.                 Name = name;
  357.                 Captured = captured;
  358.                 PC = pc;
  359.                 ParameterNames = parameterNames;
  360.                 HasRestParameter = hasRestParameter;
  361.             }
  362.  
  363.             public override string ToString() { return "<Compiled function " + Name + ">"; }
  364.         }
  365.  
  366.         private class Instruction
  367.         {
  368.             public readonly string Label;
  369.             public int LabelTarget;
  370.             protected Instruction(string label) { Label = label; }
  371.             public virtual void Execute(RegisterMachine machine) { }
  372.         }
  373.  
  374.         private sealed class LambdaInstruction : Instruction
  375.         {
  376.             private readonly Action f;
  377.             public LambdaInstruction(Action f) : base(null) { this.f = f; }
  378.             public override void Execute(RegisterMachine machine) { f(); }
  379.         }
  380.  
  381.         private sealed class BranchLabelInstruction : Instruction
  382.         {
  383.             public BranchLabelInstruction(string label) : base(label) { }
  384.             public override void Execute(RegisterMachine machine) { machine.PerformBranchLabel(LabelTarget); }
  385.         }
  386.  
  387.         private sealed class GotoLabelInstruction : Instruction
  388.         {
  389.             public GotoLabelInstruction(string label) : base(label) { }
  390.             public override void Execute(RegisterMachine machine) { machine.PerformGotoLabel(LabelTarget); }
  391.         }
  392.  
  393.         private sealed class LdContInstruction : Instruction
  394.         {
  395.             public LdContInstruction(string label) : base(label) { }
  396.             public override void Execute(RegisterMachine machine) { machine.PerformLdCont(LabelTarget); }
  397.         }
  398.  
  399.         private sealed class MakeClosureInstruction : Instruction
  400.         {
  401.             private readonly string Name;
  402.             private readonly bool HasRestParameter;
  403.             private readonly Symbol[] ParameterNames;
  404.             public MakeClosureInstruction(string name, string label, bool hasRestParameter, Symbol[] parameterNames) : base(label) { Name = name; HasRestParameter = hasRestParameter; ParameterNames = parameterNames; }
  405.             public override void Execute(RegisterMachine machine) { machine.PerformMakeClosure(Name, LabelTarget, HasRestParameter, ParameterNames); }
  406.         }
  407.     }
  408.  
  409.     public sealed class Reader
  410.     {
  411.         public sealed class EofObject
  412.         {
  413.             public static readonly EofObject Instance = new EofObject();
  414.             private EofObject() { }
  415.         }
  416.  
  417.         private readonly TextReader input;
  418.         private readonly Symbol dot = Symbol.FromString(".");
  419.         private readonly Symbol listEnd = Symbol.FromString(")");
  420.  
  421.         public Reader(TextReader input)
  422.         {
  423.             this.input = input;
  424.         }
  425.  
  426.         public object Read(bool throwOnEof = true)
  427.         {
  428.             SkipWhiteSpace();
  429.             if (IsEof())
  430.             {
  431.                 if (throwOnEof) throw new EndOfStreamException();
  432.                 return EofObject.Instance;
  433.             }
  434.             switch (PeekChar())
  435.             {
  436.                 case ';': SkipComment(); return Read(throwOnEof);
  437.                 case '\'': ReadChar(); return new Pair(Symbol.FromString("quote"), new Pair(Read(), null));
  438.                 case '(': return ReadList();
  439.                 case '"': return ReadString();
  440.                 case '#': return ReadSpecial();
  441.                 default: return ReadSymbolOrNumber();
  442.             }
  443.         }
  444.  
  445.         private void SkipWhiteSpace()
  446.         {
  447.             while (!IsEof() && char.IsWhiteSpace(PeekChar()))
  448.                 ReadChar();
  449.         }
  450.  
  451.         private void SkipComment()
  452.         {
  453.             while (!IsEof() && PeekChar() != '\n')
  454.                 ReadChar();
  455.         }
  456.  
  457.         private bool IsEof()
  458.         {
  459.             return input.Peek() == -1;
  460.         }
  461.  
  462.         private char PeekChar()
  463.         {
  464.             AssertNotEof();
  465.             return (char)input.Peek();
  466.         }
  467.  
  468.         private char ReadChar()
  469.         {
  470.             AssertNotEof();
  471.             return (char)input.Read();
  472.         }
  473.  
  474.         private void AssertNotEof()
  475.         {
  476.             if (IsEof())
  477.                 throw new EndOfStreamException();
  478.         }
  479.  
  480.         private object ReadList()
  481.         {
  482.             ReadChar(); // Opening parenthesis
  483.             Pair ret = null;
  484.             Pair current = null;
  485.             while (true)
  486.             {
  487.                 object o = Read();
  488.                 if (o == listEnd) return ret; // Closing parenthesis
  489.                 if (o == dot)
  490.                 {
  491.                     if (current == null) throw new SchemeException("Invalid dotted list");
  492.                     o = Read();
  493.                     current.Second = o;
  494.                     if (Read() != listEnd) throw new SchemeException("Invalid dotted list");
  495.                     return ret;
  496.                 }
  497.  
  498.                 var newPair = new Pair(o, null);
  499.                 if (current == null)
  500.                 {
  501.                     ret = current = newPair;
  502.                 }
  503.                 else
  504.                 {
  505.                     current.Second = newPair;
  506.                     current = newPair;
  507.                 }
  508.             }
  509.         }
  510.  
  511.         private object ReadString()
  512.         {
  513.             ReadChar(); // Opening quote
  514.             var sb = new StringBuilder();
  515.             while (PeekChar() != '"')
  516.             {
  517.                 char c = ReadChar();
  518.                 if (c == '\\')
  519.                 {
  520.                     c = ReadChar();
  521.                     if (c == 'n') c = '\n';
  522.                     if (c == 'r') c = '\r';
  523.                     if (c == 't') c = '\t';
  524.                 }
  525.                 sb.Append(c);
  526.             }
  527.             ReadChar(); // Closing quote
  528.             return sb.ToString();
  529.         }
  530.  
  531.         private object ReadSpecial()
  532.         {
  533.             ReadChar(); // #
  534.             if (PeekChar() != '\\') return ReadSymbolOrNumber("#");
  535.             ReadChar();
  536.             return ReadCharacter();
  537.         }
  538.  
  539.         private object ReadCharacter()
  540.         {
  541.             char c = ReadChar();
  542.             if (!char.IsLetter(c)) return c;
  543.  
  544.             var sb = new StringBuilder();
  545.             sb.Append(c);
  546.             while (!IsEof() && PeekChar() != ')' && !char.IsWhiteSpace(PeekChar())) sb.Append(ReadChar());
  547.             string name = sb.ToString();
  548.             switch (name)
  549.             {
  550.                 case "newline": return '\n';
  551.                 case "space": return ' ';
  552.                 case "tab": return '\t';
  553.                 default:
  554.                     if (name.Length == 1) return name[0];
  555.                     throw new SchemeException("Invalid character name: \\" + name);
  556.             }
  557.         }
  558.  
  559.         private object ReadSymbolOrNumber(string init = "")
  560.         {
  561.             if (init == "" && PeekChar() == ')')
  562.             {
  563.                 ReadChar();
  564.                 return listEnd;
  565.             }
  566.  
  567.             var sb = new StringBuilder(init);
  568.             while (!IsEof() && PeekChar() != ')' && !char.IsWhiteSpace(PeekChar())) sb.Append(ReadChar());
  569.             string symbol = sb.ToString();
  570.  
  571.             int i; if (int.TryParse(symbol, out i)) return i;
  572.             double d; if (double.TryParse(symbol, NumberStyles.Any, CultureInfo.InvariantCulture, out d)) return d;
  573.             if (symbol == "#t") return true;
  574.             if (symbol == "#f") return false;
  575.             if (symbol == "nil") return null;
  576.             return Symbol.FromString(symbol);
  577.         }
  578.     }
  579.  
  580.     public sealed class Writer
  581.     {
  582.         public string Write(object o)
  583.         {
  584.             if (o == null) return "nil";
  585.             if (o is bool) return (bool)o ? "#t" : "#f";
  586.             if (o is char) return WriteChar((char)o);
  587.             if (o is int) return ((int)o).ToString(CultureInfo.InvariantCulture);
  588.             if (o is double) return ((double)o).ToString(CultureInfo.InvariantCulture);
  589.             if (o is string) return "\"" + ((string)o).Replace("\\", "\\\\").Replace("\n", "\\n").Replace("\r", "\\r").Replace("\t", "\\t") + "\"";
  590.             if (o is Symbol) return o.ToString();
  591.             if (o is Pair) return WritePair((Pair)o);
  592.             if (o is IEnumerable) return WriteEnumerable((IEnumerable)o);
  593.  
  594.             if (o is float) return ((double)((float)o)).ToString(CultureInfo.InvariantCulture);
  595.             if (o is short) return ((int)((short)o)).ToString(CultureInfo.InvariantCulture);
  596.             if (o is ushort) return ((int)((ushort)o)).ToString(CultureInfo.InvariantCulture);
  597.             if (o is byte) return ((int)((byte)o)).ToString(CultureInfo.InvariantCulture);
  598.             if (o is sbyte) return ((int)((sbyte)o)).ToString(CultureInfo.InvariantCulture);
  599.             throw new VirtualMachineException("Unable to serialize object of type " + o.GetType());
  600.         }
  601.  
  602.         private string WriteChar(char p)
  603.         {
  604.             if (p == '\n') return "#\\newline";
  605.             if (p == ' ') return "#\\space";
  606.             if (p == '\t') return "#\\tab";
  607.             if (p < 32) throw new VirtualMachineException("Unable to serialize character with numeric code " + (int)p);
  608.             return "#\\" + p;
  609.         }
  610.  
  611.         private string WritePair(Pair pair)
  612.         {
  613.             var sb = new StringBuilder("(");
  614.             while (true)
  615.             {
  616.                 sb.Append(Write(pair.First));
  617.                 if (pair.Second == null) return sb + ")";
  618.                 if (!(pair.Second is Pair))
  619.                 {
  620.                     sb.Append(" . ");
  621.                     sb.Append(Write(pair.Second));
  622.                     return sb + ")";
  623.                 }
  624.                 pair = (Pair)pair.Second;
  625.                 sb.Append(' ');
  626.             }
  627.         }
  628.  
  629.         private string WriteEnumerable(IEnumerable values)
  630.         {
  631.             var sb = new StringBuilder("(");
  632.             foreach (var o in values)
  633.             {
  634.                 sb.Append(Write(o));
  635.                 sb.Append(' ');
  636.             }
  637.             if (sb.Length > 1) sb[sb.Length - 1] = ')'; else sb.Append(')');
  638.             return sb.ToString();
  639.         }
  640.     }
  641.  
  642.     public sealed class Compiler
  643.     {
  644.         private readonly VirtualMachine Machine;
  645.  
  646.         public Compiler(VirtualMachine machine)
  647.         {
  648.             Machine = machine;
  649.         }
  650.  
  651.         public void Compile(object form)
  652.         {
  653.             CompileObject(form, false);
  654.         }
  655.  
  656.         private void CompileObject(object o, bool isTailPosition, bool quoted = false)
  657.         {
  658.             if (o is Symbol)
  659.             {
  660.                 if (quoted) Machine.EmitLdConst(o);
  661.                 else Machine.EmitGetVariable((Symbol)o);
  662.             }
  663.             else if (o is Pair)
  664.             {
  665.                 if (quoted) CompileQuotedList(((Pair)o).ToArray());
  666.                 else CompileFuncallOrSpecialForm(((Pair)o).ToArray(), isTailPosition);
  667.             }
  668.             else
  669.                 Machine.EmitLdConst(o);
  670.         }
  671.  
  672.         private void CompileQuotedList(object[] o)
  673.         {
  674.             Machine.EmitSaveRegisters();
  675.             Machine.EmitInitArgs();
  676.             foreach (var arg in o.Reverse())
  677.             {
  678.                 CompileObject(arg, false, true);
  679.                 Machine.EmitPushParam();
  680.             }
  681.             Machine.EmitArgsToValue();
  682.             Machine.EmitRestoreRegisters();
  683.         }
  684.  
  685.         private void CompileFuncallOrSpecialForm(object[] o, bool isTailPosition)
  686.         {
  687.             if (o[0] is Symbol)
  688.             {
  689.                 Symbol s = (Symbol)o[0];
  690.                 switch (s.ToString())
  691.                 {
  692.                     case "if": CompileIfSpecialForm(o, isTailPosition); return;
  693.                     case "define": CompileDefineSpecialForm(o, isTailPosition); return;
  694.                     case "set!": CompileSetSpecialForm(o, isTailPosition); return;
  695.                     case "lambda": CompileLambdaSpecialForm(o, isTailPosition); return;
  696.                     case "quote": CompileQuoteSpecialForm(o); return;
  697.                     case "begin": CompileBeginSpecialForm(o, isTailPosition); return;
  698.                     case "sys:apply": CompileApplySpecialForm(o, isTailPosition); return;
  699.                 }
  700.             }
  701.  
  702.             CompileFunctionCall(o, isTailPosition);
  703.         }
  704.  
  705.         private void CompileFunctionCall(object[] o, bool isTailPosition)
  706.         {
  707.             if (!isTailPosition) Machine.EmitSaveRegisters();
  708.             Machine.EmitInitArgs();
  709.  
  710.             foreach (var arg in o.Skip(1).Reverse())
  711.             {
  712.                 CompileObject(arg, false);
  713.                 Machine.EmitPushParam();
  714.             }
  715.  
  716.             CompileObject(o[0], false);
  717.  
  718.             if (!isTailPosition)
  719.             {
  720.                 string continueLabel = NextLabel();
  721.                 Machine.EmitLdCont(continueLabel);
  722.                 Machine.EmitCall();
  723.                 Machine.EmitLabel(continueLabel);
  724.                 Machine.EmitRestoreRegisters();
  725.             }
  726.             else
  727.             {
  728.                 Machine.EmitCall();
  729.             }
  730.         }
  731.  
  732.         private void CompileApplySpecialForm(object[] o, bool isTailPosition)
  733.         {
  734.             if (o.Length != 3) throw new SchemeException("Invalid apply form");
  735.  
  736.             if (!isTailPosition) Machine.EmitSaveRegisters();
  737.             CompileObject(o[2], false);
  738.             Machine.EmitValueToArgs();
  739.             CompileObject(o[1], false);
  740.  
  741.             if (!isTailPosition)
  742.             {
  743.                 string continueLabel = NextLabel();
  744.                 Machine.EmitLdCont(continueLabel);
  745.                 Machine.EmitCall();
  746.                 Machine.EmitLabel(continueLabel);
  747.                 Machine.EmitRestoreRegisters();
  748.             }
  749.             else
  750.             {
  751.                 Machine.EmitCall();
  752.             }
  753.         }
  754.  
  755.         private string NextLabel()
  756.         {
  757.             return Machine.MakeLabel();
  758.         }
  759.  
  760.         private void CompileIfSpecialForm(object[] form, bool isTailPosition)
  761.         {
  762.             if (form.Length != 3 && form.Length != 4) throw new SchemeException("Invalid if form");
  763.  
  764.             string trueLabel = NextLabel();
  765.             string nextLabel = NextLabel();
  766.  
  767.             CompileObject(form[1], false); // Condition
  768.             Machine.EmitBranchLabel(trueLabel);
  769.             if (form.Length == 4) CompileObject(form[3], isTailPosition); else Machine.EmitLdConst(false); // Else-Part or #f
  770.             Machine.EmitGotoLabel(nextLabel);
  771.             Machine.EmitLabel(trueLabel);
  772.             CompileObject(form[2], isTailPosition); // Then-Part
  773.             Machine.EmitLabel(nextLabel);
  774.         }
  775.  
  776.         private void CompileDefineSpecialForm(object[] form, bool isTailPosition)
  777.         {
  778.             if (form.Length == 3 && form[1] is Symbol) // Define variable
  779.             {
  780.                 CompileObject(form[2], false);
  781.                 Machine.EmitDefineVariable((Symbol)form[1]);
  782.                 return;
  783.             }
  784.  
  785.             if (form.Length >= 3 && form[1] is Pair) // Define procedure
  786.             {
  787.                 var nameAndParameters = ((Pair)form[1]).Cast<Symbol>();
  788.                 var name = nameAndParameters.First();
  789.                 var parameterNames = nameAndParameters.Skip(1);
  790.                 bool hasRestParameter = ((Pair)form[1]).IsDottedList();
  791.                 string closureLabel = NextLabel();
  792.                 string afterClosureLabel = NextLabel();
  793.  
  794.                 Machine.EmitMakeClosure(name.ToString(), closureLabel, hasRestParameter, parameterNames.ToArray());
  795.                 Machine.EmitDefineVariable(name);
  796.                 Machine.EmitGotoLabel(afterClosureLabel);
  797.                 Machine.EmitLabel(closureLabel);
  798.  
  799.                 for (int i = 2; i < form.Length; ++i)
  800.                     CompileObject(form[i], i == form.Length - 1);
  801.  
  802.                 Machine.EmitContinue();
  803.                 Machine.EmitLabel(afterClosureLabel);
  804.                 return;
  805.             }
  806.  
  807.             throw new SchemeException("Invalid define form");
  808.         }
  809.  
  810.         private void CompileSetSpecialForm(object[] form, bool isTailPosition)
  811.         {
  812.             if (form.Length != 3) throw new SchemeException("Invalid set form: Expected 2 parameters");
  813.             if (!(form[1] is Symbol)) throw new SchemeException("Invalid set form: '" + form[1] + "' is not a symbol");
  814.             CompileObject(form[2], false);
  815.             Machine.EmitSetVariable((Symbol)form[1]);
  816.         }
  817.  
  818.         private void CompileLambdaSpecialForm(object[] form, bool isTailPosition)
  819.         {
  820.             if (form.Length < 3) throw new SchemeException("Invalid lambda form");
  821.  
  822.             Symbol[] parameterNames;
  823.             bool hasRestParameter;
  824.             string closureLabel = NextLabel();
  825.             string afterClosureLabel = NextLabel();
  826.  
  827.             if (form[1] is Symbol) // (lambda a (form) (form) (form))
  828.             {
  829.                 parameterNames = new[] { (Symbol)form[1] };
  830.                 hasRestParameter = true;
  831.             }
  832.             else if (form[1] == null) // (lambda () (form) (form) (form))
  833.             {
  834.                 parameterNames = new Symbol[0];
  835.                 hasRestParameter = false;
  836.             }
  837.             else if (form[1] is Pair) // (lambda (a b c) (form) (form) (form))
  838.             {
  839.                 hasRestParameter = ((Pair)form[1]).IsDottedList();
  840.                 parameterNames = ((Pair)form[1]).Select(s => (Symbol)s).ToArray();
  841.             }
  842.             else throw new SchemeException("Invalid lambda form");
  843.  
  844.             Machine.EmitMakeClosure("lambda", closureLabel, hasRestParameter, parameterNames);
  845.             Machine.EmitGotoLabel(afterClosureLabel);
  846.             Machine.EmitLabel(closureLabel);
  847.  
  848.             for (int i = 2; i < form.Length; ++i)
  849.                 CompileObject(form[i], i == form.Length - 1);
  850.  
  851.             Machine.EmitContinue();
  852.             Machine.EmitLabel(afterClosureLabel);
  853.         }
  854.  
  855.         private void CompileQuoteSpecialForm(object[] form)
  856.         {
  857.             if (form.Length != 2) throw new SchemeException("Invalid quote form");
  858.             CompileObject(form[1], false, true);
  859.         }
  860.  
  861.         private void CompileBeginSpecialForm(object[] form, bool isTailPosition)
  862.         {
  863.             for (int i = 1; i < form.Length; ++i)
  864.                 CompileObject(form[i], isTailPosition && i == form.Length - 1);
  865.         }
  866.     }
  867.  
  868.     public sealed class PrintEventArgs : EventArgs
  869.     {
  870.         public readonly string WhatToPrint;
  871.         internal PrintEventArgs(string whatToPrint) { WhatToPrint = whatToPrint; }
  872.     }
  873.  
  874.     public sealed class Scheme
  875.     {
  876.         private readonly VirtualMachine machine;
  877.         private readonly Compiler compiler;
  878.         private readonly Random random;
  879.  
  880.         public event EventHandler<PrintEventArgs> Print = delegate { };
  881.  
  882.         private static readonly Writer writer = new Writer();
  883.         public static string ObjectToString(object value) { try { return writer.Write(value); } catch { return value.ToString(); } }
  884.  
  885.         public void SetVariable(Symbol name, object value) { machine.SetVariable(name, value); }
  886.         public object GetVariable(Symbol name) { return machine.GetVariable(name); }
  887.  
  888.         public object Eval(string expression)
  889.         {
  890.             try
  891.             {
  892.                 object ret = null;
  893.  
  894.                 using (var input = new StringReader(expression))
  895.                 {
  896.                     var reader = new Reader(input);
  897.  
  898.                     while (true)
  899.                     {
  900.                         object o = reader.Read(false);
  901.                         if (o is Reader.EofObject) break;
  902.                         HandleMacros(ref o);
  903.  
  904.                         int nextPC = machine.ProgramSize;
  905.                         compiler.Compile(o);
  906.                         ret = machine.Run(nextPC);
  907.                     }
  908.                 }
  909.                 return ret;
  910.             }
  911.             catch (VirtualMachineException ex)
  912.             {
  913.                 throw new SchemeException(ex.Message);
  914.             }
  915.         }
  916.  
  917.         private void HandleMacros(ref object obj)
  918.         {
  919.             if (obj == null) return;
  920.             if (!(obj is Pair)) return;
  921.             if (!(((Pair)obj).First is Symbol)) return;
  922.             var form = ((Pair)obj).ToList();
  923.  
  924.             if (form[0].ToString() == "defmacro")
  925.             {
  926.                 if (!(form[1] is Symbol)) throw new SchemeException("Invalid defmacro form: Name must be a symbol");
  927.                 string name = "sys:macro##" + form[1] + "##";
  928.                 obj = new Pair(Symbol.FromString("define"), new Pair(new Pair(Symbol.FromString(name), form[2]), ((Pair)((Pair)((Pair)obj).Second).Second).Second));
  929.                 return;
  930.             }
  931.  
  932.             while (true) if (!ExpandMacros(ref obj)) break;
  933.         }
  934.  
  935.         private bool ExpandMacros(ref object obj)
  936.         {
  937.             if (obj == null) return false;
  938.             if (!(obj is Pair)) return false;
  939.             if (((Pair)obj).First.ToString() == "quote") return false;
  940.             for (object i = obj; i is Pair; i = ((Pair)i).Second) if (ExpandMacros(ref ((Pair)i).First)) return true;
  941.  
  942.             Symbol o1 = ((Pair)obj).First as Symbol;
  943.             if (o1 == null) return false;
  944.  
  945.             Symbol macroSymbol = Symbol.FromString("sys:macro##" + o1 + "##");
  946.             if (!machine.HasVariable(macroSymbol)) return false;
  947.  
  948.             int nextPC = machine.ProgramSize;
  949.             compiler.Compile(new Pair(macroSymbol, Pair.FromEnumerable(((Pair)((Pair)obj).Second).Select(i => new Pair(Symbol.FromString("quote"), new Pair(i, null))))));
  950.             obj = machine.Run(nextPC);
  951.  
  952.             return true;
  953.         }
  954.  
  955.         public Scheme()
  956.         {
  957.             random = new Random();
  958.             machine = new RegisterMachine(o => !(o is bool) || (bool)o);
  959.             compiler = new Compiler(machine);
  960.             machine.SetVariable("cons", MakeBinaryFunction("cons", (object a, object b) => new Pair(a, b)));
  961.             machine.SetVariable("car", MakeUnaryFunction("car", a => ((Pair)a).First));
  962.             machine.SetVariable("cdr", MakeUnaryFunction("cdr", a => ((Pair)a).Second));
  963.             machine.SetVariable("set-car!", MakeBinaryFunction("set-car!", (Pair a, object b) => a.First = b));
  964.             machine.SetVariable("set-cdr!", MakeBinaryFunction("set-cdr!", (Pair a, object b) => a.Second = b));
  965.             machine.SetVariable("+", MakeNumericalFunction("+", (i1, i2) => i1 + i2, (d1, d2) => d1 + d2));
  966.             machine.SetVariable("-", MakeNumericalFunction("-", (i1, i2) => i1 - i2, (d1, d2) => d1 - d2));
  967.             machine.SetVariable("*", MakeNumericalFunction("*", (i1, i2) => i1 * i2, (d1, d2) => d1 * d2));
  968.             machine.SetVariable("/", MakeNumericalFunction("/", (i1, i2) => i1 / i2, (d1, d2) => d1 / d2));
  969.             machine.SetVariable("<", MakeNumericalFunction("<", (i1, i2) => i1 < i2, (d1, d2) => d1 < d2));
  970.             machine.SetVariable(">", MakeNumericalFunction(">", (i1, i2) => i1 > i2, (d1, d2) => d1 > d2));
  971.             machine.SetVariable("=", MakeNumericalFunction("=", (i1, i2) => i1 == i2, (d1, d2) => d1 == d2));
  972.             machine.SetVariable("sqrt", MakeUnaryFunction("sqrt", o => Math.Sqrt(Convert.ToDouble(o, CultureInfo.InvariantCulture))));
  973.             machine.SetVariable("expt", MakeNumericalFunction("expt", (i1, i2) => (int)Math.Pow(i1, i2), (d1, d2) => Math.Pow(d1, d2)));
  974.             machine.SetVariable("quotient", MakeNumericalFunction("quotient", (i1, i2) => i1 / i2, (d1, d2) => (int)d1 / (int)d2));
  975.             machine.SetVariable("sys:imod", MakeNumericalFunction("sys:imod", (i1, i2) => i1 % i2, (d1, d2) => (int)d1 % (int)d2));
  976.             machine.SetVariable("eq?", MakeBinaryFunction("eq?", (object a, object b) => a == b));
  977.             machine.SetVariable("pair?", MakeUnaryFunction("pair?", o => o is Pair));
  978.             machine.SetVariable("null?", MakeUnaryFunction("null?", o => o == null));
  979.             machine.SetVariable("string?", MakeUnaryFunction("string?", o => o is string));
  980.             machine.SetVariable("number?", MakeUnaryFunction("number?", o => o is int || o is double));
  981.             machine.SetVariable("char?", MakeUnaryFunction("char?", o => o is char));
  982.             machine.SetVariable("boolean?", MakeUnaryFunction("boolean?", o => o is bool));
  983.             machine.SetVariable("symbol?", MakeUnaryFunction("symbol?", o => o is Symbol));
  984.             machine.SetVariable("integer?", MakeUnaryFunction("integer?", o => o is int));
  985.             machine.SetVariable("real?", MakeUnaryFunction("real?", o => o is double));
  986.             machine.SetVariable("procedure?", MakeUnaryFunction("procedure?", o => RegisterMachine.IsCallable(o)));
  987.             machine.SetVariable("random", MakeUnaryFunction("random", a => random.Next(Convert.ToInt32(a, CultureInfo.InvariantCulture))));
  988.             machine.SetVariable("display", (Func<object[], object>)display);
  989.             machine.SetVariable("char=?", MakeBinaryFunction("char=?", (char a, char b) => a == b));
  990.             machine.SetVariable("char>?", MakeBinaryFunction("char>?", (char a, char b) => a > b));
  991.             machine.SetVariable("char<?", MakeBinaryFunction("char<?", (char a, char b) => a < b));
  992.             machine.SetVariable("char-ci=?", MakeBinaryFunction("char-ci=?", (char a, char b) => char.ToLowerInvariant(a) == char.ToLowerInvariant(b)));
  993.             machine.SetVariable("char-ci>?", MakeBinaryFunction("char-ci>?", (char a, char b) => char.ToLowerInvariant(a) > char.ToLowerInvariant(b)));
  994.             machine.SetVariable("char-ci<?", MakeBinaryFunction("char-ci<?", (char a, char b) => char.ToLowerInvariant(a) < char.ToLowerInvariant(b)));
  995.             machine.SetVariable("char-alphabetic?", MakeUnaryFunction("char-alphabetic?", o => char.IsLetter((char)o)));
  996.             machine.SetVariable("char-numeric?", MakeUnaryFunction("char-numeric?", o => char.IsDigit((char)o)));
  997.             machine.SetVariable("char-whitespace?", MakeUnaryFunction("char-whitespace?", o => char.IsWhiteSpace((char)o)));
  998.             machine.SetVariable("char-upper-case?", MakeUnaryFunction("char-upper-case?", o => char.IsUpper((char)o)));
  999.             machine.SetVariable("char-lower-case?", MakeUnaryFunction("char-lower-case?", o => char.IsLower((char)o)));
  1000.             machine.SetVariable("char-upcase", MakeUnaryFunction("char-upcase", o => char.ToUpperInvariant((char)o)));
  1001.             machine.SetVariable("char-downcase", MakeUnaryFunction("char-downcase", o => char.ToLowerInvariant((char)o)));
  1002.             machine.SetVariable("string=?", MakeBinaryFunction("string=?", (string a, string b) => String.Compare(a, b, false, CultureInfo.InvariantCulture) == 0));
  1003.             machine.SetVariable("string>?", MakeBinaryFunction("string>?", (string a, string b) => String.Compare(a, b, false, CultureInfo.InvariantCulture) > 0));
  1004.             machine.SetVariable("string<?", MakeBinaryFunction("string<?", (string a, string b) => String.Compare(a, b, false, CultureInfo.InvariantCulture) < 0));
  1005.             machine.SetVariable("string-ci=?", MakeBinaryFunction("string-ci=?", (string a, string b) => String.Compare(a, b, true, CultureInfo.InvariantCulture) == 0));
  1006.             machine.SetVariable("string-ci>?", MakeBinaryFunction("string-ci>?", (string a, string b) => String.Compare(a, b, true, CultureInfo.InvariantCulture) > 0));
  1007.             machine.SetVariable("string-ci<?", MakeBinaryFunction("string-ci<?", (string a, string b) => String.Compare(a, b, true, CultureInfo.InvariantCulture) < 0));
  1008.             machine.SetVariable("string-length", MakeUnaryFunction("string-length", o => ((string)o).Length));
  1009.             machine.SetVariable("string-append", MakeBinaryFunction("string-append", (string a, string b) => a + b));
  1010.             machine.SetVariable("char->integer", MakeUnaryFunction("char->integer", o => (int)(char)o));
  1011.             machine.SetVariable("integer->char", MakeUnaryFunction("integer->char", o => (char)(int)o));
  1012.             machine.SetVariable("string-ref", MakeBinaryFunction("string-ref", (string s, int index) => s[index]));
  1013.             machine.SetVariable("string->symbol", MakeUnaryFunction("string->symbol", o => Symbol.FromString((string)o)));
  1014.             machine.SetVariable("symbol->string", MakeUnaryFunction("symbol->string", o => (Symbol)o).ToString());
  1015.             machine.SetVariable("string->list", MakeUnaryFunction("string->list", o => Pair.FromEnumerable(((string)o).ToCharArray().Cast<object>())));
  1016.             machine.SetVariable("list->string", MakeUnaryFunction("list->string", o => o == null ? "" : new string(((IEnumerable<object>)o).Cast<char>().ToArray())));
  1017.             machine.SetVariable("sys:strtonum", MakeBinaryFunction("sys:strtonum", (string s, int b) => s.Contains('.') ? Convert.ToDouble(s, CultureInfo.InvariantCulture) : Convert.ToInt32(s, b)));
  1018.             machine.SetVariable("sys:numtostr", MakeBinaryFunction("sys:numtostr", (object i, int b) => (i is int) ? Convert.ToString((int)i, b) : Convert.ToString((double)i)));
  1019.             machine.SetVariable("eqv?", MakeBinaryFunction("eqv?", (object a, object b) => Eqv(a, b)));
  1020.             machine.SetVariable("equal?", MakeBinaryFunction("equal?", (object a, object b) => Equal(a, b)));
  1021.             machine.SetVariable("sys:error", MakeUnaryFunction("sys:error", o => { throw new SchemeError((Pair)o); }));
  1022.             machine.SetVariable("sys:sleep", MakeUnaryFunction("sys:sleep", o => { Thread.Sleep(Convert.ToInt32(o, CultureInfo.InvariantCulture)); return null; }));
  1023.  
  1024.             //// TODO: string-set, string-fill!, make-string, string-copy. Impossible with .NET strings.
  1025.             //AddFunction("sys:clr.", TODO
  1026.             //AddFunction("sys:clr-get", (object o, Symbol name) => GetClrProperty(o, name).GetValue(o, new object[0]));
  1027.             //AddFunction("sys:clr-set", (object o, Symbol name, object value) => SetClrProperty(o, name, value));
  1028.  
  1029.             Eval(initScript);
  1030.         }
  1031.  
  1032.         private const string initScript =
  1033.             "(define (caar x) (car (car x)))" +
  1034.             "(define (cadr x) (car (cdr x)))" +
  1035.             "(define (cdar x) (cdr (car x)))" +
  1036.             "(define (cddr x) (cdr (cdr x)))" +
  1037.             "(define (caaar x) (car (car (car x))))" +
  1038.             "(define (caadr x) (car (car (cdr x))))" +
  1039.             "(define (cadar x) (car (cdr (car x))))" +
  1040.             "(define (caddr x) (car (cdr (cdr x))))" +
  1041.             "(define (cdaar x) (cdr (car (car x))))" +
  1042.             "(define (cdadr x) (cdr (car (cdr x))))" +
  1043.             "(define (cddar x) (cdr (cdr (car x))))" +
  1044.             "(define (cdddr x) (cdr (cdr (cdr x))))" +
  1045.             "(define (list . lst) lst)" +
  1046.             "(define (>= a b) (if (< a b) #f #t))" +
  1047.             "(define (<= a b) (if (> a b) #f #t))" +
  1048.             "(define (char>=? a b) (if (char<? a b) #f #t))" +
  1049.             "(define (char<=? a b) (if (char>? a b) #f #t))" +
  1050.             "(define (char-ci>=? a b) (if (char-ci<? a b) #f #t))" +
  1051.             "(define (char-ci<=? a b) (if (char-ci>? a b) #f #t))" +
  1052.             "(define (string>=? a b) (if (string<? a b) #f #t))" +
  1053.             "(define (string<=? a b) (if (string>? a b) #f #t))" +
  1054.             "(define (string-ci>=? a b) (if (string-ci<? a b) #f #t))" +
  1055.             "(define (string-ci<=? a b) (if (string-ci>? a b) #f #t))" +
  1056.             "(define (zero? x) (= x 0))" +
  1057.             "(define (positive? x) (> x 0))" +
  1058.             "(define (negative? x) (< x 0))" +
  1059.             "(define (abs x) (if (positive? x) x (- 0 x)))" +
  1060.             "(define (sys:sign x) (if (>= x 0) 1 -1))" +
  1061.             "(define (remainder a b) (* (sys:sign a) (abs (sys:imod a b))))" +
  1062.             "(define (modulo a b) (if (= (sys:sign a) (sys:sign b)) (sys:imod a b) (+ b (sys:imod a b))))" +
  1063.             "(define (even? x) (zero? (sys:imod x 2)))" +
  1064.             "(define (odd? x) (if (even? x) #f #t))" +
  1065.             "(define (not x) (if x #f #t))" +
  1066.             "(define (newline) (display \"\\n\"))" +
  1067.             "(define (length lst) (define (iter i acc) (if (null? i) acc (iter (cdr i) (+ 1 acc)))) (iter lst 0))" +
  1068.             "(define (reverse lst) (define (iter i acc) (if (null? i) acc (iter (cdr i) (cons (car i) acc)))) (iter lst nil))" +
  1069.             "(define (map f lst) (define (iter i acc) (if (null? i) (reverse acc) (iter (cdr i) (cons (f (car i)) acc)))) (iter lst nil))" +
  1070.             "(define (for-each f lst) (if (null? lst) nil (begin (f (car lst)) (for-each f (cdr lst)))))" +
  1071.             "(define (filter f lst) (define (iter i acc) (if (null? i) (reverse acc) (iter (cdr i) (if (f (car i)) (cons (car i) acc) acc)))) (iter lst nil))" +
  1072.             "(define (fold f acc lst) (if (null? lst) acc (fold f (f (car lst) acc) (cdr lst))))" +
  1073.             "(define (all? f lst) (define (iter i) (if (null? i) #t (if (f (car i)) (iter (cdr i)) #f))) (iter lst))" +
  1074.             "(define (any? f lst) (define (iter i) (if (null? i) #f (if (f (car i)) #t (iter (cdr i))))) (iter lst))" +
  1075.             "(define (list-tail lst k) (if (zero? k) lst (list-tail (cdr lst) (- k 1))))" +
  1076.             "(define (list-ref lst k) (car (list-tail lst k)))" +
  1077.             "(define (sys:gcd-of-two a b) (if (= b 0) a (sys:gcd-of-two b (remainder a b))))" +
  1078.             "(define (sys:lcm-of-two a b) (/ (* a b) (sys:gcd-of-two a b)))" +
  1079.             "(define (gcd . args) (if (zero? (length args)) 0 (abs (fold sys:gcd-of-two (car args) (cdr args)))))" +
  1080.             "(define (lcm . args) (if (zero? (length args)) 1 (abs (fold sys:lcm-of-two (car args) (cdr args)))))" +
  1081.             "(define (append . lsts) (define (iter current acc) (if (pair? current) (iter (cdr current) (cons (car current) acc)) acc)) (reverse (fold iter nil lsts)))" +
  1082.             "(define (error . params) (sys:error params))" +
  1083.             "(define (string . values) (list->string values))" +
  1084.             "(define (string->number n . rest) (if (pair? rest) (sys:strtonum n (car rest)) (sys:strtonum n 10)))" +
  1085.             "(define (number->string n . rest) (if (pair? rest) (sys:numtostr n (car rest)) (sys:numtostr n 10)))" +
  1086.             "(define (substring str start end) (define (get-char pos) (string-ref str pos)) (list->string (map get-char (sys:range start (- end 1)))))" +
  1087.             "(define (memq obj lst) (if (pair? lst) (if (eq? obj (car lst)) lst (memq obj (cdr lst))) #f))" +
  1088.             "(define (memv obj lst) (if (pair? lst) (if (eqv? obj (car lst)) lst (memv obj (cdr lst))) #f))" +
  1089.             "(define (member obj lst) (if (pair? lst) (if (equal? obj (car lst)) lst (member obj (cdr lst))) #f))" +
  1090.             "(define (assq obj lst) (if (pair? lst) (if (eq? obj (caar lst)) (car lst) (assq obj (cdr lst))) #f))" +
  1091.             "(define (assv obj lst) (if (pair? lst) (if (eqv? obj (caar lst)) (car lst) (assv obj (cdr lst))) #f))" +
  1092.             "(define (assoc obj lst) (if (pair? lst) (if (equal? obj (caar lst)) (car lst) (assoc obj (cdr lst))) #f))" +
  1093.             "(define (apply f args) (sys:apply f args))" +
  1094.             "(defmacro let (lst . forms) (cons (cons 'lambda (cons (map car lst) forms)) (map cadr lst)))" +
  1095.             "(defmacro cond list-of-forms (define (expand-cond lst) (if (null? lst) #f (if (eq? (caar lst) 'else) (cons 'begin (cdar lst)) (list 'if (caar lst) (cons 'begin (cdar lst)) (expand-cond (cdr lst)))))) (expand-cond list-of-forms))" +
  1096.             "(defmacro delay (expression) (list 'let '((##forced_value (quote ##not_forced_yet))) (list 'lambda '() (list 'if '(eq? ##forced_value (quote ##not_forced_yet)) (list 'set! '##forced_value expression)) '##forced_value)))" +
  1097.             "(define (force promise) (promise))" +
  1098.             "(define (min . args) (define (min-of-two a b) (if (< a b) a b)) (let ((l (length args))) (cond ((= 0 l) (error \"min called without parameters\")) ((= 1 l) (car args)) (else (fold min-of-two (car args) (cdr args))))))" +
  1099.             "(define (max . args) (define (max-of-two a b) (if (> a b) a b)) (let ((l (length args))) (cond ((= 0 l) (error \"max called without parameters\")) ((= 1 l) (car args)) (else (fold max-of-two (car args) (cdr args))))))" +
  1100.             "(define (sys:curry proc . cargs) (lambda args (apply proc (append cargs args))))" +
  1101.             "(define (sys:range from to) (define (iter i acc) (if (> from i) acc (iter (- i 1) (cons i acc)))) (iter to nil))" +
  1102.             "(define (sys:count from to f) (if (< to from) nil (begin (f from) (sys:count (+ 1 from) to f))))" +
  1103.             "(define (sys:split str sep) (define (iter acc cur s) (cond ((string=? s \"\") (reverse (cons cur acc))) ((char=? (string-ref s 0) sep) (iter (cons cur acc) \"\" (substring s 1 (string-length s)))) (else (iter acc (string-append cur (substring s 0 1)) (substring s 1 (string-length s)))))) (iter '() \"\" str))" +
  1104.  
  1105.             "(define (sort x f)" +
  1106.             "  (cond ((null? x) x)                                                        " +
  1107.             "        ((null? (cdr x)) x)                                                  " +
  1108.             "        (else                                                                " +
  1109.             "          (let ((pivot (car x)))                                             " +
  1110.             "            (let ((part1 (filter (lambda (i) (f i pivot)) (cdr x)))          " +
  1111.             "                  (part2 (filter (lambda (i) (not (f i pivot))) (cdr x))))   " +
  1112.             "              (append                                                        " +
  1113.             "                (sort part1 f)                                               " +
  1114.             "                (list pivot)                                                 " +
  1115.             "                (sort part2 f)))))))                                         " +
  1116.  
  1117.  
  1118.             "(define curry sys:curry)" +
  1119.             "(define range sys:range)" +
  1120.             "(define count sys:count)" +
  1121.             "(define sleep sys:sleep)" +
  1122.             "(define split sys:split)" +
  1123.             //"(define clr-get sys:clr-get)" +
  1124.             //"(define clr-set sys:clr-set)" +
  1125.             //"(define clr. sys:clr.)" +
  1126.             "";
  1127.  
  1128.         // TODO: and, or, sort
  1129.  
  1130.         private static void AssertParameterCount(string procedure, int expected, object[] parameters)
  1131.         {
  1132.             if (parameters.Length != expected) throw new SchemeException(procedure + ": Expected " + expected + " parameter(s), got " + parameters.Length);
  1133.         }
  1134.  
  1135.         private static Func<object[], object> MakeNumericalFunction(string name, Func<int, int, object> iF, Func<double, double, object> dF)
  1136.         {
  1137.             return args =>
  1138.             {
  1139.                 AssertParameterCount(name, 2, args);
  1140.                 object o1 = args[0];
  1141.                 object o2 = args[1];
  1142.                 if (!(o1 is int) && !(o1 is double)) throw new SchemeException(name + ": Invalid argument type in arg 1, expected int or double, got " + o1.GetType());
  1143.                 if (!(o2 is int) && !(o2 is double)) throw new SchemeException(name + ": Invalid argument type in arg 2, expected int or double, got " + o2.GetType());
  1144.                 return o1 is int && o2 is int ? iF((int)o1, (int)o2) : dF(Convert.ToDouble(o1, CultureInfo.InvariantCulture), Convert.ToDouble(o2, CultureInfo.InvariantCulture));
  1145.             };
  1146.         }
  1147.  
  1148.         private static Func<object[], object> MakeUnaryFunction(string name, Func<object, object> f)
  1149.         {
  1150.             return args =>
  1151.             {
  1152.                 AssertParameterCount(name, 1, args);
  1153.                 return f(args[0]);
  1154.             };
  1155.         }
  1156.  
  1157.         private static Func<object[], object> MakeBinaryFunction<A, B>(string name, Func<A, B, object> f)
  1158.         {
  1159.             return args =>
  1160.             {
  1161.                 AssertParameterCount(name, 2, args);
  1162.                 if (args[0] != null && !(args[0] is A)) throw new SchemeException(name + ": Expected first parameter to be of type '" + typeof(A) + "', got '" + args[0].GetType() + "'");
  1163.                 if (args[1] != null && !(args[1] is B)) throw new SchemeException(name + ": Expected second parameter to be of type '" + typeof(B) + "', got '" + args[1].GetType() + "'");
  1164.                 return f((A)args[0], (B)args[1]);
  1165.             };
  1166.         }
  1167.  
  1168.         private static object Eqv(object a, object b)
  1169.         {
  1170.             if (a == b) return true;
  1171.             if (a is bool && b is bool) return ((bool)a) == ((bool)b);
  1172.             if (a is char && b is char) return ((char)a) == ((char)b);
  1173.             if (a is int && b is int) return ((int)a) == ((int)b);
  1174.             if (a is double && b is double) return ((double)a) == ((double)b);
  1175.             return false;
  1176.         }
  1177.  
  1178.         private static object Equal(object a, object b)
  1179.         {
  1180.             if ((bool)Eqv(a, b)) return true;
  1181.             if (a is string && b is string) return string.Equals(a, b);
  1182.             if (a is IEnumerable<object> && b is IEnumerable<object>)
  1183.             {
  1184.                 List<object> l1 = ((IEnumerable<object>)a).ToList();
  1185.                 List<object> l2 = ((IEnumerable<object>)b).ToList();
  1186.                 if (l1.Count != l2.Count) return false;
  1187.                 for (int i = 0; i < l1.Count; ++i) if (!(bool)Equal(l1[i], l2[i])) return false;
  1188.                 return true;
  1189.             }
  1190.             return false;
  1191.         }
  1192.  
  1193.         private object display(object[] parameters)
  1194.         {
  1195.             Print(this, new PrintEventArgs(string.Join(" ", parameters)));
  1196.             return true;
  1197.         }
  1198.     }
  1199. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement