/System.Xronos/Builtins/SpecialForms.cs
C# | 747 lines | 592 code | 131 blank | 24 comment | 57 complexity | e66235336007d25a0deacd86eefebfed MD5 | raw file
- /* ****************************************************************************
- *
- * Copyright (c) 2008 Stefan Rusek and Benjamin Pollack
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- * ***************************************************************************/
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Xronos.Language;
- using Microsoft.Linq.Expressions;
- using System.Reflection;
- using System.Collections;
- using Microsoft.Scripting.Actions;
- using Microsoft.Scripting.Runtime;
- using System.Xronos.Scripting.Binders;
- using Microsoft.Scripting.Utils;
- using System.Xronos.Scripting;
- using Microsoft.Scripting.Ast;
-
- namespace System.Xronos.Builtins
- {
- public static partial class SpecialForms
- {
- static readonly Symbol Add = Symbol.Create("+*");
- static readonly Symbol Sub = Symbol.Create("-*");
- static readonly Symbol Mul = Symbol.Create("**");
- static readonly Symbol Div = Symbol.Create("div*");
- static readonly Symbol Quot = Symbol.Create("quot");
- static readonly Symbol Rem = Symbol.Create("rem");
-
- static readonly Symbol Lt = Symbol.Create("<");
- static readonly Symbol Gt = Symbol.Create(">");
- static readonly Symbol Lte = Symbol.Create("<=");
- static readonly Symbol Gte = Symbol.Create(">=");
-
- static readonly Symbol EqualsOp = Symbol.Create("==");
- static readonly Symbol Not = Symbol.Create("not");
- static readonly Symbol NotEquals = Symbol.Create("not=");
-
- static readonly Symbol Try = Symbol.Create("try");
- static readonly Symbol Throw = Symbol.Create("throw");
- static readonly Symbol Rethrow = Symbol.Create("rethrow");
-
- internal static readonly Symbol Do = Symbol.Create("do");
- static readonly Symbol Let = Symbol.Create("let");
- static readonly Symbol If = Symbol.Create("if");
- static readonly Symbol Binding = Symbol.Create("binding");
- static readonly Symbol Set = Symbol.Create("set!");
-
- static readonly Symbol Def = Symbol.Create("def");
- static readonly Symbol Fn = Symbol.Create("fn");
- static readonly Symbol Loop = Symbol.Create("loop");
- static readonly Symbol Recur = Symbol.Create("recur");
- static readonly Symbol Quote = Symbol.Create("quote");
-
- public static readonly Symbol Dot = Symbol.Create(".");
- public static readonly Symbol New = Symbol.Create("new");
-
- static readonly Symbol Enter = Symbol.Create("monitor-enter");
- static readonly Symbol Exit = Symbol.Create("monitor-exit");
-
- static readonly Symbol InNs = Symbol.Create("in-ns");
-
- static readonly Symbol Cast = Symbol.Create("cast*");
- static readonly Symbol Is = Symbol.Create("is*");
- static readonly Symbol As = Symbol.Create("as*");
-
-
- #if DEBUG
- static readonly Symbol Debug = Symbol.Create("debug");
- #endif
-
- static Dictionary<Symbol, SpecialFormBase> forms;
-
- static SpecialForms()
- {
- forms = new Dictionary<Symbol, SpecialFormBase>();
-
- forms[Add] = new AddForm();
- forms[Sub] = new SubtractForm();
- forms[Mul] = new MultiplyForm();
- forms[Div] = new DivideForm();
- forms[Quot] = new QuotForm();
- forms[Rem] = new RemForm();
-
- forms[Lt] = new LtForm();
- forms[Gt] = new GtForm();
- forms[Lte] = new LteForm();
- forms[Gte] = new GteForm();
-
- forms[EqualsOp] = new EqualsForm();
- forms[Not] = new NotForm();
- forms[NotEquals] = new NotEqualsForm();
-
- forms[Try] = new TryForm();
- forms[Throw] = new ThrowForm();
- forms[Rethrow] = new RethrowForm();
-
- forms[Do] = new DoForm();
- forms[Let] = new LetForm();
- forms[If] = new IfForm();
- forms[Binding] = new BindingForm();
- forms[Set] = new SetForm();
-
- forms[Def] = new DefForm();
- forms[Fn] = new FnForm();
- forms[Loop] = new LoopForm();
- forms[Recur] = new RecurForm();
- forms[Quote] = new QuoteForm();
-
- forms[Dot] = new DotForm();
- forms[New] = new NewForm();
-
- forms[Enter] = new StaticMethodForm(typeof(System.Threading.Monitor).GetMethod("Enter"));
- forms[Exit] = new StaticMethodForm(typeof(System.Threading.Monitor).GetMethod("Exit"));
-
- forms[InNs] = new InNsForm();
-
- forms[Cast] = new CastForm();
- forms[Is] = new CastIsForm();
- forms[As] = new CastAsForm();
- #if DEBUG
- forms[Debug] = new DebugForm();
- #endif
- }
-
- internal static object Lookup(Symbol sym)
- {
- SpecialFormBase result;
- if (forms.TryGetValue(sym, out result))
- return result;
- return null;
- }
-
- internal static bool IsSpecialForm(Symbol sym)
- {
- return Lookup(sym) != null;
- }
-
- internal abstract class SpecialFormBase : XronosObject
- {
- protected SpecialFormBase() : base(null) { }
-
- protected abstract Expression Compile(Compiler compiler, ISequence rest, Scope scope);
-
- public virtual object Invoke(object arg1, object arg2, object arg3)
- {
- return Compile((Compiler)arg1, RT.seq(arg2), (Scope)arg3);
- }
-
- public override XronosObject withMeta(IPersistentMap meta)
- {
- throw new NotImplementedException();
- }
- }
-
- class StaticMethodForm : SpecialFormBase
- {
- MethodInfo method;
- internal StaticMethodForm(MethodInfo method) { this.method = method; }
- protected override Expression Compile(Compiler compiler, ISequence rest, Scope scope)
- {
- return Utils.SimpleCallHelper(method, compiler.CompileArguments(rest, scope));
- }
- }
-
- class ThrowForm : SpecialFormBase
- {
- protected override Expression Compile(Compiler compiler, ISequence rest, Scope scope)
- {
- return Expression.Throw(compiler.CompileToExpression(rest.first(), scope));
- }
- }
-
- class RethrowForm : SpecialFormBase
- {
- protected override Expression Compile(Compiler compiler, ISequence rest, Scope scope)
- {
- return Expression.Rethrow();
- }
- }
-
- class DebugForm : SpecialFormBase
- {
- protected override Expression Compile(Compiler compiler, ISequence rest, Scope scope)
- {
- var exp = compiler.CompileToExpression(rest.first(), scope);
- object dump = exp.DebugView;
- Console.Out.WriteLine(dump);
- return exp;
- }
- }
-
- #region math special forms
- abstract class BinaryOpForm : SpecialFormBase
- {
- protected virtual bool AllowEmpty { get { return true; } }
- protected abstract object DefaultValue { get; }
- protected abstract ExpressionType ExType { get; }
-
- protected Expression InternalOp(Expression left, Expression right)
- {
- return Expression.Dynamic(BinderFactory.BinaryOp(ExType), typeof(object), left, right);
- }
-
- protected override Expression Compile(Compiler compiler, ISequence rest, Scope scope)
- {
- Expression result = null;
- if (rest == null && AllowEmpty)
- result = Expression.Constant(DefaultValue);
- else
- {
- result = compiler.CompileToExpression(rest.first(), scope);
- rest = rest.rest();
- }
-
- CompileRest(compiler, rest, scope, ref result);
-
- return result;
- }
-
- protected virtual void CompileRest(Compiler compiler, ISequence rest, Scope scope, ref Expression result)
- {
- while (rest != null)
- {
- result = InternalOp(result, compiler.CompileToExpression(rest.first(), scope));
- rest = rest.rest();
- }
- }
- }
-
- class AddForm : BinaryOpForm
- {
- protected override object DefaultValue
- {
- get { return (int)0; }
- }
-
- protected override ExpressionType ExType
- {
- get { return ExpressionType.Add; }
- }
- }
-
- class SubtractForm : BinaryOpForm
- {
- protected override bool AllowEmpty { get { return false; } }
-
- protected override object DefaultValue
- {
- get { return (int)0; }
- }
-
- protected override ExpressionType ExType
- {
- get { return ExpressionType.Subtract; }
- }
- }
-
- class MultiplyForm : BinaryOpForm
- {
- protected override object DefaultValue
- {
- get { return (int)1; }
- }
-
- protected override ExpressionType ExType
- {
- get { return ExpressionType.Multiply; }
- }
- }
-
- class DivideForm : BinaryOpForm
- {
- protected override bool AllowEmpty { get { return false; } }
-
- protected override object DefaultValue
- {
- get { return (int)1; }
- }
-
- protected override ExpressionType ExType
- {
- get { return ExpressionType.Divide; }
- }
- }
-
- class QuotForm : BinaryOpForm
- {
- protected override bool AllowEmpty { get { return false; } }
-
- protected override object DefaultValue
- {
- get { return (int)1; }
- }
-
- protected override ExpressionType ExType
- {
- get { return ExpressionType.Divide; }
- }
- }
-
- class RemForm : BinaryOpForm
- {
- protected override bool AllowEmpty { get { return false; } }
-
- protected override object DefaultValue
- {
- get { return (int)1; }
- }
-
- protected override ExpressionType ExType
- {
- get { return ExpressionType.Modulo; }
- }
- }
-
- abstract class ComparisonForm : BinaryOpForm
- {
- protected override bool AllowEmpty { get { return false; } }
-
- protected override object DefaultValue
- {
- get { return null; }
- }
-
- protected override void CompileRest(Compiler compiler, ISequence rest, Scope scope, ref Expression result)
- {
- var vars = new List<ParameterExpression>();
- List<Expression> exprs = new List<Expression>();
-
- vars.Add(Expression.Variable(result.Type, "__t0"));
- exprs.Add(Expression.Assign(vars[0], result));
-
- while (rest != null)
- {
- var e = compiler.CompileToExpression(rest.first(), scope);
- var v = Expression.Variable(e.Type, "__t" + vars.Count);
- vars.Add(v);
- exprs.Add(Expression.Assign(v, e));
-
- rest = rest.rest();
- }
-
- Expression comparison;
- comparison = InternalOp(vars[0], vars[1]);
- for (int i = 1; i < vars.Count - 1; i++)
- comparison = Expression.AndAlso(comparison, InternalOp(vars[i], vars[i + 1]));
- exprs.Add(comparison);
-
- result = Expression.Block(vars, exprs);
- }
- }
-
- class LtForm : ComparisonForm
- {
- protected override ExpressionType ExType
- {
- get { return ExpressionType.LessThan; }
- }
- }
-
- class GtForm : ComparisonForm
- {
- protected override ExpressionType ExType
- {
- get { return ExpressionType.GreaterThan; }
- }
- }
-
- class LteForm : ComparisonForm
- {
- protected override ExpressionType ExType
- {
- get { return ExpressionType.LessThanOrEqual; }
- }
- }
-
- class GteForm : ComparisonForm
- {
- protected override ExpressionType ExType
- {
- get { return ExpressionType.GreaterThanOrEqual; }
- }
- }
- #endregion
-
- class EqualsForm : SpecialFormBase
- {
- protected override Expression Compile(Compiler compiler, ISequence rest, Scope scope)
- {
- return Utils.SimpleCallHelper(typeof(object).GetMethod("Equals", new Type[] { typeof(object), typeof(object)}),
- compiler.CompileToExpression(rest.first(), scope),
- compiler.CompileToExpression(rest.rest().first(), scope));
- }
- }
-
- class NotForm : SpecialFormBase
- {
- protected override Expression Compile(Compiler compiler, ISequence rest, Scope scope)
- {
- return Expression.Not(IfForm.ToBool(compiler.CompileToExpression(rest.first(), scope)));
- }
- }
-
- class NotEqualsForm : SpecialFormBase
- {
- EqualsForm equals = new EqualsForm();
- protected override Expression Compile(Compiler compiler, ISequence rest, Scope scope)
- {
- return Expression.Not((Expression)equals.Invoke(compiler, rest, scope));
- }
- }
-
- class DoForm : SpecialFormBase
- {
- protected override Expression Compile(Compiler compiler, ISequence rest, Scope scope)
- {
- return CompileDo(compiler, null, rest, null, scope);
- }
-
- internal static Expression CompileDo(Compiler compiler, IEnumerable<Expression> pre, ISequence rest, IEnumerable<Expression> post, Scope scope)
- {
- return CompileDo(compiler, pre, CompileToEnum(compiler, rest, scope), post, scope);
- }
-
- internal static Expression CompileDo(Compiler compiler, IEnumerable<Expression> pre, IEnumerable<Expression> block, IEnumerable<Expression> post, Scope scope)
- {
- var list = new List<Expression>();
-
- if (pre != null) list.AddRange(pre);
- if (block != null) list.AddRange(block);
- if (post != null) list.AddRange(post);
-
- if (list.Count == 0)
- return Expression.Constant(null);
-
- return Expression.Block(list);
- }
-
- static IEnumerable<Expression> CompileToEnum(Compiler compiler, ISequence rest, Scope scope)
- {
- while (rest != null)
- {
- yield return compiler.CompileToExpression(rest.first(), scope);
- rest = rest.rest();
- }
- }
- }
-
- class QuoteForm : SpecialFormBase
- {
- protected override Expression Compile(Compiler compiler, ISequence rest, Scope scope)
- {
- return Expression.Constant(rest.first());
- }
- }
-
- class DefForm : SpecialFormBase
- {
- protected override Expression Compile(Compiler compiler, ISequence rest, Scope scope)
- {
- if (!scope.IsTopLevel)
- throw new CompilerException("(def) is only allowed at top-level scope.");
-
- var name = (Symbol)rest.first();
- rest = rest.rest();
-
- var var = compiler.CompileToVar(name, true);
-
- if (rest == null)
- return var;
-
- var temp = Expression.Variable(var.Type, "temp");
- var val = Expression.Variable(var.Type.GetGenericArguments()[0], "val");
- return Expression.Block(new[] { temp, val },
- Expression.Assign(temp, var),
- Expression.Assign(val, Expression.Convert(compiler.CompileToExpression(rest.first(), scope), val.Type)),
- Utils.SimpleCallHelper(temp, var.Type.GetMethod("bindRoot"), val),
- Utils.SimpleCallHelper(temp, var.Type.GetMethod("setMeta"), Expression.Constant(name.meta())),
- temp);
- }
- }
-
- class TryForm : SpecialFormBase
- {
- internal static readonly Symbol Catch = Symbol.Create("catch");
- internal static readonly Symbol Finally = Symbol.Create("finally");
-
- internal static readonly LabelTarget CatchNullLabel = Expression.Label();
-
- protected override Expression Compile(Compiler compiler, ISequence rest, Scope scope)
- {
- List<Expression> body = new List<Expression>();
- List<CatchBlock> catches = new List<CatchBlock>();
- Expression @finally = null;
-
- while (rest != null)
- {
- var first = rest.first();
- var call = first as IPersistentList;
- rest = rest.rest();
-
- if (call != null)
- {
- var method = call.peek() as Symbol;
-
- if (Catch.Equals(method))
- {
- if (@finally != null)
- throw new InvalidProgramException("Catches must appear before finally");
- BuildCatch(compiler, scope, catches, RT.seq(call));
- continue;
- }
-
- if (Finally.Equals(method))
- {
- if (@finally != null)
- throw new InvalidProgramException("More than one finally");
-
- @finally = DoForm.CompileDo(compiler, null, RT.seq( call.pop()), null, scope);
- continue;
- }
- }
-
- if (@finally != null || catches.Count > 0)
- throw new InvalidProgramException();
-
- body.Add(compiler.CompileToExpression(first, scope));
- }
-
- if (body.Count == 0)
- return Expression.Constant(null);
-
- Type result = body[body.Count - 1].Type;
-
- if (result == typeof(void))
- {
- result = typeof(object);
- body.Add(Expression.Constant(null));
- }
-
- var rvar = Expression.Variable(result, "@tryResult");
- var vars = new List<ParameterExpression>();
- vars.Add(rvar);
-
- for (int i = 0; i < catches.Count; i++)
- {
- var cb = catches[i];
- if (cb.Body.Type != typeof(void))
- {
- catches[i] = Expression.Catch(cb.Variable,
- Expression.Assign(rvar, Expression.Convert(cb.Body, rvar.Type)));
- }
- vars.Add(cb.Variable);
- }
-
- return Expression.Block(vars,
- Expression.TryCatchFinally(
- Expression.Assign(rvar, Expression.Block(body)),
- @finally,
- catches.ToArray()),
- rvar);
- }
-
- private static void BuildCatch(Compiler compiler, Scope scope, List<CatchBlock> catches, ISequence call)
- {
- var type = (Symbol)call.rest().first();
- var name = (Symbol)call.rest().rest().first();
-
- var cScope = new Scope(scope);
-
- // make sure we can't recur from in a catch out of the catch
- cScope.LoopLabel = CatchNullLabel;
- cScope.LoopVariables = new List<Expression>();
-
- var ex = Expression.Variable(Compiler.FindType(type), name.Name);
- cScope[name] = ex;
-
- catches.Add(Expression.Catch(
- ex,
- DoForm.CompileDo(compiler, null, call.rest().rest().rest(), null, cScope)));
- }
- }
-
- class BindingForm : SpecialFormBase
- {
- protected override Expression Compile(Compiler compiler, ISequence rest, Scope scope)
- {
- List<Expression> vars = new List<Expression>();
- List<Expression> values = new List<Expression>();
- BuildVarsAndValues(compiler, (PersistentVector)rest.first(), vars, values, scope);
-
- var body = DoForm.CompileDo(compiler, values, rest.rest(), null, scope);
-
- var result = Expression.Variable(body.Type, "bindingResult");
-
- return Expression.Block( new [] { result },
- Utils.SimpleCallHelper(typeof(VarBase).GetMethod("PushThreadBindings"), Expression.NewArrayInit(typeof(VarBase), vars), Expression.NewArrayInit(typeof(object), values)),
- Expression.TryFinally(
- Expression.Assign(result, body),
- Utils.SimpleCallHelper(typeof(VarBase).GetMethod("PopThreadBindings"))),
- result);
- }
-
- public static void BuildVarsAndValues(Compiler compiler, IList vector, List<Expression> vars, List<Expression> values, Scope scope)
- {
- for (int i = 0; i < vector.Count; i+=2)
- {
- var sym = (Symbol)vector[i];
- var val = vector[i + 1];
-
- var var = compiler.CompileToVar(sym, false);
- var value = compiler.CompileToExpression(val, scope);
-
- vars.Add(var);
- values.Add(value);
- }
- }
- }
-
- class LetForm : SpecialFormBase
- {
- protected override Expression Compile(Compiler compiler, ISequence rest, Scope scope)
- {
- scope = new Scope(scope);
-
- List<Expression> vars = new List<Expression>();
- List<Expression> assigns = new List<Expression>();
- BuildVariablesAndAssignments(compiler, (PersistentVector)rest.first(), vars, assigns, scope);
-
- return Expression.Block(
- from v in vars select (ParameterExpression)v,
- DoForm.CompileDo(compiler, assigns, rest.rest(), null, scope));
- }
-
- public static void BuildVariablesAndAssignments(Compiler compiler, IList vector, List<Expression> vars, List<Expression> assigns, Scope scope)
- {
- for (int i = 0; i < vector.Count; i += 2)
- {
- var sym = (Symbol)vector[i];
- var val = vector[i + 1];
-
- var value = compiler.CompileToExpression(val, scope);
- var varexp = Expression.Variable(value.Type, sym.ToString());
- scope[sym] = varexp;
- vars.Add(varexp);
-
- assigns.Add(Expression.Assign(varexp, value));
- }
- }
- }
-
- class IfForm : SpecialFormBase
- {
- protected override Expression Compile(Compiler compiler, ISequence rest, Scope scope)
- {
- var cond = compiler.CompileToExpression(rest.first(), scope); rest=rest.rest();
- var t = compiler.CompileToExpression(rest.first(), scope); rest=rest.rest();
-
- Expression f;
- if (rest == null)
- f = Expression.Constant(null);
- else
- f = compiler.CompileToExpression(rest.first(),scope);
-
- Type result = t.Type;
- if (result != f.Type)
- result = typeof(object);
-
- if (result == typeof(void))
- result = typeof(object);
-
- return Expression.Condition(ToBool(cond), Wrap(result, t), Wrap(result, f));
- }
-
- private Expression Wrap(Type result, Expression e)
- {
- if (e.Type == typeof(void))
- return Expression.Block(e, Expression.Constant(null));
- return Expression.Convert(e, result);
- }
-
- internal static Expression ToBool(Expression cond)
- {
- if (cond.Type == typeof(bool))
- return cond;
-
- var temp = Expression.Variable(typeof(object), "temp");
- return Expression.Block(new[] { temp },
- Expression.Assign(temp, Expression.Convert(cond, typeof(object))),
- Expression.Not(Expression.Or(
- Expression.Equal(Expression.Constant(null), temp),
- Expression.Call(Expression.Constant(false), "Equals", new Type[0], temp))
- ));
- }
- }
-
- class NewForm : SpecialFormBase
- {
- protected override Expression Compile(Compiler compiler, ISequence rest, Scope scope)
- {
- var symbol = (Symbol)rest.first();
- var t = Compiler.FindType(symbol);
-
- if (t == null)
- throw new System.TypeLoadException(symbol.ToString());
-
- var args = compiler.CompileArguments(rest.rest(), scope);
- args = ArrayUtils.Insert(Expression.Constant(t.FullName), args);
-
- return Expression.Dynamic(BinderFactory.New(symbol.meta(), t), t, args);
- }
- }
-
- class InNsForm : SpecialFormBase
- {
- protected override Expression Compile(Compiler compiler, ISequence rest, Scope scope)
- {
- return Utils.SimpleCallHelper(
- Expression.Constant(Namespace.CurrentNs),
- Namespace.CurrentNs.GetType().GetMethod("set"),
- Utils.SimpleCallHelper(typeof(Namespace).GetMethod("findOrCreate"),
- Expression.Convert(compiler.CompileToExpression(rest.first(), scope), typeof(Symbol))));
- }
- }
- }
- }