public ResolvedType ResolveType(AType type) { if (type.IsAnyType) { return(this.typeContext.ANY); } switch (type.RootType) { case "void": return(this.typeContext.VOID); case "int": return(this.typeContext.INTEGER); case "bool": return(this.typeContext.BOOLEAN); case "float": return(this.typeContext.FLOAT); case "string": return(this.typeContext.STRING); case "object": return(this.typeContext.OBJECT); case "[": case "List": if (type.Generics.Length != 1) { throw new ParserException(type.FirstToken, "A list type has 1 generic."); } return(ResolvedType.ListOrArrayOf(ResolveType(type.Generics[0]))); case "Dictionary": if (type.Generics.Length != 2) { throw new ParserException(type.FirstToken, "A dictionary type has 2 generics."); } ResolvedType keyType = ResolveType(type.Generics[0]); ResolvedType valueType = ResolveType(type.Generics[1]); switch (keyType.Category) { case ResolvedTypeCategory.INSTANCE: case ResolvedTypeCategory.INTEGER: case ResolvedTypeCategory.STRING: // This is fine. break; default: throw new ParserException(type.Generics[0].FirstToken, "This is not a valid key type for a dictionary."); } return(ResolvedType.GetDictionaryType(keyType, valueType)); default: ClassDefinition classDef = this.owner.FileScope.DoClassLookup(this.owner, type.FirstToken, type.RootType); return(ResolvedType.GetInstanceType(this.typeContext, classDef)); } }
internal override Expression ResolveTypes(ParserContext parser, TypeResolver typeResolver) { ResolvedType itemType = typeResolver.ResolveType(this.ListType); this.ResolvedType = ResolvedType.ListOrArrayOf(itemType); for (int i = 0; i < this.Items.Length; ++i) { this.Items[i] = this.Items[i].ResolveTypes(parser, typeResolver); if (!this.Items[i].ResolvedType.CanAssignToA(itemType)) { throw new ParserException(this.Items[i], "This item cannot exist in a list of this type."); } } return(this); }
internal override Expression ResolveTypes(ParserContext parser, TypeResolver typeResolver) { this.ResolvedType = ResolvedType.ListOrArrayOf(ResolvedType.ANY); return(this); }
internal override Expression ResolveTypes(ParserContext parser, TypeResolver typeResolver) { this.Root.ResolveTypes(parser, typeResolver); string field = this.FieldToken.Value; if (this.Root is EnumReference) { throw new System.NotImplementedException(); } ResolvedType rootType = this.Root.ResolvedType; // TODO: all of this needs to be localized. switch (rootType.Category) { case ResolvedTypeCategory.NULL: throw new ParserException(this.DotToken, "Cannot dereference a field from null."); case ResolvedTypeCategory.ANY: // ¯\_(ツ)_/¯ this.ResolvedType = ResolvedType.ANY; return(this); case ResolvedTypeCategory.INTEGER: throw new ParserException(this.DotToken, "Integers do not have any fields."); case ResolvedTypeCategory.FLOAT: throw new ParserException(this.DotToken, "Floating point decimals do not have any fields."); case ResolvedTypeCategory.BOOLEAN: throw new ParserException(this.DotToken, "Booleans do not have any fields."); case ResolvedTypeCategory.STRING: switch (field) { case "length": this.ResolvedType = ResolvedType.INTEGER; if (this.Root is StringConstant) { return(new IntegerConstant(this.FirstToken, ((StringConstant)this.Root).Value.Length, this.Owner)); } return(this); case "contains": return(BuildPrimitiveMethod(ResolvedType.BOOLEAN, ResolvedType.STRING)); case "endsWith": return(BuildPrimitiveMethod(ResolvedType.BOOLEAN, ResolvedType.STRING)); case "indexOf": return(BuildPrimitiveMethod(ResolvedType.INTEGER, ResolvedType.STRING)); case "lower": return(BuildPrimitiveMethod(ResolvedType.STRING)); case "ltrim": return(BuildPrimitiveMethod(ResolvedType.STRING)); case "replace": return(BuildPrimitiveMethod(ResolvedType.STRING, ResolvedType.STRING, ResolvedType.STRING)); case "reverse": return(BuildPrimitiveMethod(ResolvedType.STRING)); case "rtrim": return(BuildPrimitiveMethod(ResolvedType.STRING)); case "split": return(BuildPrimitiveMethod(ResolvedType.ListOrArrayOf(ResolvedType.STRING), ResolvedType.STRING)); case "startsWith": return(BuildPrimitiveMethod(ResolvedType.BOOLEAN, ResolvedType.STRING)); case "trim": return(BuildPrimitiveMethod(ResolvedType.STRING)); case "upper": return(BuildPrimitiveMethod(ResolvedType.STRING)); // common mistakes case "join": throw new ParserException(this.DotToken, "Strings do not have a .join(list) method. Did you mean to do list.join(string)?"); case "size": throw new ParserException(this.DotToken, "Strings do not have a .size() method. Did you mean to use .length?"); default: throw new ParserException(this.DotToken, "Strings do not have that method."); } case ResolvedTypeCategory.LIST: ResolvedType itemType = rootType.ListItemType; switch (field) { case "length": this.ResolvedType = ResolvedType.INTEGER; return(this); case "filter": case "map": if (this.CompilationScope.IsStaticallyTyped) { // TODO: for Acrylic, this needs to have a way to indicate that resolution should be attempted // again once the function return type is known. throw new System.NotImplementedException(); } this.ResolvedType = ResolvedType.ANY; return(this); case "add": return(BuildPrimitiveMethod(ResolvedType.VOID, itemType)); case "choice": return(BuildPrimitiveMethod(ResolvedType.VOID)); case "clear": return(BuildPrimitiveMethod(ResolvedType.VOID)); case "clone": return(BuildPrimitiveMethod(rootType)); case "concat": return(BuildPrimitiveMethod(rootType, rootType)); case "contains": return(BuildPrimitiveMethod(ResolvedType.BOOLEAN, itemType)); case "insert": return(BuildPrimitiveMethod(ResolvedType.VOID, ResolvedType.INTEGER, itemType)); case "join": return(BuildPrimitiveMethodWithOptionalArgs(ResolvedType.STRING, 1, ResolvedType.STRING)); case "pop": return(BuildPrimitiveMethod(itemType)); case "remove": return(BuildPrimitiveMethod(ResolvedType.VOID, ResolvedType.INTEGER)); case "reverse": return(BuildPrimitiveMethod(ResolvedType.VOID)); case "shuffle": return(BuildPrimitiveMethod(ResolvedType.VOID)); case "sort": return(BuildPrimitiveMethod(ResolvedType.VOID)); // common mistakes case "count": case "size": throw new ParserException(this.DotToken, "Lists do not have a ." + this.FieldToken.Value + "() method. Did you mean to use .length?"); default: throw new ParserException(this.DotToken, "Lists do not have that method."); } case ResolvedTypeCategory.DICTIONARY: ResolvedType keyType = rootType.DictionaryKeyType; ResolvedType valueType = rootType.DictionaryValueType; switch (field) { case "length": this.ResolvedType = ResolvedType.INTEGER; return(this); case "clear": return(BuildPrimitiveMethod(ResolvedType.VOID)); case "clone": return(BuildPrimitiveMethod(rootType)); case "contains": return(BuildPrimitiveMethod(ResolvedType.BOOLEAN, keyType)); case "get": return(BuildPrimitiveMethodWithOptionalArgs(valueType, 1, keyType, valueType)); case "keys": return(BuildPrimitiveMethod(ResolvedType.ListOrArrayOf(keyType))); case "merge": return(BuildPrimitiveMethod(ResolvedType.VOID, rootType)); case "remove": return(BuildPrimitiveMethod(ResolvedType.VOID, keyType)); case "values": return(BuildPrimitiveMethod(ResolvedType.ListOrArrayOf(valueType))); default: throw new ParserException(this.DotToken, "Dictionaries do not have that field."); } case ResolvedTypeCategory.CLASS_DEFINITION: throw new ParserException(this.DotToken, "Class definitions do not have that field."); case ResolvedTypeCategory.FUNCTION_POINTER: switch (field) { case "invoke": return(BuildPrimitiveMethod(ResolvedType.ANY, ResolvedType.ListOrArrayOf(ResolvedType.ANY))); default: throw new ParserException(this.DotToken, "Fucntions do not have that field."); } case ResolvedTypeCategory.INSTANCE: FieldDefinition fieldDef = rootType.ClassTypeOrReference.GetField(field, true); if (fieldDef != null) { if (!Node.IsAccessAllowed(this, fieldDef)) { ClassDefinition cd = fieldDef.ClassOwner; throw new ParserException(FieldToken, "The field '" + cd.NameToken.Value + "." + this.FieldToken.Value + "' is not accessible from here due to its access scope."); } this.ResolvedType = fieldDef.ResolvedFieldType; return(this); } FunctionDefinition funcDef = rootType.ClassTypeOrReference.GetMethod(field, true); if (funcDef != null) { this.ResolvedType = ResolvedType.GetFunctionType(funcDef); return(this); } throw new ParserException(this.DotToken, "The class '" + rootType.ClassTypeOrReference.NameToken.Value + "' does not have a field called '" + field + "'."); default: throw new ParserException(this.DotToken, "This field does not exist."); } }