Example #1
0
 private SignatureSearcher.Checks <OperatorTypeSignature> GetChecks(OperatorTypeSignature target)
 {
     return(new SignatureSearcher.Checks <OperatorTypeSignature>
     {
         Matches = (option) => option.CanAccept(target, _assignmentResolver),
         ExactComparison = CheckExact(target),
         LosslessComparison = CheckLossless(target)
     });
 }
Example #2
0
        private void AddOperator(MethodInfo methodInfo, SprakOperatorAttribute meta)
        {
            BuiltInFunction function = new BuiltInFunction(methodInfo, this);

            if (!Operator.TryParse(out Operator op, name: meta.OperatorName))
            {
                string message = $"{MethodName(methodInfo)} is declared to be an unrecognized operator: \"{meta.OperatorName}\"";
                throw new ArgumentException(message);
            }

            int paramCount = function.Parameters.Count;

            bool binary        = meta.InputsHint == InputSides.Both;
            int  requiredCount = binary ? 2 : 1;

            if (paramCount != requiredCount)
            {
                string desc = binary ? "binary" : "unary";

                string message = $"{MethodName(methodInfo)} was declared to be the {desc} operator \"{meta.OperatorName}\", " +
                                 $"but has {function.Parameters.Count} Sprak arguments";

                throw new ArgumentException(message);
            }

            InputSides inputs = meta.InputsHint;

            SprakType left  = null;
            SprakType right = null;

            switch (inputs)
            {
            case InputSides.Both:
                left  = function.Parameters[0];
                right = function.Parameters[1];
                break;

            case InputSides.Left:
                left = function.Parameters[0];
                break;

            case InputSides.Right:
                right = function.Parameters[0];
                break;
            }

            OperatorTypeSignature typeSignature
                = new OperatorTypeSignature(left, right, inputs);

            OperatorSignature signature = new OperatorSignature(op.Name, typeSignature);

            _operators.Add(signature, function);
        }
Example #3
0
        private Func <OperatorTypeSignature, int> CheckLossless(OperatorTypeSignature target)
        {
            int KeyFunction(OperatorTypeSignature subject)
            {
                int key = 0;;

                if (!_assignmentResolver.IsPerfect(target.LeftParam, subject.LeftParam))
                {
                    key++;
                }

                if (!_assignmentResolver.IsPerfect(target.RightParam, subject.RightParam))
                {
                    key++;
                }

                return(key);
            }

            return(KeyFunction);
        }
Example #4
0
        private Func <OperatorTypeSignature, int> CheckExact(OperatorTypeSignature target)
        {
            int KeyFunction(OperatorTypeSignature subject)
            {
                int key = 0;;

                if (target.LeftParam != subject.LeftParam)
                {
                    key++;
                }

                if (target.RightParam != subject.RightParam)
                {
                    key++;
                }

                return(key);
            }

            return(KeyFunction);
        }
Example #5
0
        public SignatureLookupResult TryFindMatch(string name, OperatorTypeSignature typeSignature)
        {
            SignatureLookupResult result = new SignatureLookupResult();
            var checks = GetChecks(typeSignature);

            Dictionary <OperatorTypeSignature, Func <Op> > opOptions;

            if (_operatorBindingLookup.TryGetOptions(name, out opOptions))
            {
                var searchResult = SignatureSearcher.Search(opOptions, checks, x => x);
                if (searchResult.Success)
                {
                    result.Success   = true;
                    result.Ambiguous = searchResult.Ambiguous;
                    result.OpBuilder = searchResult.Value;

                    return(result);
                }
            }

            Dictionary <OperatorTypeSignature, BuiltInFunction> builtinOptions;

            if (_builtInOperatorLookup.TryGetOptions(name, out builtinOptions))
            {
                var searchResult = SignatureSearcher.Search(builtinOptions, checks, x => x);
                if (searchResult.Success)
                {
                    result.Success         = true;
                    result.Ambiguous       = searchResult.Ambiguous;
                    result.FunctionInfo    = searchResult.Value.Info;
                    result.BuiltInFunction = searchResult.Value;

                    return(result);
                }
            }

            return(result);
        }
