Example #1
0
        public override string VisitArrayAccessExpr(AstArrayAccessExpr arr, int data = 0)
        {
            var sub  = arr.SubExpression.Accept(this);
            var args = string.Join(", ", arr.Arguments.Select(a => a.Accept(this)));

            return($"{sub}[{args}]");
        }
Example #2
0
        public override NodeFinderResult VisitArrayAccessExpr(AstArrayAccessExpr arr, int index = 0)
        {
            if (GetRelativeLocation(arr.SubExpression.Location, index) == RelativeLocation.Same)
            {
                return(arr.SubExpression.Accept(this, index));
            }

            if (GetRelativeLocation(arr.Arguments[0].Location, index) == RelativeLocation.Same)
            {
                return(arr.Arguments[0].Accept(this, index));
            }

            return(new NodeFinderResult(arr.Scope, expr: arr));
        }
Example #3
0
        private IEnumerable <AstConstantDeclaration> SplitConstantDeclaration(AstConstantDeclaration v)
        {
            v.Pattern.SetFlag(ExprFlags.IsDeclarationPattern, true);
            switch (v.Pattern)
            {
            case AstCompCallExpr cc when cc.Name.Name == "id":
                cc.AttachTo(v);
                v.Name = InferType(cc, null) as AstIdExpr;
                break;

            case AstIdExpr name:
                // ok, do nothing
                v.Name = name;
                break;

            case AstTupleExpr t:
                v.Name = new AstIdExpr(GetUniqueName(t.ToString()), false, t);

                // create new declarations for sub patterns
                var index = 0;
                foreach (var subPattern in t.Values)
                {
                    var init = new AstArrayAccessExpr(
                        new AstConstantRef(v, v.Initializer),
                        new AstNumberExpr(NumberData.FromBigInt(index), Location: v.Initializer));
                    var sub = new AstConstantDeclaration(subPattern, null, init, v.Documentation, null, Location: v);
                    sub.Scope = v.Scope;
                    sub.SetFlags(v.GetFlags());

                    yield return(sub);

                    index += 1;
                }

                v.Pattern = v.Name;
                break;

            default:
                ReportError(v.Pattern, $"Invalid pattern in variable declaration");
                break;
            }
        }
Example #4
0
        private IEnumerable <AstVariableDecl> SplitVariableDeclaration(AstVariableDecl v)
        {
            v.Pattern.SetFlag(ExprFlags.IsDeclarationPattern, true);
            switch (v.Pattern)
            {
            case AstCompCallExpr cc when cc.Name.Name == "id":
                cc.AttachTo(v);
                v.Name = InferType(cc, null) as AstIdExpr;
                break;

            case AstIdExpr name:
                // ok, do nothing
                v.Name = name;
                break;

            case AstTupleExpr t:
            {
                v.Name    = new AstIdExpr(GetUniqueName(t.ToString()), false, t);
                v.Pattern = v.Name;

                //var initClone = v.Initializer.Clone();
                //initClone.AttachTo(v);
                //initClone.SetFlag(ExprFlags.ValueRequired, true);
                //initClone = InferType(initClone, null);

                //AstVariableDecl CreateSub(int index, string name)
                //{
                //    var init = mCompiler.ParseExpression(
                //        $"@{name}(§init)",
                //        new Dictionary<string, AstExpression>
                //        {
                //                { "init", new AstVariableRef(v, v.Initializer) }
                //        });
                //    var sub = new AstVariableDecl(t.Values[index], null, init, Location: v);
                //    sub.Scope = v.Scope;
                //    sub.SetFlags(v.GetFlags());
                //    return sub;
                //}
                //if (initClone.Type is PointerType pt1 && pt1.TargetType is AnyType)
                //{
                //    // create new declarations for sub patterns
                //    yield return CreateSub(0, "ptr_of_any");
                //    yield return CreateSub(1, "type_info_of_any");
                //    break;
                //}
                //else if (initClone.Type is PointerType pt2 && pt2.TargetType is TraitType)
                //{
                //    // create new declarations for sub patterns
                //    yield return CreateSub(0, "ptr_of_trait");
                //    yield return CreateSub(1, "vtable_of_trait");
                //    break;
                //}
                //else
                //{
                // create new declarations for sub patterns
                var index = 0;
                foreach (var subPattern in t.Values)
                {
                    var init = new AstArrayAccessExpr(
                        new AstVariableRef(v, v.Initializer),
                        new AstNumberExpr(NumberData.FromBigInt(index), Location: v.Initializer));
                    var sub = new AstVariableDecl(subPattern, null, init, v.Mutable, v.Documentation, Location: v);
                    sub.Scope = v.Scope;
                    sub.SetFlags(v.GetFlags());

                    yield return(sub);

                    index += 1;
                }
                break;
                //}
            }

            default:
                ReportError(v.Pattern, $"Invalid pattern in variable declaration");
                break;
            }
        }
