Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: 5b18f455b7
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

file 175 lines (142 sloc) 6.567 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
using System;
using System.Collections.Generic;
using System.Linq;
using Rook.Compiling.Syntax;
using Rook.Compiling.Types;

namespace Rook.Compiling
{
    public class Scope
    {
        private readonly Func<TypeVariable> CreateTypeVariable;

        private readonly IDictionary<string, DataType> locals;
        protected readonly Scope parent;

        protected Scope(Scope parent, Func<TypeVariable> createTypeVariable)
        {
            CreateTypeVariable = createTypeVariable;
            locals = new Dictionary<string, DataType>();
            this.parent = parent;
        }

        public static Scope CreateRoot(TypeChecker typeChecker)
        {
            var scope = new Scope(null, typeChecker.CreateTypeVariable);

            DataType @int = NamedType.Integer;
            DataType @bool = NamedType.Boolean;

            DataType integerOperation = NamedType.Function(new[] { @int, @int }, @int);
            DataType integerComparison = NamedType.Function(new[] { @int, @int }, @bool);
            DataType booleanOperation = NamedType.Function(new[] { @bool, @bool }, @bool);

            scope["<"] = integerComparison;
            scope["<="] = integerComparison;
            scope[">"] = integerComparison;
            scope[">="] = integerComparison;
            scope["=="] = integerComparison;
            scope["!="] = integerComparison;

            scope["+"] = integerOperation;
            scope["*"] = integerOperation;
            scope["/"] = integerOperation;
            scope["-"] = integerOperation;

            scope["&&"] = booleanOperation;
            scope["||"] = booleanOperation;
            scope["!"] = NamedType.Function(new[] { @bool }, @bool);

            var T = typeChecker.CreateTypeVariable(); //TypeVariable 0
            var S = typeChecker.CreateTypeVariable(); //TypeVariable 1

            scope["??"] = NamedType.Function(new DataType[] { NamedType.Nullable(T), T }, T);
            scope["Print"] = NamedType.Function(new[] { T }, NamedType.Void);
            scope["Nullable"] = NamedType.Function(new[] { T }, NamedType.Nullable(T));
            scope["First"] = NamedType.Function(new[] { NamedType.Enumerable(T) }, T);
            scope["Take"] = NamedType.Function(new[] { NamedType.Enumerable(T), @int }, NamedType.Enumerable(T));
            scope["Skip"] = NamedType.Function(new[] { NamedType.Enumerable(T), @int }, NamedType.Enumerable(T));
            scope["Any"] = NamedType.Function(new[] { NamedType.Enumerable(T) }, @bool);
            scope["Count"] = NamedType.Function(new[] { NamedType.Enumerable(T) }, @int);
            scope["Select"] = NamedType.Function(new[] { NamedType.Enumerable(T), NamedType.Function(new[] { T }, S) }, NamedType.Enumerable(S));
            scope["Where"] = NamedType.Function(new[] { NamedType.Enumerable(T), NamedType.Function(new[] { T }, @bool) }, NamedType.Enumerable(T));
            scope["Each"] = NamedType.Function(new[] { NamedType.Vector(T) }, NamedType.Enumerable(T));
            scope["Index"] = NamedType.Function(new[] { NamedType.Vector(T), @int }, T);
            scope["Slice"] = NamedType.Function(new[] { NamedType.Vector(T), @int, @int }, NamedType.Vector(T));
            scope["Append"] = NamedType.Function(new DataType[] { NamedType.Vector(T), T }, NamedType.Vector(T));
            scope["With"] = NamedType.Function(new[] { NamedType.Vector(T), @int, T }, NamedType.Vector(T));

            return scope;
        }

        public Scope CreateLocalScope()
        {
            return new Scope(this, CreateTypeVariable);
        }

        public LambdaScope CreateLambdaScope()
        {
            return new LambdaScope(this, CreateTypeVariable);
        }

        public DataType this[string key]
        {
            set { locals[key] = value; }
        }

        public bool TryGetMemberScope(TypeRegistry typeRegistry, NamedType typeKey, out Scope typeMemberScope)
        {
            IEnumerable<Binding> typeMembers;
            if (typeRegistry.TryGetMembers(typeKey, out typeMembers))
            {
                var scope = new Scope(null, CreateTypeVariable);

                foreach (var member in typeMembers)
                    scope.TryIncludeUniqueBinding(member);

                typeMemberScope = scope;
                return true;
            }

            typeMemberScope = null;
            return false;
        }

        public bool TryGet(string key, out DataType value)
        {
            if (locals.ContainsKey(key))
            {
                value = FreshenGenericTypeVariables(locals[key]);
                return true;
            }

            if (parent == null)
            {
                value = null;
                return false;
            }

            return parent.TryGet(key, out value);
        }

        private DataType FreshenGenericTypeVariables(DataType type)
        {
            var substitutions = new Dictionary<TypeVariable, DataType>();
            var genericTypeVariables = type.FindTypeVariables().Where(IsGeneric);
            foreach (var genericTypeVariable in genericTypeVariables)
                substitutions[genericTypeVariable] = CreateTypeVariable();

            return type.ReplaceTypeVariables(substitutions);
        }

        public bool Contains(string key)
        {
            return locals.ContainsKey(key) || (parent != null && parent.Contains(key));
        }

        public bool TryIncludeUniqueBinding(Binding binding)
        {
            if (Contains(binding.Identifier))
                return false;

            this[binding.Identifier] = binding.Type;
            return true;
        }

        public virtual bool IsGeneric(TypeVariable typeVariable)
        {
            return parent == null || parent.IsGeneric(typeVariable);
        }
    }

    public class LambdaScope : Scope
    {
        private readonly List<TypeVariable> localNonGenericTypeVariables;

        public LambdaScope(Scope parent, Func<TypeVariable> createTypeVariable)
            : base(parent, createTypeVariable)
        {
            localNonGenericTypeVariables = new List<TypeVariable>();
        }

        public void TreatAsNonGeneric(IEnumerable<TypeVariable> typeVariables)
        {
            localNonGenericTypeVariables.AddRange(typeVariables);
        }

        public override bool IsGeneric(TypeVariable typeVariable)
        {
            if (localNonGenericTypeVariables.Contains(typeVariable))
                return false;

            return parent.IsGeneric(typeVariable);
        }
    }
}
Something went wrong with that request. Please try again.