Ejemplo n.º 1
0
        private static IType Infer(IDictionary<string, IType> env, INode node, IType[] known)
        {
            Func<INode, IType> taggedType = tagged =>
                {
                    if (!Type.Const.ContainsKey(tagged.Type))
                    {
                        throw new InvalidOperationException(String.Format("unknown basic type : \"{0}\"", tagged.Type));
                    }
                    return Type.Const[tagged.Type];
                };

            known = known ?? new IType[] {};

            if ((node.Name is string) && (node.Args == null) && (node.Term == null))
            {
                if (!env.ContainsKey((string) node.Name))
                {
                    throw new InvalidOperationException(String.Format("unknown identifier : \"{0}\"", node.Name));
                }
                return Unifier.Fresh(env[(string) node.Name], known);
            }

            if ((node.Name == null) && (node.Type != null))
            {
                return taggedType(node);
            }

            if ((node.Name is INode) && (node.Args != null) && (node.Term == null))
            {
                List<IType> args = node.Args.Select(arg => Infer(env, arg, known)).ToList();
                var type = new Var();
                args.Add(type);
                Unifier.Unify(new Type(Type.Function, args.ToArray()), Infer(env, (INode) node.Name, known));
                return type;
            }

            if ((node.Name is string) && (node.Args != null) && (node.Term is INode))
            {
                // Optional: node.Type (string)
                List<IType> types = known.ToList();
                var args = new List<IType>();
                Type type;
                foreach (INode arg in node.Args)
                {
                    IType var;
                    if (arg.Type == null)
                    {
                        var = new Var();
                        types.Add(var);
                    }
                    else
                    {
                        var = taggedType(arg);
                    }
                    env[(string) arg.Name] = var;
                    args.Add(var);
                }
                args.Add(Infer(env, (INode) node.Term, types.ToArray()));
                if (node.Type != null)
                {
                    Unifier.Unify(args[args.Count - 1], taggedType(node));
                }
                type = new Type(Type.Function, args.ToArray());

                if (((string) node.Name).Length > 0)
                {
                    env[(string) node.Name] = type;
                }
                return type;
            }

            if ((node.Name is string) && (((string) node.Name).Length > 0) && (node.Term is INode))
            {
                // Optional: node.Type (string)
                IType type = Infer(env, (INode) node.Term, known);
                if (node.Type != null)
                {
                    Unifier.Unify(type, taggedType(node));
                }
                return (env[(string) node.Name] = type);
            }
            throw new ArgumentOutOfRangeException("node", "missing or invalid attribute(s)");
        }