Example #5
0
 public virtual ReturnType VisitArrayAccessExpr(AstArrayAccessExpr expr, DataType data = default) => default;
Example #6
0
        private AstExpression MatchPatternWithExpression(AstAssignment ass, AstExpression pattern, AstExpression value)
        {
            // check for operator set[]
            if (ass.Pattern is AstArrayAccessExpr arr)
            {
                // before we search for operators, make sure that all impls for both arguments have been matched
                GetImplsForType(arr.SubExpression.Type);
                GetImplsForType(arr.Arguments[0].Type);
                GetImplsForType(value.Type);

                var ops = ass.Scope.GetNaryOperators("set[]", arr.SubExpression.Type, arr.Arguments[0].Type, value.Type);
                if (ops.Count == 0)
                {
                    var type = arr.SubExpression.Type;
                    if (type is ReferenceType r)
                    {
                        type = r.TargetType;
                    }
                    else
                    {
                        type = ReferenceType.GetRefType(type, true);
                    }
                    ops = ass.Scope.GetNaryOperators("set[]", type, arr.Arguments[0].Type, value.Type);
                }

                if (ops.Count == 0)
                {
                    if (!pattern.TypeInferred)
                    {
                        pattern.SetFlag(ExprFlags.AssignmentTarget, false);
                        ass.Pattern = pattern = InferType(pattern, null);
                    }
                }
                else if (ops.Count == 1)
                {
                    arr.SubExpression = HandleReference(arr.SubExpression, ops[0].ArgTypes[0], null);
                    var args = new List <AstExpression>
                    {
                        arr.SubExpression,
                        arr.Arguments[0],
                        value
                    };
                    var opCall = new AstNaryOpExpr("set[]", args, value.Location);
                    opCall.ActualOperator = ops[0];
                    opCall.Replace(value);
                    ass.OnlyGenerateValue = true;
                    return(InferType(opCall, null));
                }
                else
                {
                    ReportError(ass, $"Multiple operators 'set[]' match the types ({arr.SubExpression.Type}, {arr.Arguments[0].Type}, {value.Type})");
                }
            }

            if (ass.Operator != null)
            {
                var assOp   = ass.Operator + "=";
                var valType = LiteralTypeToDefaultType(value.Type);

                // before we search for operators, make sure that all impls for both arguments have been matched
                GetImplsForType(pattern.Type);
                GetImplsForType(valType);

                var ops = ass.Scope.GetBinaryOperators(assOp, pattern.Type, valType);
                if (ops.Count == 0)
                {
                    var type = pattern.Type;
                    if (type is ReferenceType r)
                    {
                        type = r.TargetType;
                    }
                    else
                    {
                        type = ReferenceType.GetRefType(type, true);
                    }
                    ops = ass.Scope.GetBinaryOperators(assOp, type, valType);
                }

                if (ops.Count == 1)
                {
                    ass.OnlyGenerateValue = true;
                    pattern = HandleReference(pattern, ops[0].LhsType, null);
                    var opCall = new AstBinaryExpr(assOp, pattern, value, value.Location);
                    opCall.Replace(value);
                    return(InferType(opCall, null));
                }
                else if (ops.Count > 1)
                {
                    ReportError(ass, $"Multiple operators '{assOp}' match the types {PointerType.GetPointerType(pattern.Type, true)} and {value.Type}");
                }
            }

            switch (pattern)
            {
            case AstIdExpr id:
            {
                if (!id.GetFlag(ExprFlags.IsLValue))
                {
                    ReportError(pattern, $"Can't assign to '{id}' because it is not an lvalue");
                }

                if (ass.Operator != null)
                {
                    AstExpression newVal = new AstBinaryExpr(ass.Operator, pattern, value, value.Location);
                    newVal.Replace(value);
                    newVal = InferType(newVal, pattern.Type);

                    return(newVal);
                }

                ConvertLiteralTypeToDefaultType(ass.Value, pattern.Type);

                return(CheckType(ass.Value, ass.Pattern.Type, $"Can't assign a value of type {ass.Value.Type} to a pattern of type {ass.Pattern.Type}"));
            }

            case AstTupleExpr t:
            {
                if (value is AstTupleExpr v)
                {
                    if (t.Values.Count != v.Values.Count)
                    {
                        ReportError(ass, $"Can't assign the tuple '{v}' to the pattern '{t}' because the amount of values does not match");
                        return(value);
                    }

                    // create new assignments for all sub values
                    for (int i = 0; i < t.Values.Count; i++)
                    {
                        var subPat = t.Values[i];
                        var subVal = v.Values[i];
                        var subAss = new AstAssignment(subPat, subVal, ass.Operator, ass.Location);
                        subAss.Scope = ass.Scope;
                        subAss.Value = MatchPatternWithExpression(subAss, subPat, subVal);
                        ass.AddSubAssignment(subAss);
                    }
                }
                else
                {
                    var tmp = new AstTempVarExpr(value);
                    tmp.SetFlag(ExprFlags.IsLValue, true);

                    // create new assignments for all sub values
                    for (int i = 0; i < t.Values.Count; i++)
                    {
                        AstExpression subVal = new AstArrayAccessExpr(tmp, new AstNumberExpr(i));
                        subVal.Scope = ass.Scope;
                        subVal       = InferType(subVal, t.Values[i].Type);

                        var subAss = new AstAssignment(t.Values[i], subVal, ass.Operator, ass.Location);
                        subAss.Scope = ass.Scope;
                        subAss.Value = MatchPatternWithExpression(subAss, t.Values[i], subVal);
                        ass.AddSubAssignment(subAss);
                    }
                }
                break;
            }

            case AstDereferenceExpr de:
            {
                if (!pattern.GetFlag(ExprFlags.IsLValue))
                {
                    ReportError(pattern, $"Can't assign to '{pattern}' because it is not an lvalue");
                }

                if (ass.Operator != null)
                {
                    if (!de.SubExpression.GetFlag(ExprFlags.IsLValue))
                    {
                        AstExpression tmp = new AstTempVarExpr(de.SubExpression);
                        tmp.SetFlag(ExprFlags.IsLValue, true);
                        tmp = InferType(tmp, de.SubExpression.Type);

                        de.SubExpression = tmp;
                    }

                    AstExpression newVal = new AstBinaryExpr(ass.Operator, pattern, value, value.Location);
                    newVal.Replace(value);
                    newVal = InferType(newVal, pattern.Type);
                    return(newVal);
                }

                ConvertLiteralTypeToDefaultType(ass.Value, pattern.Type);


                return(CheckType(ass.Value, ass.Pattern.Type, $"Can't assign a value of type {value.Type} to a pattern of type {pattern.Type}"));
            }

            case AstDotExpr dot:
            {
                if (!pattern.GetFlag(ExprFlags.IsLValue))
                {
                    ReportError(pattern, $"Can't assign to '{pattern}' because it is not an lvalue");
                }

                if (ass.Operator != null)
                {
                    AstExpression tmp = new AstTempVarExpr(dot.Left, true);
                    tmp.SetFlag(ExprFlags.IsLValue, true);
                    //tmp = new AstDereferenceExpr(tmp, tmp.Location);
                    tmp = InferType(tmp, dot.Left.Type);

                    dot.Left = tmp;

                    AstExpression newVal = new AstBinaryExpr(ass.Operator, pattern, value, value.Location);
                    newVal.Replace(value);
                    newVal = InferType(newVal, pattern.Type);
                    return(newVal);
                }

                ConvertLiteralTypeToDefaultType(ass.Value, pattern.Type);


                return(CheckType(ass.Value, ass.Pattern.Type, $"Can't assign a value of type {value.Type} to a pattern of type {pattern.Type}"));
            }

            case AstArrayAccessExpr index:
            {
                if (!pattern.GetFlag(ExprFlags.IsLValue))
                {
                    ReportError(pattern, $"Can't assign to '{pattern}' because it is not an lvalue");
                }

                if (ass.Operator != null)
                {
                    AstExpression tmp = new AstTempVarExpr(index.SubExpression, true);
                    tmp.SetFlag(ExprFlags.IsLValue, true);
                    tmp = InferType(tmp, index.SubExpression.Type);

                    index.SubExpression = tmp;

                    AstExpression newVal = new AstBinaryExpr(ass.Operator, pattern, value, value.Location);
                    newVal.Replace(value);
                    newVal = InferType(newVal, pattern.Type);
                    return(newVal);
                }

                ConvertLiteralTypeToDefaultType(ass.Value, pattern.Type);


                return(CheckType(ass.Value, ass.Pattern.Type, $"Can't assign a value of type {value.Type} to a pattern of type {pattern.Type}"));
            }

            case AstExpression e when e.Type is ReferenceType r:
            {
                if (!pattern.GetFlag(ExprFlags.IsLValue))
                {
                    ReportError(pattern, $"Can't assign to '{pattern}' because it is not an lvalue");
                }

                // TODO: check if can be assigned to id (e.g. not const)
                if (ass.Operator != null)
                {
                    AstExpression newVal = new AstBinaryExpr(ass.Operator, pattern, value, value.Location);
                    newVal.Replace(value);
                    newVal = InferType(newVal, pattern.Type);
                    return(newVal);
                }

                ConvertLiteralTypeToDefaultType(ass.Value, pattern.Type);
                return(CheckType(ass.Value, r.TargetType, $"Can't assign a value of type {value.Type} to a pattern of type {pattern.Type}"));
            }

            default: ReportError(pattern, $"Can't assign to '{pattern.Type}', not an lvalue"); break;
            }

            return(value);
        }