Example #6
0
        private void ResolveAssignment(VariableAssignment assignment, CompilationEnvironment env)
        {
            if (assignment.Indices.Count > 1)
            {
                env.Messages.AtExpression(assignment.Indices.Last().Index,
                                          Messages.MultipleIndices);
            }

            if (!assignment.ParentBlockHint
                .TryGetVariableInfo(assignment.Name, out VariableInfo nameInfo))
            {
                env.Messages.AtToken(assignment.NameToken,
                                     Messages.UnrecognizedName, assignment.NameToken.Content);
                return;
            }

            if (!assignment.IsDeclaration)
            {
                Block ancestor = assignment.ParentBlockHint;
                while (ancestor != null && ancestor != nameInfo.Source)
                {
                    ancestor = ancestor.ParentBlockHint;
                }

                if (ancestor == null)
                {
                    env.Messages.AtToken(assignment.NameToken,
                                         Messages.VariableFromDisconnectedBlock);
                }
            }

            if (nameInfo.DeclaredType == null)
            {
                // I don't think this should be possible, but this is all
                // very convoluted. I wish C# was more nullable-aware.
                throw new Exception("Declaration with Declaration Type");
            }

            SprakType dstType;

            if (assignment.Indices.Count == 0)
            {
                dstType = nameInfo.DeclaredType;
            }

            else
            {
                if (nameInfo.DeclaredType != SprakType.Array)
                {
                    env.Messages.AtToken(assignment.NameToken,
                                         Messages.CanOnlyIndexArrays, nameInfo.DeclaredType);
                }

                // Best we can do with array assignments until generic
                // type tracking is introduced.
                dstType = SprakType.Any;
            }

            SprakType srcType;

            if (assignment.Value == null)
            {
                srcType = nameInfo.DeclaredType;
            }

            else if (assignment.Value.TypeHint != null)
            {
                srcType = assignment.Value.TypeHint;
            }

            else
            {
                srcType = SprakType.Any;
            }

            if (assignment.IsDeclaration)
            {
                if (assignment.Operator != Operator.Set)
                {
                    env.Messages.AtToken(assignment.OperatorToken,
                                         Messages.InvalidDeclarationOperator);
                }

                if (assignment.Indices.Count > 0)
                {
                    env.Messages.AtExpression(assignment.Indices.First().Index,
                                              Messages.InvalidIndexDeclaration);
                }
            }
            else if (!assignment.Operator.IsAssignment)
            {
                env.Messages.AtToken(assignment.OperatorToken,
                                     Messages.ExpectedAssignmentOperator, assignment.Operator.Text);
                return;
            }
            else if (assignment.Operator.AssignmentOperation != null)
            {
                // I doubt I'll bother implementing right-only inputs.
                // (Like --i) They don't show up much.

                InputSides inputs;
                SprakType  left;
                SprakType  right;

                if (!assignment.HasValue)
                {
                    inputs = InputSides.Left;
                    left   = srcType;
                    right  = null;
                }
                else
                {
                    inputs = InputSides.Both;
                    left   = srcType;
                    right  = dstType;
                }

                // We need the name of the function to called before assignment.
                // That may or may not be the same name as that of the operator.
                string name = assignment.Operator.AssignmentOperation;

                OperatorTypeSignature signature
                    = new OperatorTypeSignature(left, right, inputs);

                SignatureLookupResult lookupResult = env.SignatureLookup
                                                     .TryFindMatch(name, signature);

                if (lookupResult.Success)
                {
                    assignment.BuiltInFunctionHint = lookupResult.BuiltInFunction;
                    assignment.OpHint = lookupResult.OpBuilder;
                    srcType           = lookupResult.BuiltInFunction.ReturnType;
                }
                else
                {
                    string operation = assignment.ToString();
                    env.Messages.AtExpression(assignment,
                                              Messages.UnresolvedOperation, operation);

                    srcType = SprakType.Any;
                }
            }

            if (!env.AssignmentLookup.IsAssignable(srcType, dstType))
            {
                env.Messages.AtExpression(
                    assignment, Messages.AssignmentTypeMismatch, srcType, dstType);
            }
        }
Example #7
0
        private void ResolveCallAndTypeHint(OperatorCall call, CompilationEnvironment env)
        {
            if (!Operator.TryParse(out Operator op, text: call.OperatorText))
            {
                env.Messages.AtToken(call.OperatorToken,
                                     Messages.UnrecognizedOperator, call.OperatorText);
                return;
            }

            if (op.IsAssignment)
            {
                env.Messages.AtToken(call.OperatorToken,
                                     Messages.IncorrectUseOfAssignment, op.Text);
                return;
            }

            call.TypeHint = null;

            if (call.LeftInput != null && call.LeftInput.TypeHint == null)
            {
                return;
            }

            if (call.RightInput != null && call.RightInput.TypeHint == null)
            {
                return;
            }

            SprakType  left  = call.LeftInput?.TypeHint;
            SprakType  right = call.RightInput?.TypeHint;
            InputSides inputs;

            if (left != null && right != null)
            {
                inputs = InputSides.Both;
            }

            else if (left != null)
            {
                inputs = InputSides.Left;
            }

            else
            {
                inputs = InputSides.Right;
            }

            OperatorTypeSignature signature
                = new OperatorTypeSignature(left, right, inputs);

            SignatureLookupResult lookupResult;

            lookupResult = env.SignatureLookup
                           .TryFindMatch(op.Name, signature);

            if (lookupResult.Success)
            {
                call.BuiltInFunctionHint = lookupResult.BuiltInFunction;
                call.TypeHint            = lookupResult.FunctionInfo?.ReturnType;
            }
            else
            {
                string operation = $"({call.LeftInput?.TypeHint?.Text})"
                                   + $" {call.OperatorToken.Content}"
                                   + $" ({call.RightInput?.TypeHint?.Text})";

                env.Messages.AtToken(call.OperatorToken,
                                     Messages.UnresolvedOperation, operation);
            }
        }