public override Expression ResolveTypes(ParserContext context, VariableScope varScope) { this.Root = this.Root.ResolveTypes(context, varScope); this.Index = this.Index.ResolveTypes(context, varScope); ResolvedType rootType = this.Root.ResolvedType; ResolvedType indexType = this.Index.ResolvedType; if (rootType.IsArray) { if (indexType.PrimitiveType != "int") { throw new ParserException(this.Index.FirstToken, "Array index must be an integer."); } this.ResolvedType = rootType.Generics[0]; } else if (rootType.IsIDictionary(context)) { if (!indexType.CanBeAssignedTo(rootType.Generics[0], context)) { throw new ParserException(this.Index.FirstToken, "Incorrect key type."); } this.ResolvedType = rootType.Generics[1]; } else { throw new System.NotImplementedException(); } return(this); }
public Expression ResolveTypesWithExteriorHint( ParserContext context, VariableScope varScope, ResolvedType[] expectedArgsAndReturnTypes) { VariableScope lambdaScope = new VariableScope(varScope); if (this.Args.Length != expectedArgsAndReturnTypes.Length - 1) { throw new ParserException(this.ArrowToken, "The expected number of args was " + (expectedArgsAndReturnTypes.Length - 1)); } for (int i = 0; i < this.Args.Length; ++i) { lambdaScope.DeclareVariable(this.Args[i].Value, expectedArgsAndReturnTypes[i]); } this.Code = Executable.ResolveTypesForCode(this.Code, context, lambdaScope); ResolvedType returnType = null; if (this.Code.Length == 1 && this.Code[0] is ExpressionAsExecutable) { returnType = ((ExpressionAsExecutable)this.Code[0]).Expression.ResolvedType; } else if (this.Code.Length > 0 && this.Code[this.Code.Length - 1] is ReturnStatement) { ReturnStatement ret = (ReturnStatement)this.Code[this.Code.Length - 1]; if (ret.Value == null) { throw new ParserException(ret.FirstToken, "Return statement in lambda must have a value."); } returnType = ret.Value.ResolvedType; } else { throw new ParserException(this.FirstToken, "Not implemented: the return is hiding in this lambda."); } ResolvedType expectedReturnType = expectedArgsAndReturnTypes[expectedArgsAndReturnTypes.Length - 1]; if (expectedReturnType == null) { expectedReturnType = returnType; } else { if (!returnType.CanBeAssignedTo(expectedReturnType, context)) { throw new ParserException(this.FirstToken, "This lambda does not seem to be returning the expected type."); } } List <ResolvedType> argTypes = new List <ResolvedType>(expectedArgsAndReturnTypes); argTypes.RemoveAt(argTypes.Count - 1); this.ResolvedType = ResolvedType.CreateFunction(expectedReturnType, argTypes.ToArray()); return(this); }
public void ResolveTypesForInitialData(ParserContext context, VariableScope varScope) { switch (this.InitialDataFormat) { case InitialDataFormatType.NONE: break; case InitialDataFormatType.ITEM_LIST: if (this.Class.Generics.Length != 1) { throw new ParserException(this.FirstToken, "The generics of this constructor does not support an initialization list."); } ResolvedType itemType = this.Class.Generics[0]; for (int i = 0; i < this.InitialDataValues.Length; ++i) { Expression item = this.InitialDataValues[i].ResolveTypes(context, varScope); this.InitialDataValues[i] = item; if (!itemType.CanBeAssignedTo(item.ResolvedType, context)) { throw new ParserException(item.FirstToken, "Incorrect type. Cannot convert a " + item.ResolvedType + " to a " + itemType); } } break; case InitialDataFormatType.KEY_VALUES: for (int i = 0; i < this.InitialDataValues.Length; ++i) { this.InitialDataKeys[i] = this.InitialDataKeys[i].ResolveTypes(context, varScope); this.InitialDataValues[i] = this.InitialDataValues[i].ResolveTypes(context, varScope); } break; case InitialDataFormatType.PROPERTIES: for (int i = 0; i < this.InitialDataValues.Length; ++i) { this.InitialDataValues[i] = this.InitialDataValues[i].ResolveTypes(context, varScope); } break; } }
public override Expression ResolveTypes(ParserContext context, VariableScope varScope) { for (int i = 0; i < this.Expressions.Length; ++i) { this.Expressions[i] = this.Expressions[i].ResolveTypes(context, varScope); } ResolvedType cumulativeType = this.Expressions[0].ResolvedType; for (int i = 0; i < this.Ops.Length; ++i) { Expression leftExpr = this.Expressions[i]; Expression rightExpr = this.Expressions[i + 1]; ResolvedType leftType = leftExpr.ResolvedType; ResolvedType rightType = rightExpr.ResolvedType; switch (this.Ops[i].Value) { case "==": case "!=": // anything is fine on either end. cumulativeType = ResolvedType.Bool(); break; case ">=": case ">": case "<=": case "<": if (!leftType.IsNumber) { throw new ParserException(leftExpr.FirstToken, NOT_A_NUMBER_ERROR); } if (!rightType.IsNumber) { throw new ParserException(rightExpr.FirstToken, NOT_A_NUMBER_ERROR); } cumulativeType = ResolvedType.Bool(); break; case "+": if (leftType.IsString || rightType.IsString) { cumulativeType = ResolvedType.String(); } else { cumulativeType = CombineNumberTypes(leftExpr, rightExpr); } break; case "-": case "/": case "*": cumulativeType = CombineNumberTypes(leftExpr, rightExpr); break; case "<<": case ">>": case "&": case "|": case "^": if (!leftType.IsIntLike) { throw new ParserException(leftExpr.FirstToken, INT_REQUIRED_ERROR); } if (!rightType.IsIntLike) { throw new ParserException(rightExpr.FirstToken, INT_REQUIRED_ERROR); } cumulativeType = CombineNumberTypes(leftExpr, rightExpr); break; case "&&": case "||": if (!leftType.IsBool) { throw new ParserException(leftExpr.FirstToken, BOOLEAN_REQUIRED_ERROR); } if (!rightType.IsBool) { throw new ParserException(rightExpr.FirstToken, BOOLEAN_REQUIRED_ERROR); } cumulativeType = ResolvedType.Bool(); break; case "??": if (!leftType.IsReferenceType) { throw new ParserException(leftExpr.FirstToken, "This type is not nullable and cannot be used with '??'"); } if (!rightType.IsReferenceType) { throw new ParserException(rightExpr.FirstToken, "This type is not nullable and cannot be used with '??'"); } if (leftType.CanBeAssignedTo(rightType, context)) { cumulativeType = rightType; } else if (rightType.CanBeAssignedTo(leftType, context)) { cumulativeType = leftType; } else { throw new ParserException(leftExpr.FirstToken, "Cannot use ?? on these two types. It is unclear what the resulting type should be."); } break; default: throw new ParserException(this.Ops[i], "The type resolution for this op is not yet implemented."); } } this.ResolvedType = cumulativeType; return(this); }