/// <summary>High-level function to parse the body of a function. Turns parseMe.body (a string) into parseMe.parsed_body /// (a List of Invocations) via multiple calls to ParseAnInvocation() and ParseListSeparator().</summary> public static void ParseInvocations(multimethod parseMe) { Console.WriteLine("#{0}: parsing body", parseMe.prompt); index = 0; subprompt = 0; parseMe.parsed_body = new List <invocation>(); invocation invoke; do { ++subprompt; subsubprompt = 0; invoke = ParseAnInvocation(parseMe.body); if (invoke != null) { parseMe.parsed_body.Add(invoke); invoke.definition.called++; } if (index < parseMe.body.Count - 1) { ParseListSeparator(parseMe.body.ToArray()); } } while (invoke != null && index < parseMe.body.Count - 1); Console.WriteLine(" {0} statements in that function.", parseMe.parsed_body.Count); Console.WriteLine(); }
/// <summary>Given a method signature and the types of the values being fed to it, this calculates how close of a match the values are for /// that signature. It's used during multi-method dispatch when multiple methods can take that set of inputs to choose the /// best match for those inputs.</summary> public static long Distance(multimethod method, List <instance> inputs) { if (inputs.Count == 0) { return(0); // hopefully the signature's verb and the used verb match. If not, why call this function? } long summation = 0; int i = 0; int squareme; foreach (term term in method.signature) { if (term.which != PartsOfSpeech.noun) { continue; } if (i >= inputs.Count) { return(999998); } squareme = DistanceFrom(inputs[i].type, term.noun.type); if (squareme < 0) { return(1000000); // the inputs don't even match the signature. } summation += squareme * squareme; i++; } return(summation); }
public parameter(multimethod subfunction) { prompt = subfunction.prompt; relation = subfunction.signature; foreach (var term in relation) { if (term.which == PartsOfSpeech.verb) { name = term.verb._ing; } } fullname1 = name; fullname2 = name; }
/// <summary>This is used while defining a higher-order function, tipped off by the -ing verb form that leads.</summary> static parameter CreateFunctionParameterObject(string[] words, fiveforms ing, bool isSubject = false) { long savedIndex = index; multimethod outerMethod = method_being_constructed; string savedDefinedVerb = definedVerb; method_being_constructed = new multimethod() { prompt = -outerMethod.prompt, question = "" }; multimethod innerMethod = PredicateDefinition2(words, ing, isSubject); // returns method_being_constructed method_being_constructed = outerMethod; definedVerb = savedDefinedVerb; return(new parameter(innerMethod)); }
/// <summary>For cases of "give someone the thing", we must back up and add "to" to the "someone"</summary> static void HandleSwappedDirectandIndirectObjects(multimethod method_being_constructed, string prep, fiveforms verb, bool isSubject) { if (isSubject) { return; } if (listType != null) { return; } switch (TheGiveSomebodyItException) { case DirectObjectPlacement.not_there_yet: TheGiveSomebodyItException = DirectObjectPlacement.normal; break; case DirectObjectPlacement.normal: // then the previous parameter is the indirect, not direct, object, and needs "to" prepended for (int i = 0; method_being_constructed.signature.Count > i; i++) { if (method_being_constructed.signature[i].which == PartsOfSpeech.noun) { term newterm = method_being_constructed.signature[i]; newterm.noun.preposition = prep; method_being_constructed.signature[i] = newterm; CreateFullNames(method_being_constructed.signature[i].noun, verb); //not sure why this is still needed break; } } TheGiveSomebodyItException = DirectObjectPlacement.after_the_indirect_object; break; case DirectObjectPlacement.after_the_indirect_object: case DirectObjectPlacement.error: TheGiveSomebodyItException = DirectObjectPlacement.error; Console.WriteLine(" ERROR: I require those parameters to be separated by prepositions or commas."); method_being_constructed.problems++; break; } }
static void VerifyAbstractSyntaxTree() { // now check the whole abstract syntax tree // First, is there one and only one root? "To do:" fiveforms rootverb = FindVerb("do"); multimethod main = null; if (mms.ContainsKey(rootverb)) { foreach (multimethod possibleRoot in mms[rootverb]) { if (possibleRoot.signature.Count == 1) { if (main == null) { main = possibleRoot; } else { Console.WriteLine(" ERROR: I have too many definitions for \"To do:\", like #{0} and #{1}", main.prompt, possibleRoot.prompt); } } } } if (main == null) { Console.WriteLine(" ERROR: Where does the whole thing start? I need a sentence which begins, \"To do:\""); } else { main.called++; } // dead code elimination? unused structs elimination? }
public invocation(multimethod d, int from, int to, List <instance> bound) { definition = d; startWord = from; endWord = to; boundParameters = bound; }
static int prompt = 1, subprompt, subsubprompt; // the sentence#, invocation#, and relative clause # ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static void Main(string[] args) { ReadForms(); TheVerbIs = FindVerb("is"); InitNumberUnitSystem(); InitInheritanceTree(); string input = null; string[] words = null; int maxWords; TestHarness.loadTestScript("me"); for (Console.Write("{0}: ", prompt); (input = TestHarness.LineFeeder()) != null; TestHarness.EndTurn(2), Console.Write("{0}: ", ++prompt)) { TestHarness.BeginTurn(); // Move string literals into the string table, leaving placeholders behind. while (input.Contains('"')) { int from = input.IndexOf('"'); int endAt = from + 1; loopPastDquoteLiteral: endAt += input.Substring(endAt).IndexOf('"'); if (input.Length > endAt + 1 && input.ElementAt(endAt + 1) == '"') { endAt += 2; goto loopPastDquoteLiteral; } int len = endAt - (from + 1); string literal = input.Substring(from + 1, len); input = input.Substring(0, from - 1) + String.Format(" __litstring{0}__ ", literalStrings.Count) + input.Substring(endAt + 1); literalStrings.Add(literal.Replace("\"\"", "\"")); } // cleanse the input input = input.ToLowerInvariant() + " "; input = input.Replace(", ", " , ").Replace(". ", " . ").Replace(": ", " : ").Replace("? ", " ? "); input = input + " " + stringnums.EOL[0]; words = input.Split(new[] { ' ', '\t', '\n' }, StringSplitOptions.RemoveEmptyEntries); maxWords = (int)words.Count(); if (maxWords < 2) { break; // EOL is always appended } // debugging / testharness feature: input a line number if (maxWords == 2 && Int32.TryParse(words[0], out subjectAt)) { Console.WriteLine(TestHarness.testlines[--subjectAt * 3]); Console.WriteLine(TestHarness.testlines[subjectAt * 3 + 1]); Console.WriteLine(TestHarness.testlines[subjectAt * 3 + 2]); continue; } // meta / macro command: tell the compiler to run another file. if (maxWords == 3 && words[0] == "regard" && words[1].StartsWith("__litstring")) { TestHarness.loadTestScript(Say(words[1])); continue; } // initialize vars index = 0; definedVerb = ""; preposition = ""; method_being_constructed = new multimethod() { prompt = prompt, question = "" }; //method_being_constructed.prompt = prompt; subjectAt = -1; isQuestion = false; incarnations = null; listType = null; IdentEndsAt = maxWords; just_declared_new_type = false; // Absorb any prepositions at the beginning, as in "To give..." or "To boldly go..." or "To a person give...", etc. while (stringnums.prepositions.Contains(words[index])) { if (preposition != "") { preposition += " "; } preposition += words[index++]; } // if the first word(s) indicate a question, read it. //method_being_constructed.question = ""; /*if (stringnums.QuestionWords.Contains(words[index])) * { * string question = ""; * while (stringnums.QuestionWords.Contains(words[index])) * { * if (question != "") question += " "; * question += words[index++]; * } * incarnations = FindVerb(words[index]); // Catches "What is.." but not "Which car is..." * method_being_constructed.question = question; * isQuestion = true; * }*/ // if first word(s) indicated a subject, read it if (stringnums.DefiniteArticles.Contains(words[index]) || stringnums.IndefiniteArticles.Contains(words[index]) || stringnums.ListDeterminers.Contains(words[index]) || words[index].EndsWith("ing") || (method_being_constructed.question != "" && incarnations == null)) { ParseSubject(words); } if (prompt >= 37) { Console.WriteLine(); } // Regardless, parse the predicate: a verb and the nouns that go with. incarnations = PredicateDefinition(words); // If we haven't found a verb yet, but we do have a subject, look for the verb in the subject's name. if (incarnations == null && subjectAt >= 0) { string[] subnames = method_being_constructed.signature[subjectAt].noun.name.Split(' '); for (int i = subnames.Count() - 1; i >= 0; i--) { index--; incarnations = FindMainVerb(subnames[i]); if (incarnations == null) { continue; } // Ah, there's the verb. Shorten the subject's name, and try parsing the predicate again from this index position. definedVerb = subnames[i]; string newname = subnames[0]; for (int j = 1; j < i; j++) { newname += " " + subnames[j]; } method_being_constructed.signature[subjectAt].noun.name = newname; Console.WriteLine(" oops; verb is '{1}' and subject is '{0}'", newname, definedVerb); incarnations = PredicateDefinition(words); break; } } // If we still don't have a verb, we're going to have to search for it the long way. if (incarnations == null) { int savedIndex = index; while (incarnations == null && index < maxWords - 1 && !stringnums.EndsInfinitiveDefinition.Contains(words[index])) { incarnations = FindMainVerb(words[++index]); // this is an expensive loop } if (incarnations != null) { // ah, found it. There must be a subject in front of it... definedVerb = words[index]; IdentEndsAt = index; index = 0; // back to first word of sentence if (ParseSubject(words) == null) { method_being_constructed.signature.Add(new term(incarnations)); Console.Write("ERROR: verb is '{0}' but I don't know what to do with the subject: ", definedVerb); for (int i = savedIndex; i < IdentEndsAt; i++) { Console.Write("{0} ", words[i]); } Console.WriteLine(); method_being_constructed.problems++; multimethods.Add(method_being_constructed); continue; } index++; // advance past verb IdentEndsAt = (int)words.Count(); // un-set the hint var mm = PredicateDefinition2(words, incarnations); // and finish the predicate as normal multimethods.Add(mm); } } // If we STILL don't have a verb, abort this sentence. if (incarnations == null) { method_being_constructed.signature.Add(new term("...")); Console.Write("ERROR: I couldn't find a verb in: "); for (int i = 0; i < index; i++) { Console.Write("{0} ", words[i]); } Console.WriteLine(); method_being_constructed.problems++; multimethods.Add(method_being_constructed); continue; } //if (prompt == 32) // Console.WriteLine("debug"); // OK, we have a verb, and processed the rest of the definition with it. We should be at a marker separating // the function head from the function body. Or if it's a type/struct/object definition, we're at the end of // the sentence entirely. method_being_constructed.fully_parsed = stringnums.EOL.Contains(words[index]); if (stringnums.EndsInfinitiveDefinition.Contains(words[index])) { index++; // advance past the comma, colon, BY, VIA, MEANS, or whatever separates head from body } else if (words[index] != ".") { Console.WriteLine("I didn't expect this definition of '{1}' end with a '{0}'", words[index], definedVerb); method_being_constructed.problems++; continue; } // If we had a valid definition, save away its body. We can't parse the bodies until we read all the heads. // That's because what names, esp. parameter names and other function invocations, that appear in the bodies // aren't even known yet. if (!method_being_constructed.fully_parsed) { method_being_constructed.body = new List <string>(); while (index < maxWords - 1 && !stringnums.EOL.Contains(words[index])) { method_being_constructed.body.Add(words[index++]); //ParseParameterInvocation(words); } } // for case of "X is Y..." // if the subject is already a type, and is now being used with "IS" again, // Ensure we don't use a known type with "is" unless // 1) there's a "when", or // 2) the subject is "the" instance of the type, or // 3) the subject is a gerund phrase (function type), so the predicate is a categorical name, a "class" or "name of enum" for signatures if (subjectAt != -1 && incarnations._en == "been" && method_being_constructed.fully_parsed) { parameter theSubject = method_being_constructed.signature[subjectAt].noun; if (just_declared_new_type && theSubject.art == Article.the) { Console.WriteLine(" global variable or singleton instance '{0}' created", theSubject.name); PermanentDataSegment.Add(theSubject); } else if (theSubject.isAggregate && method_being_constructed.signature.Count == 3) { // "Xing... is Y." so define Y as a category for verbs var ident = method_being_constructed.signature[2].which == PartsOfSpeech.noun ? method_being_constructed.signature[2].noun.name : method_being_constructed.signature[2].preposition; var newType = CreateNewType(ident, StandardType.homogene); Console.WriteLine(" assuming '{0}' categorizes verbs", ident); } else if (!just_declared_new_type) { if (theSubject.type == StandardType.anything) { Console.WriteLine(" ERROR: I have no idea what a '{0}' is. It could be anything.", theSubject.name); } else { Console.WriteLine(" ERROR: trying to re-define the type '{0}'", NameOfType(theSubject.type)); } method_being_constructed.problems++; } } // Create the various names for each parameter in the new method. // This isn't perfect because we don't know where a noun phrase ends and where adverbs and verbs begin. // We'll keep it all as the possible noun phrase, but when we start parsing the body, we'll look at // what the parameters are actually called in there. Then we can shorten our parameter names to match // sensibly. TheGiveSomebodyItException = DirectObjectPlacement.not_there_yet; for (int i = 0; i < method_being_constructed.signature.Count; i++) { if (method_being_constructed.signature[i].which == PartsOfSpeech.noun) { term newterm = method_being_constructed.signature[i]; parameter oldparam = newterm.noun; newterm.noun = NamedParameter(oldparam, incarnations, (i == subjectAt)); method_being_constructed.signature[i] = newterm; } else if (method_being_constructed.signature[i].which == PartsOfSpeech.verb) { TheGiveSomebodyItException = DirectObjectPlacement.not_there_yet; } } // Now we should be at the end of line: a period, question mark, or exclamation mark // If not, throw a helpful error. method_being_constructed.problems++; if (index >= words.Count()) { Console.WriteLine("COMPILER ERROR: EOL eaten: index too high"); } else if (words[index] != "ENDOFINPUT" && words[index] != ".") { if (index < words.Count()) { Console.WriteLine(" ERROR: I wasn't expecting '{0}' there, but rather, the end of the sentence.", words[index]); } else { Console.WriteLine("COMPILER ERROR: EOL eaten"); } } else { method_being_constructed.problems--; } // Sentence processed. Get next sentence } TestSignatures(); Pass2ResolveImplicitTypesAndCreateMultimethodDictionary(); Pass3MethodBodies(); VerifyAbstractSyntaxTree(); CodeGeneration(); }