protected override void VisitAssignmentSyntax(AssignmentSyntax pNode) { base.VisitAssignmentSyntax(pNode); if (pNode.Value.Type == SmallTypeCache.NoValue) { CompilerErrors.ExpressionNoValue(pNode.Value.Span); } var isTuple = pNode.Value.Type.IsTuple; for (int i = 0; i < pNode.Variables.Count; i++) { //Check if we are assigning to a const variable if (_locals.TryGetVariable(pNode.Variables[i].Value, out LocalDefinition ld) && ld.IsConst) { CompilerErrors.CannotAssignCost(pNode.Variables[i], pNode.Variables[i].Span); } var t = isTuple ? pNode.Value.Type.GetFieldType(i) : pNode.Value.Type; //We have to set the type of discards so the tuple is created properly if (SyntaxHelper.IsDiscard(pNode.Variables[i])) { ((DiscardSyntax)pNode.Variables[i]).SetType(t); } } }
protected override void VisitDeclarationSyntax(DeclarationSyntax pNode) { Visit(pNode.Value); var isTuple = pNode.Value.Type.IsTuple; for (int i = 0; i < pNode.Variables.Count; i++) { if (!SyntaxHelper.IsDiscard(pNode.Variables[i])) { if (_locals.IsVariableDefinedInScope(pNode.Variables[i].Value)) { CompilerErrors.IdentifierAlreadyDeclared(pNode.Variables[i], pNode.Span); } else { //We do not allow variables to have the same names as types //This makes it easier to check for "static" method/fields if (SmallTypeCache.IsTypeDefined(pNode.Variables[i].Value)) { CompilerErrors.ValueDefinedAsType(pNode.Variables[i], pNode.Variables[i].Span); } else { //For tuple types we set the individual variables to the tuple field type... not the tuple itself var t = isTuple ? pNode.Value.Type.GetFieldType(i) : pNode.Value.Type; //Report expression errors and change the type to Undefined so we don't get further no expression errors if (pNode.Value.Type == SmallTypeCache.NoValue) { CompilerErrors.ExpressionNoValue(pNode.Value.Span); t = SmallTypeCache.Undefined; } pNode.Variables[i].SetType(t); _locals.DefineVariableInScope(pNode.Variables[i].Value, LocalDefinition.Create(pNode.IsConst, pNode.Variables[i].Type)); } } } } //Check that we are declaring the proper number of variables if (isTuple && pNode.Value.Type.GetFieldCount() != pNode.Variables.Count) { CompilerErrors.DeclarationCountMismatch(pNode.Value.Type.GetFieldCount(), pNode.Variables.Count, pNode.Span); } }
protected override void VisitMethodCallSyntax(MethodCallSyntax pNode) { base.VisitMethodCallSyntax(pNode); SmallType[] types = new SmallType[pNode.Arguments.Count]; for (int i = 0; i < types.Length; i++) { types[i] = pNode.Arguments[i].Type; if (types[i] == SmallTypeCache.NoValue) { CompilerErrors.ExpressionNoValue(pNode.Arguments[i].Span); } } if (SyntaxHelper.HasUndefinedCastAsArg(pNode)) { IList <MethodDefinition> matches = _unit.GetAllMatches(Namespace, pNode.Value, pNode.Arguments.Count); if (matches.Count > 1) { //If multiple matches are found the implicit cast could map to either method, so we can't tell CompilerErrors.InferImplicitCast(pNode.Span); return; } else if (matches.Count == 1) { //Check if we can determine implicit cast type yet for (int j = 0; j < Math.Min(matches[0].ArgumentTypes.Count, pNode.Arguments.Count); j++) { if (SyntaxHelper.IsUndefinedCast(pNode.Arguments[j])) { TrySetImplicitCastType(pNode.Arguments[j], matches[0].ArgumentTypes[j]); types[j] = pNode.Arguments[j].Type; } } } } //Check to ensure this method exists var result = SyntaxHelper.FindMethodOnType(out MethodDefinition m, _unit, Namespace, pNode.Value, CurrentType, types); switch (result) { case Compiler.FindResult.NotFound: CompilerErrors.MethodNotFound(m, Struct, pNode.Value, pNode.Arguments, pNode.Span); return; case Compiler.FindResult.IncorrectScope: CompilerErrors.MethodNotInScope(m, Struct, pNode.Value, pNode.Arguments, pNode.Span); return; } for (int i = 0; i < m.ArgumentTypes.Count; i++) { ForceCastLiteral(m.ArgumentTypes[i], pNode.Arguments[i]); } //Poly our method definition to match any generic types m = m.MakeConcreteDefinition(CurrentType); pNode.SetType(m.ReturnType); }