private Dictionary<string, Executable> CreateFullyQualifiedLookup(IList<Executable> code) { HashSet<string> namespaces = new HashSet<string>(); Dictionary<string, Executable> lookup = new Dictionary<string, Executable>(); bool mainFound = false; foreach (Executable item in code) { string ns; string memberName; if (item is FunctionDefinition) { FunctionDefinition fd = (FunctionDefinition)item; ns = fd.Namespace; memberName = fd.NameToken.Value; if (memberName == "main") { if (mainFound) { throw new ParserException(item.FirstToken, "Multiple main methods found."); } mainFound = true; lookup["~"] = item; } } else if (item is ClassDefinition) { ClassDefinition cd = (ClassDefinition)item; ns = cd.Namespace; memberName = cd.NameToken.Value; // TODO: nested classes, constants, and enums. } else if (item is EnumDefinition) { EnumDefinition ed = (EnumDefinition)item; ns = ed.Namespace; memberName = ed.Name; } else if (item is ConstStatement) { ConstStatement cs = (ConstStatement)item; ns = cs.Namespace; memberName = cs.Name; } else { throw new Exception(); } if (ns.Length > 0) { string accumulator = ""; foreach (string nsPart in ns.Split('.')) { if (accumulator.Length > 0) accumulator += "."; accumulator += nsPart; namespaces.Add(accumulator); } } string fullyQualifiedName = (ns.Length > 0 ? (ns + ".") : "") + memberName; lookup[fullyQualifiedName] = item; } foreach (string key in lookup.Keys) { if (namespaces.Contains(key)) { throw new ParserException(lookup[key].FirstToken, "This name collides with a namespace definition."); } } // Go through and fill in all the partially qualified namespace names. foreach (string ns in namespaces) { lookup[ns] = new Namespace(null, ns, null); } if (lookup.ContainsKey("~")) { FunctionDefinition mainFunc = (FunctionDefinition)lookup["~"]; if (mainFunc.ArgNames.Length > 1) { throw new ParserException(mainFunc.FirstToken, "The main function must accept 0 or 1 arguments."); } } else { throw new Exception("No main(args) function was defined."); } return lookup; }
private static Executable ParseNamespace(Parser parser, TokenStream tokens, Executable owner) { Token namespaceToken = tokens.PopExpected("namespace"); Token first = tokens.Pop(); Parser.VerifyIdentifier(first); List<Token> namespacePieces = new List<Token>() { first }; while (tokens.PopIfPresent(".")) { Token nsToken = tokens.Pop(); Parser.VerifyIdentifier(nsToken); namespacePieces.Add(nsToken); } string name = string.Join(".", namespacePieces.Select<Token, string>(t => t.Value)); parser.PushNamespacePrefix(name); Namespace namespaceInstance = new Namespace(namespaceToken, name, owner); tokens.PopExpected("{"); List<Executable> namespaceMembers = new List<Executable>(); while (!tokens.PopIfPresent("}")) { Executable executable = ExecutableParser.Parse(parser, tokens, false, false, true, namespaceInstance); if (executable is FunctionDefinition || executable is ClassDefinition || executable is Namespace) { namespaceMembers.Add(executable); } else { throw new ParserException(executable.FirstToken, "Only function, class, and nested namespace declarations may exist as direct members of a namespace."); } } namespaceInstance.Code = namespaceMembers.ToArray(); parser.PopNamespacePrefix(); return namespaceInstance; }