static void TestSignatures() { //// And now, all the input sentences have been read in, if not processed. // test output only TestHarness.Reset(); foreach (multimethod func in multimethods) { TestHarness.BeginTurn(); Console.WriteLine("{0}{1}", (TestHarness.NextTestLine < TestHarness.testlines.Count()) ? TestHarness.testlines[TestHarness.NextTestLine].Trim() : func.prompt.ToString(), (func.problems > 0) ? " (problematic)" : ""); foreach (term term in func.signature) { switch (term.which) { case PartsOfSpeech.noun: Console.WriteLine(" parameter '{1}{0}'", term.noun.fullname1, term.noun.isAggregate ? "" : "the "); break; case PartsOfSpeech.verb: Console.WriteLine(" verb '{0}'", term.verb.plural); break; case PartsOfSpeech.preposition: Console.WriteLine(" keywords '{0}'", term.preposition); break; default: Console.WriteLine("ERROR IN COMPILER: unknown term"); break; } } TestHarness.EndTurn(1); if (func.fully_parsed) { Console.WriteLine("({0} fully parsed{1})", func.prompt, func.problems + func.todo > 0 ? ", but with problems/to-dos" : ""); } } }
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(); }