Example #7
0
        private void AnalyseFunction(AstFuncExpr func)
        {
            if (func.IsAnalysed)
            {
                return;
            }
            func.IsAnalysed = true;

            Log($"Analysing function {func.Name}", $"impl = {func.ImplBlock?.Accept(new SignatureAstPrinter())}", $"poly = {func.IsGeneric}");
            PushLogScope();

            var prevCurrentFunction = currentFunction;

            currentFunction = func;
            try
            {
                if (func.SelfType != SelfParamType.None)
                {
                    var p = func.Parameters[0];
                    if (p.Name == null)
                    {
                        p.Name = new AstIdExpr("self", false, p.Location);
                    }

                    if (func.ImplBlock.TargetType is StructType @struct)
                    {
                        ComputeStructMembers(@struct.Declaration);
                        foreach (var m in @struct.Declaration.Members)
                        {
                            AstExpression expr = new AstDotExpr(new AstSymbolExpr(p), new AstIdExpr(m.Name, false, p.Location), p.Location);
                            expr.AttachTo(func, func.SubScope);
                            expr = InferType(expr, m.Type);

                            // define use if no parameter has the same name
                            if (!func.Parameters.Any(pa => pa.Name?.Name == m.Name))
                            {
                                var(ok, other) = func.SubScope.DefineUse(m.Name, expr, false, out var use);

                                if (!ok)
                                {
                                    ReportError(p, $"A symbol with name '{m.Name}' already exists", ("Other here:", other));
                                }
                            }
                        }
                    }
                }

                if (func.IsGeneric)
                {
                    return;
                }

                if (func.TryGetDirective("linkname", out var ln))
                {
                    if (ln.Arguments.Count != 1)
                    {
                        ReportError(ln, $"#linkname requires exactly one argument!");
                    }
                    else
                    {
                        var arg = ln.Arguments[0];
                        arg.SetFlag(ExprFlags.ValueRequired, true);
                        arg = ln.Arguments[0] = InferType(arg, null);
                        if (!(arg.Value is string))
                        {
                            ReportError(arg, $"Argument to #linkname must be a constant string!");
                        }
                    }
                }

                // define parameters
                foreach (var p in func.Parameters)
                {
                    p.ContainingFunction = func;
                    if (p.Name != null)
                    {
                        var(ok, other) = func.SubScope.DefineSymbol(p);
                        if (!ok)
                        {
                            ReportError(p, $"Duplicate parameter '{p.Name}'", ("Other parameter here:", other));
                        }
                    }

                    if (p.DefaultValue != null)
                    {
                        p.DefaultValue.Scope = func.Scope;
                        p.DefaultValue       = InferTypeHelper(p.DefaultValue, p.Type, new TypeInferenceContext {
                            TypeOfExprContext = p.Type
                        });
                        ConvertLiteralTypeToDefaultType(p.DefaultValue, p.Type);
                        p.DefaultValue = CheckType(p.DefaultValue, p.Type);
                        if (p.DefaultValue.Type != p.Type && !p.DefaultValue.Type.IsErrorType)
                        {
                            ReportError(p.DefaultValue,
                                        $"The type of the default value ({p.DefaultValue.Type}) does not match the type of the parameter ({p.Type})");
                        }
                    }
                }

                if (func.ReturnTypeExpr != null)
                {
                    func.ReturnTypeExpr.Mutable = true;
                }

                if (func.ReturnTypeExpr?.Name != null)
                {
                    func.ReturnTypeExpr.ContainingFunction = func;
                    func.ReturnTypeExpr.IsReturnParam      = true;
                    var(ok, other) = func.SubScope.DefineSymbol(func.ReturnTypeExpr);
                    if (!ok)
                    {
                        ReportError(func.ReturnTypeExpr, $"A symbol with name '{func.ReturnTypeExpr.Name.Name}' already exists in current scope", ("Other symbol here:", other));
                    }
                }
                else if (func.ReturnTypeExpr != null)
                {
                    func.SubScope.DefineSymbol(func.ReturnTypeExpr, ".ret");
                }
                if (func.ReturnTypeExpr?.TypeExpr is AstTupleExpr t)
                {
                    int index = 0;
                    foreach (var m in t.Types)
                    {
                        if (m.Name == null)
                        {
                            continue;
                        }
                        m.Mutable = true;
                        AstExpression access = new AstArrayAccessExpr(new AstSymbolExpr(func.ReturnTypeExpr), new AstNumberExpr(index, Location: func.ReturnTypeExpr.Location), func.ReturnTypeExpr.Location);
                        access         = InferType(access, null);
                        var(ok, other) = func.SubScope.DefineUse(m.Name.Name, access, false, out var use);
                        if (!ok)
                        {
                            ReportError(m, $"A symbol with name '{m.Name.Name}' already exists in current scope", ("Other symbol here:", other));
                        }
                        m.Symbol = use;
                        ++index;
                    }
                }

                if (func.FunctionType.IsErrorType || func.FunctionType.IsPolyType)
                {
                    return;
                }

                if (func.Body != null && !func.IsMacroFunction)
                {
                    var errs = PushSilentErrorHandler();
                    func.Body.AttachTo(func, func.SubScope);
                    InferType(func.Body, null);

                    if (func.ReturnTypeExpr != null && !func.Body.GetFlag(ExprFlags.Returns))
                    {
                        // TODO: check that all return values are set
                        var ret = new AstReturnStmt(null, new Location(func.Body.End));
                        ret.Scope = func.Body.SubScope;
                        ret       = AnalyseReturnStatement(ret);
                        func.Body.Statements.Add(ret);
                        func.Body.SetFlag(ExprFlags.Returns, true);
                    }

                    PopErrorHandler();

                    if (errs.HasErrors)
                    {
                        if (func.IsPolyInstance && func.InstantiatedAt != null)
                        {
                            ReportError($"Errors in polymorphic function '{func.Name}':");
                            errs.ForwardErrors(CurrentErrorHandler);

                            void ReportSources(AstFuncExpr func, string indent = "")
                            {
                                if (func.InstantiatedAt == null)
                                {
                                    return;
                                }
                                foreach (var loc in func.InstantiatedAt)
                                {
                                    ReportError(loc, indent + $"Failed to instantiate function '{func.Name}'");
                                }
                                foreach (var loc in func.InstantiatedBy)
                                {
                                    ReportError(loc, indent + $"Failed to instantiate function '{func.Name}'");
                                    ReportSources(loc, indent + "  ");
                                }
                            }

                            ReportError($"Caused from invocations here:");
                            ReportSources(func);
                        }
                        else
                        {
                            errs.ForwardErrors(CurrentErrorHandler);
                        }
                    }
                    else
                    {
                        PassVariableLifetimes(func);
                    }
                }
            }
            finally
            {
                currentFunction = prevCurrentFunction;
                PopLogScope();
                Log($"Finished function {func.Name}");
            }
        }