/// <summary>Creates a new type defined by the user, as a subclass of another user-defined type.</summary> public static InheritedType CreateNewType(string ident, string parentClassName) { if (string.IsNullOrWhiteSpace(parentClassName)) { return(CreateNewType(ident)); } var newType = new InheritedType() { name = ident, parent = parentClassName, typeid = (StandardType)(InheritanceTree.Count + 2) }; InheritanceTree.Add(newType); just_declared_new_type = true; return(newType); }
/// <summary> Creates the lookup table for what types inherit from what. This would be hard-coded if C# would allow. </summary> public static void InitInheritanceTree() { for (StandardType st = StandardType.anything; st < StandardType.Count; st++) { var it = new InheritedType() { name = st.ToString(), subtypes = null, typeid = st }; switch (st) { case StandardType.anything: it.parent = null; break; case StandardType.something: case StandardType.nothing: it.parent = StandardType.anything.ToString(); break; case StandardType.valueType: case StandardType.referenceType: it.parent = StandardType.something.ToString(); break; case StandardType.number: case StandardType.discrete: case StandardType.reference: case StandardType.structure: it.parent = StandardType.valueType.ToString(); break; case StandardType.homogene: case StandardType.heterogene: case StandardType.value: it.parent = StandardType.referenceType.ToString(); break; case StandardType.percent: case StandardType.money: it.parent = StandardType.number.ToString(); break; case StandardType.position: case StandardType.boole: it.parent = StandardType.discrete.ToString(); break; case StandardType.time: it.parent = StandardType.structure.ToString(); break; case StandardType.text: case StandardType.list: it.parent = StandardType.homogene.ToString(); break; case StandardType.sequence: case StandardType.Object: it.parent = StandardType.heterogene.ToString(); break; default: Console.WriteLine("ERROR IN COMPILER: unknown base type {0}", st); break; } InheritanceTree.Add(it); } //TestInheritanceTree(); }
/// <summary>Returns the parent of the passed-in type. Returns Anything for unrecognized types as well as Anything /// itself. Returns Object (which is assumed) for types which claim to have no parent. (Those were implicitly /// created by a "list of" construction, and will presumably be filled in later.) </summary> public static StandardType ParentOf(StandardType st) { if (st == StandardType.anything) { return(StandardType.anything); // anything is anything, the root type } InheritedType it = InheritanceTree.Find(item => item.typeid == st); if (it == null) { return(StandardType.anything); } if (it.parent == null) { return(StandardType.Object); // only happens with used but undefined types } return(InheritanceTree.Find(item => item.name == it.parent).typeid); }
/*public static void TestInheritanceTree() * { * IsA(StandardType.number, StandardType.number); * Console.WriteLine("Is {0} a {1}? {2}.", StandardType.number, StandardType.number, (distance > -1)); * IsA(StandardType.number, StandardType.valueType); * Console.WriteLine("Is {0} a {1}? {2}.", StandardType.number, StandardType.valueType, (distance > -1)); * IsA(StandardType.Object, StandardType.anything); * Console.WriteLine("Is {0} a {1}? {2}.", StandardType.Object, StandardType.anything, (distance > -1)); * IsA(StandardType.anything, StandardType.anything); * Console.WriteLine("Is {0} a {1}? {2}.", StandardType.anything, StandardType.anything, (distance > -1)); * IsA(StandardType.text, StandardType.valueType); * Console.WriteLine("Is {0} a {1}? {2}.", StandardType.text, StandardType.valueType, (distance > -1)); * IsA(StandardType.text, StandardType.reference); * Console.WriteLine("Is {0} a {1}? {2}.", StandardType.text, StandardType.reference, (distance > -1)); * IsA(StandardType.number, StandardType.percent); * Console.WriteLine("Is {0} a {1}? {2}.", "number", "percent", (distance > -1)); * IsA(StandardType.percent, StandardType.number); * Console.WriteLine("Is {0} a {1}? {2}.", "percent", "number", (distance > -1)); * IsA(StandardType.number, StandardType.anything); * Console.WriteLine("Is {0} a {1}? {2}.", "number", "anything", (distance > -1)); * IsA(StandardType.number, StandardType.something); * Console.WriteLine("Is {0} a {1}? {2}.", "number", "something", (distance > -1)); * /*IsA(StandardType.money, StandardType.car); * Console.WriteLine("Is {0} a {1}? {2}.", "money", "car", (distance > -1)); * IsA("car", "object"); * Console.WriteLine("Is {0} a {1}? {2}.", "car", "object", (distance > -1)); * IsA("car", "something"); * Console.WriteLine("Is {0} a {1}? {2}.", "car", "something", (distance > -1)); * }*/ /// <summary>Returns the name of the given StandardType, including newly-defined types in the source. </summary> public static string NameOfType(StandardType?s) { if (s == null) { return("whatever"); } var st = s.Value; if (st <= StandardType.anything) { return(StandardType.anything.ToString()); } if (st < StandardType.Count) { return(st.ToString()); } InheritedType it = InheritanceTree.Find(item => item.typeid == st); return(it.name); }
/// <summary>Part of CreateParameterObject, which does the work for ParseNounPhraseForParameter. /// When declaring the parameters of a function's signature, this helper digests the "many..." parameter, which isn't /// a trivial operation, considering that lists have subtypes, some of which may not be known yet.</summary> static parameter CreateListParameterObject(ref StandardType?type, string ident, bool adjnounswap) { if (ident == null && type == null) { Console.WriteLine(" ERROR: many whats?"); method_being_constructed.problems++; return(new parameter("", ident, Article.many, (StandardType)0, adjnounswap)); } //either ident has value, type has value, or both have value // if basetype has value, then ident must not be a type. i.e., warn of "numeric car" or "many numeric cars" when car is of type object if (ident.HasValue() && type.HasValue) { InheritedType it = InheritanceTree.Find(item => item.name == ident); if (it != null && it.typeid != type.Value) { Console.WriteLine(" WARNING: '{0}' is declared elsewhere as a '{1}', not a '{2}'", it.name, NameOfType(it.typeid), NameOfType(type.Value)); } } // for the term "several/many/multiple numbers", set ident to the whole term "many numbers" -- a generated name if (string.IsNullOrEmpty(ident)) { ident = string.Format("many {0}", type); } // for the term "many gadgets", set type to "gadgets" by finding the type by name, or making a new one if (type == null) { InheritedType subtype = InheritanceTree.Find(item => item.name == ident); if (subtype == null) { // make a new type, "gadgets", whose parent (and subtype, if applicable) to be filled out later? subtype = new InheritedType() { name = ident, typeid = (StandardType)(InheritanceTree.Count + 2) }; InheritanceTree.Add(subtype); } type = subtype.typeid; } // now all three are populated: mode, type, ident // now, does our composite type already exist? Else make a new typeid string typeAsString = type.Value.ToString(); InheritedType aggregate = InheritanceTree.Find(item => item.name == ident && item.parent == StandardType.list.ToString() && item.subtypes == typeAsString); if (aggregate != null) { Console.WriteLine(" another '{0}' (a list of {1})", ident, NameOfType(type.Value)); return(new parameter("", ident, Article.many, type.Value, adjnounswap)); } aggregate = new InheritedType() { name = ident, parent = StandardType.list.ToString(), subtypes = type.Value.ToString(), typeid = (StandardType)(InheritanceTree.Count + 2) }; InheritanceTree.Add(aggregate); just_declared_new_type = true; string typename = NameOfType(type.Value); if (ident != typename) { Console.WriteLine(" a list of {0}, called {1}", typename, ident); } else { Console.WriteLine(" a list of {0}", typename); } return(new parameter("", ident, Article.many, type.Value, adjnounswap)); }
/// <summary>When defining a parameter of a new function's signature, and once parsing of that parameter is done, this converts /// the information into a parameter object. Uses CreateListParameterObject since that is a tome in itself.</summary> static parameter CreateParameterObject(string[] words, Article?mode, StandardType?type, StandardTypeAdjective?adjtype, string ident, bool identIsAdjectiveTypeIsNoun = false, bool isSubject = false) { // something/nothing/anything aren't preceded by an article. Treat as "a thing" if (type.HasValue && type <= StandardType.something) { Console.WriteLine(" declaring a parameter which {0}", type == StandardType.nothing ? "must be nothing" : type == StandardType.anything ? "could be anything" : "mustn't be nothing"); return(new parameter("", type.Value.ToString(), Article.a, type.Value, identIsAdjectiveTypeIsNoun)); } switch (mode) { case Article.the: if (type.HasValue) { if (adjtype == null) { Console.WriteLine("ERROR: we say 'the {0}' to use it later in the sentence. Here we should say 'a {0}'.", NameOfType(type.Value)); } else { Console.WriteLine("ERROR: we say 'the {0}' to use it later in the sentence. Here we should say 'a {0} {1}'.", adjtype, ident == "" ? "name-of-it" : ident); } method_being_constructed.problems++; return(null); } if (isSubject || isQuestion) { just_declared_new_type = isSubject; // and a global instance, as well return(new parameter("", ident, mode ?? Article.the, type ?? StandardType.number, identIsAdjectiveTypeIsNoun)); } Console.WriteLine("ERROR: we should use 'a' not 'the' in this part of the sentence."); method_being_constructed.problems++; return(null); case Article.many: return(CreateListParameterObject(ref type, ident, identIsAdjectiveTypeIsNoun)); case Article.a: if (type.HasValue) // also, should we disallow it when the ident is also a type? "numeric car" { Console.WriteLine(" declaring a parameter of type {0} called '{1}'", NameOfType(type.Value), ident); InheritedType it = InheritanceTree.Find(item => item.name == ident); if (it != null && it.typeid != type.Value) { Console.WriteLine(" WARNING: '{0}' is declared elsewhere as a '{1}', not a '{2}'", it.name, NameOfType(it.typeid), NameOfType(type.Value)); } } else if (isQuestion && incarnations == TheVerbIs) { for (IdentEndsAt = index; IdentEndsAt < words.Length && words[IdentEndsAt] != "?"; IdentEndsAt++) { ; } if (IdentEndsAt >= words.Length) { Console.WriteLine(" ERROR: I thought #{0} was a question because it began with '{1}', but I couldn't find a question mark afterward.", method_being_constructed.prompt, method_being_constructed.question); method_being_constructed.problems++; return(null); } Console.WriteLine(" defining a {0} by Q&A.", ident); ident = ParseNewIdentifier(words, ref type); } else if (!isSubject) { if (ident == "") // then we have no type info whatsoever. Just get a new ident { ident = ParseNewIdentifier(words, ref type); } Console.WriteLine(" TODO: is '{0}' textual? Numeric? Or something more complex?", ident); method_being_constructed.todo++; } // defining a new type else if (InheritanceTree.Find(item => item.name == ident) != null) { Console.WriteLine(" ERROR: re-defining type '{0}'.", ident); method_being_constructed.problems++; //return null; // let it parse for now return(new parameter("", ident, mode ?? Article.a, type ?? (StandardType)0, identIsAdjectiveTypeIsNoun)); } else { // object until proven otherwise. heck, it may not even be a type, it might be an instance or variable. var newType = CreateNewType(ident); Console.WriteLine(" assuming '{0}' is a new type", newType.name, newType.typeid); } break; case null: if (type == null) { return(null); } if (ident == null) { Console.WriteLine(" plural(?) parameter of type {0}", type); } else { Console.WriteLine(" plural(?) parameter of type {1} called the {0}", ident, NameOfType(type.Value)); } break; } return(new parameter("", ident, mode ?? Article.a, type ?? (StandardType)0, identIsAdjectiveTypeIsNoun)); }
static void Pass2ResolveImplicitTypesAndCreateMultimethodDictionary() { // Next up, ensure we've resolved the types of all parameters. // (and to speed up later processing, create a sorted dictionary of all the multimethods) // (and to speed up later processing, create a sorted dictionary of all the multimethods which don't begin with a parameter) List <term> badterms = new List <term>(); foreach (multimethod function in multimethods) { foreach (term term in function.signature) { switch (term.which) { case PartsOfSpeech.verb: // create a sorted dictionary of all multimethods if (!mms.ContainsKey(term.verb)) { mms.Add(term.verb, new List <multimethod>()); } mms[term.verb].Add(function); continue; case PartsOfSpeech.noun: // find the type of any unknown-type parameters if (term.noun.type != (StandardType)0) { break; } if (term.noun.isAggregate) { foreach (term innerTerm in term.noun.relation) { if (innerTerm.which != PartsOfSpeech.noun) { continue; } InheritedType it = InheritanceTree.Find(x => x.name == innerTerm.noun.name); if (it != null) { innerTerm.noun.type = it.typeid; } else { badterms.Add(innerTerm); } } break; } foreach (var t in InheritanceTree) { if (t.name != term.noun.name) { continue; } term.noun.type = t.typeid; goto breakOverElseBecauseFoundIt; } badterms.Add(term); // Console.WriteLine(" ERROR: is '{0}' a number? A text? Something else? You haven't said.", term.noun.name); function.problems++; break; } breakOverElseBecauseFoundIt: ; } } if (badterms.Count > 0) { Console.WriteLine(" ERROR: What are these? A number? A text? Something else? You haven't said."); } foreach (var term in badterms) { Console.Write("{0}, ", term.noun.name); } Console.WriteLine(); // When creating aggregate types like List Of X, we might create X as a placeholder. But if the real X is never defined... List <InheritedType> badtypes = new List <InheritedType>(); foreach (InheritedType t in InheritanceTree) { if (t.parent == null && t.typeid != StandardType.anything) { badtypes.Add(t); } } if (badtypes.Count > 0) { Console.WriteLine(" ERROR: Are these the plural form of a word I don't know? Or is it a number? A text? Something else? We have 'many' of them but I need to know what just one of them is."); } foreach (var t in badtypes) { Console.Write("{0}, ", t.name); } Console.WriteLine(); // Now that all types are resolved, ensure we haven't re-declared the same verb with the same signature. Console.WriteLine("{0} different verbs: ", mms.Count); foreach (KeyValuePair <fiveforms, List <multimethod> > entry in mms) { Console.WriteLine(entry.Key.plural); if (entry.Value.Count < 2) { continue; } var sigs = new Dictionary <string, multimethod>(); foreach (multimethod method in entry.Value) { string newsig = method.signature.ToString(false);//""; /*foreach (term t in method.signature) * { * switch (t.which) * { * case PartsOfSpeech.noun: * newsig += (t.noun.isAggregate) ? t.noun.signatureToString() : t.noun.name; * break; * case PartsOfSpeech.preposition: newsig += t.preposition; break; * case PartsOfSpeech.verb: * newsig += t.verb.plural; * break; * } * newsig += " "; * }*/ var preexisting = (sigs.ContainsKey(newsig)) ? sigs[newsig] : null; if (preexisting != null) { Console.WriteLine(" ERROR: we have more than one method for {0}:", entry.Key._ing); Console.WriteLine("#{0} '{1}'", preexisting.prompt, newsig); Console.WriteLine("#{0} '{1}'", method.prompt, newsig); } else { sigs.Add(newsig, method); } } } }