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}]"); }
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)); }
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; } }
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; } }
public virtual ReturnType VisitArrayAccessExpr(AstArrayAccessExpr expr, DataType data = default) => default;
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); }
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}"); } }