internal override void ResolveTypes(VariableScope varScope, PastelCompiler compiler) { this.Condition = this.Condition.ResolveType(varScope, compiler); PType conditionType = this.Condition.ResolvedType; bool isInt = conditionType.IsIdentical(compiler, PType.INT); bool isChar = !isInt && conditionType.IsIdentical(compiler, PType.CHAR); if (!isInt && !isChar) { throw new ParserException(this.Condition.FirstToken, "Only ints and chars can be used in switch statements."); } // consider it all one scope for (int i = 0; i < this.Chunks.Length; ++i) { SwitchChunk chunk = this.Chunks[i]; for (int j = 0; j < chunk.Cases.Length; ++j) { Expression ex = chunk.Cases[j]; if (ex != null) { ex = ex.ResolveType(varScope, compiler); chunk.Cases[j] = ex; if ((isInt && ex.ResolvedType.RootValue != "int") || (isChar && ex.ResolvedType.RootValue != "char")) { throw new ParserException(ex.FirstToken, isInt ? "Only ints may be used." : "Only chars may be used."); } } } Executable.ResolveTypes(chunk.Code, varScope, compiler); } }
public static bool CheckReturnType(PType returnType, PType value) { if (returnType.IsIdentical(value)) { return(true); } if (returnType.RootValue == "object") { return(true); } if (returnType.RootValue == "void") { return(false); } if (value.RootValue == "null") { if (returnType.RootValue == "string") { return(true); } if (returnType.Generics.Length > 0) { return(true); } // is struct? char c = returnType.RootValue[0]; if (c >= 'A' && c <= 'Z') { return(true); } } return(false); }
internal override Expression ResolveType(VariableScope varScope, PastelCompiler compiler) { this.Root = this.Root.ResolveType(varScope, compiler); this.Index = this.Index.ResolveType(varScope, compiler); PType rootType = this.Root.ResolvedType; PType indexType = this.Index.ResolvedType; bool badIndex = false; if (rootType.RootValue == "List" || rootType.RootValue == "Array") { badIndex = !indexType.IsIdentical(PType.INT); this.ResolvedType = rootType.Generics[0]; } else if (rootType.RootValue == "Dictionary") { badIndex = !indexType.IsIdentical(rootType.Generics[0]); this.ResolvedType = rootType.Generics[1]; } else if (rootType.RootValue == "string") { badIndex = !indexType.IsIdentical(PType.INT); this.ResolvedType = PType.CHAR; if (this.Root is InlineConstant && this.Index is InlineConstant) { string c = ((string)((InlineConstant)this.Root).Value)[(int)((InlineConstant)this.Index).Value].ToString(); InlineConstant newValue = new InlineConstant(PType.CHAR, this.FirstToken, c); newValue.ResolveType(varScope, compiler); return(newValue); } } else { badIndex = true; } if (badIndex) { throw new ParserException(this.BracketToken, "Cannot index into a " + rootType + " with a " + indexType + "."); } return(this); }
internal override Expression ResolveType(VariableScope varScope, PastelCompiler compiler) { this.Root = this.Root.ResolveType(varScope, compiler); this.Index = this.Index.ResolveType(varScope, compiler); PType rootType = this.Root.ResolvedType; PType indexType = this.Index.ResolvedType; bool badIndex = false; if (rootType.RootValue == "List" || rootType.RootValue == "Array") { badIndex = !indexType.IsIdentical(PType.INT); this.ResolvedType = rootType.Generics[0]; } else if (rootType.RootValue == "Dictionary") { badIndex = !indexType.IsIdentical(rootType.Generics[0]); this.ResolvedType = rootType.Generics[1]; } else if (rootType.RootValue == "string") { badIndex = !indexType.IsIdentical(PType.INT); this.ResolvedType = PType.CHAR; } else { badIndex = true; } if (badIndex) { throw new ParserException(this.BracketToken, "Cannot index into a " + rootType + " with a " + indexType + "."); } return(this); }
// Note that this class is instantiated in the ResolveType phase. public FunctionPointerInvocation(PastelCompiler compiler, Token firstToken, Expression root, IList <Expression> Args) : base(firstToken, root.Owner) { this.Root = root; this.Args = Args.ToArray(); this.ResolvedType = this.Root.ResolvedType.Generics[0]; if (this.Root.ResolvedType.Generics.Length - 1 != this.Args.Length) { throw new ParserException(this.Root.FirstToken, "This function has the incorrect number of arguments."); } for (int i = 0; i < this.Args.Length; ++i) { PType expectedArgType = this.Root.ResolvedType.Generics[i + 1]; PType actualArgType = this.Args[i].ResolvedType; if (!actualArgType.IsIdentical(compiler, expectedArgType)) { throw new ParserException(this.Args[i].FirstToken, "Incorrect argument type. Expected " + expectedArgType + " but found " + actualArgType + "."); } } }
// when a templated type coincides with an actual value, add that template key to the lookup output param. public static bool CheckAssignmentWithTemplateOutput(PType templatedType, PType actualValue, Dictionary <string, PType> output) { if (templatedType.RootValue == "object") { return(true); } // Most cases, nothing to do if (templatedType.IsIdentical(actualValue)) { return(true); } if (templatedType.RootValue.Length == 1) { if (output.ContainsKey(templatedType.RootValue)) { PType requiredType = output[templatedType.RootValue]; // if it's already encountered it better match the existing value if (actualValue.IsIdentical(requiredType)) { return(true); } // It's also possible that this is null, in which case the type must be nullable. if (actualValue.RootValue == "null" && requiredType.IsNullable) { return(true); } return(false); } output[templatedType.RootValue] = actualValue; return(true); } if (templatedType.Generics.Length != actualValue.Generics.Length) { // completely different. don't even try to match templates return(false); } if (templatedType.RootValue != actualValue.RootValue) { if (templatedType.RootValue.Length == 1) { if (output.ContainsKey(templatedType.RootValue)) { // if it's already encountered it better match the existing value if (actualValue.IsIdentical(output[templatedType.RootValue])) { // yup, that's okay } else { return(false); } } else { // first time this type was encountered. output[templatedType.RootValue] = actualValue; } } else { // different type return(false); } } for (int i = 0; i < templatedType.Generics.Length; ++i) { if (!CheckAssignmentWithTemplateOutput(templatedType.Generics[i], actualValue.Generics[i], output)) { return(false); } } return(true); }