///////////////////////// // HAIRINESS BELOW public void ProcessFile(string filename) { this.cpath.Clear(); this.popLevels.Clear(); this.pindent = 0; this.ignoreLevel.Clear(); this.contextDebugOn = DebugContext; //|| filename.EndsWith("Chemistry-Machinery.dm"); this.ignoreDebugOn = DebugIgnore; //|| filename.EndsWith("Chemistry-Machinery.dm"); this.ppcDebugOn = DebugPreprocessing; this.ignoreStartIndent = -1; this.loadingProc = null; this.comment = ""; //this.fileLayout = [] this.lineBeforePreprocessing = ""; this.current_filename = filename; Match m; using (TextReader f = File.OpenText(filename)) { int ln = 0; ignoreLevel.Clear(); string cline = ""; while (f.Peek() != -1) { string line = f.ReadLine(); ln++; bool skipNextChar = false; string nl = ""; line = line.TrimEnd(); if (line.EndsWith("\\")) { cline += line.Substring(0, line.Length - 1); continue; } else { line = cline + line; if ( ignoreDebugOn &&cline != "") log.DebugFormat("{0}:{1}: Combined line with prior line. {2}", filename, ln, line); cline = ""; } this.lineBeforePreprocessing = line; var line_len = line.Length; for (int i = 0; i < line_len; i++) { string c = line.Substring(i, 1); string nc = ""; if (line_len > i + 1) nc = line.Substring(i + 1, 1); string tok = c + nc; if (skipNextChar) { ignoreDebug(string.Format("Skipping {0}.", tok)); skipNextChar = false; // this.comment += c ignoreDebug(string.Format("this.comment = {0}.", this.comment)); continue; } if (tok == "//") { //if(this.ignoreDebugOn) debug(filename,ln,this.cpath,'{} ({})'.format(tok,len(ignoreLevel))) if (ignoreLevel.Count == 0) { this.comment = line.Substring(i); // if this.ignoreDebugOn: print('this.comment = {}.'.format(repr(this.comment))) // print('Found '+this.comment) this.finishComment(cleansed_line: nl); break; } } if (ignoreTokens.ContainsKey(tok)) { string pc = ""; if (i > 0) pc = line.Substring(i - 1, 1); if (tok == "{\"" && pc == "\"") { this.comment += c; continue; } // if this.ignoreDebugOn: print(repr(this.ignoreTokens[tok])) string stop = ignoreTokens[tok]; // End comment if (stop == null) { if (ignoreLevel.Count > 0) { if (ignoreLevel.Peek() == tok) { skipNextChar = true; this.comment += tok; ignoreLevel.Pop(); if (ignoreLevel.Count == 0) this.finishComment(); continue; } else { this.comment += c; continue; } } } else // Start comment { skipNextChar = true; ignoreLevel.Push(stop); this.comment = tok; continue; } if (this.ignoreDebugOn) debug(filename, ln, this.cpath, string.Format("{0} ({1})", tok, ignoreLevel.Count)); } if (ignoreLevel.Count == 0) nl += c; else this.comment += c; } if (line != nl) { ignoreDebug("IN : " + line); line = nl; ignoreDebug("OUT: " + line); ignoreDebug(string.Format("this.comment = {0}.", comment)); } if (ignoreLevel.Count > 0) { this.comment += "\n"; continue; } line = REGEX_LINE_COMMENT.Replace(line, ""); if (line.Trim() == "") { //if (loadingProc != null) // loadingProc.AddBlankLine(); continue; } ///////////////////////////// // Preprocessing defines. if (line.Trim().StartsWith("#")) { if (line.EndsWith("\\")) continue; var tokenChunks = line.Split('#'); tokenChunks = tokenChunks[1].Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); var directive = tokenChunks[0]; //if (line.Contains("MAX_PILL_SPRITE")) // throw new Exception("MAX PILL SPRITE"); if (directive == "define") { // //define SOMETHING Value var defineChunks = line.Split(new char[] { ' ', '\t' }, 3, StringSplitOptions.RemoveEmptyEntries).ToList(); if (defineChunks.Count == 2) defineChunks.Add("1"); else if (defineChunks.Count == 3) defineChunks[2] = this.PreprocessLine(defineChunks[2]); // print(repr(defineChunks)) try { Defines[defineChunks[1]] = new BYONDNumber(float.Parse(defineChunks[2]), filename, ln); } catch { Defines[defineChunks[1]] = new BYONDString(defineChunks[2], filename, ln); } //this.fileLayout += [("DEFINE", defineChunks[1], defineChunks[2])] } else if (directive == "undef") { var undefChunks = line.Split(new char[] { ' ', '\t' }, 2); if (Defines.ContainsKey(undefChunks[1])) Defines.Remove(undefChunks[1]); //this.fileLayout += [("UNDEF", undefChunks[1])] // OpenBYOND tokens. } else if (directive.StartsWith("__OB_")) { int numtabs = 0; m = REGEX_TABS.Match(line); if (m.Success) numtabs = m.Groups["tabs"].Length; string atom = this.DetermineContext(filename, ln, line, numtabs); // if atom is None: continue // print("OBTOK {0}".format(repr(tokenChunks))) this.handleOBToken(tokenChunks[0].Replace("__OB_", ""), atom, tokenChunks.Skip(1).ToArray()); // this.fileLayout += [("OBTOK", atom.path)] continue; } else { var chunks = line.Split(' '); //this.fileLayout += [("PP_TOKEN", line)] log.WarnFormat("BUG: Unhandled preprocessor directive #{0} in {1}:{2}", directive, filename, ln); } continue; } // Preprocessing line = this.PreprocessLine(line); m = REGEX_TABS.Match(this.lineBeforePreprocessing); if (m.Success) { var numtabs = m.Groups["tabs"].Length; //if(lineBeforePreprocessing.StartsWith("\t")) // log.DebugFormat("TABS: {0} ? {1} - {2}: {3}", numtabs, this.ignoreStartIndent, this.loadingProc, line); if (this.ignoreStartIndent > -1 && this.ignoreStartIndent < numtabs) { if (loadingProc != null) { // this.loadingProc.AddCode(numtabs - this.ignoreStartIndent, this.lineBeforePreprocessing.strip()) this.AddCodeToProc(this.ignoreStartIndent, this.lineBeforePreprocessing); } if (contextDebugOn) log.DebugFormat("TABS: {0} ? {1} - {2}: {3}", numtabs, this.ignoreStartIndent, this.loadingProc, line); continue; } else { if (this.contextDebugOn && this.ignoreStartIndent > -1) log.DebugFormat("BREAK ({0} -> {1}): {2}", this.ignoreStartIndent, numtabs, line); this.ignoreStartIndent = -1; this.loadingProc = null; } } else { if (this.contextDebugOn && this.ignoreStartIndent > -1) log.Debug("BREAK " + line); this.ignoreStartIndent = -1; this.loadingProc = null; } if (!line.Trim().StartsWith("var/")) { m = REGEX_ATOMDEF.Match(line); if (m.Success) { var numtabs = m.Groups["tabs"].Length; var atom_str = m.Groups["atom"].Value; var atom_path = new List<string>(this.SplitPath(atom_str)); var atom = this.ProcessAtom(filename, ln, line, atom_str, atom_path, numtabs); //if(atom==null) continue; //this.fileLayout += [("ATOMDEF", atom.path)]; continue; } else { m = REGEX_ABSOLUTE_PROCDEF.Match(line); if (m.Success) { var numtabs = m.Groups["tabs"].Length; var atom = string.Format("{0}/{1}({2})", m.Groups["atom"].Value, m.Groups["proc"].Value, m.Groups["args"].Value); var atom_path = new List<string>(this.SplitPath(atom)); //log.DebugFormat("PROCESSING ABS PROC AT INDENT > {0} {1} -> {2}", numtabs, atom, "/".join(atom_path)); var proc = this.ProcessAtom(filename, ln, line, atom, atom_path, numtabs, m.Groups["args"].Value.Split(',')); if (proc == null) continue; this.ignoreStartIndent = numtabs; this.loadingProc = (Proc)proc; //this.fileLayout += [("PROCDEF", proc.path)] continue; } else { m = REGEX_RELATIVE_PROCDEF.Match(line); if (m.Success) { var numtabs = m.Groups["tabs"].Length; var atom = string.Format("{0}({1})", m.Groups["proc"].Value, m.Groups["args"].Value); var atom_path = new List<string>(this.SplitPath(atom)); // print("IGNORING RELATIVE PROC AT INDENT > " + str(numtabs) + " " + line) var proc = this.ProcessAtom(filename, ln, line, atom, atom_path, numtabs, m.Groups["args"].Value.Split(',')); if (proc == null) continue; this.ignoreStartIndent = numtabs; this.loadingProc = (Proc)proc; //this.fileLayout += [("PROCDEF", proc.path)] continue; } else { if (line.Contains("(") && line.Trim().StartsWith("/") && !line.Contains("list(")) { log.WarnFormat("{0}:{1}: Possible skipped proc: {2}", filename, ln, line); } } } } } var path = "/".join(this.cpath); // if len(this.cpath) > 0 and "proc" in this.cpath: // continue if (line.Contains("=") || line.Trim().StartsWith("var/")) { if (!Atoms.ContainsKey(path)) this.Atoms[path] = new Atom(path); string name; Atom prop; this.consumeVariable(line, filename, ln, out name, out prop); this.Atoms[path].Properties[name] = prop; //this.fileLayout += [("VAR", path, name)]; } } //this.fileLayouts[filename] = this.fileLayout } }
private Atom ProcessAtom(string filename, int ln, string line, string atom, List<string> atom_path, int numtabs, string[] procArgs = null) { // Reserved words that show up on their own if (reservedWords.Contains(atom)) return null; // Other things to ignore (false positives, comments) if (atom.StartsWith("var/") || atom.StartsWith("//")) return null; // Things part of a string or list. if (numtabs > 0 && atom.Trim().StartsWith("/")) return null; if (contextDebugOn) log.DebugFormat("{0} > {1}", numtabs, line.TrimEnd()); // Global scope (no tabs) if (numtabs == 0) { this.cpath = atom_path; // Ensure cpath has a slash at the front (empty first entry) if (this.cpath.Count == 0) this.cpath.Add(""); else if (this.cpath[0] != "") this.cpath.Insert(0, ""); // Create new poplevel stack, add current path length to it. this.popLevels = new Stack<int>(); this.popLevels.Push(this.cpath.Count); if (this.contextDebugOn) debug(filename, ln, this.cpath, "0 - " + string.Join("/", atom_path)); } else if (numtabs > pindent) // Going up a tab level. { // Add path to cpath. this.cpath.AddRange(atom_path); // Add new poplevel with current path length. this.popLevels.Push(atom_path.Count); if (this.contextDebugOn) debug(filename, ln, this.cpath, ">"); } else if (numtabs < pindent) // Going down. { if (this.contextDebugOn) log.DebugFormat("({0} - {1})={2}: {3}", this.pindent, numtabs, this.pindent - numtabs, string.Join("/", this.cpath)); // This is complex as f**k, so bear with me. // For every poplevel we've lost, we need to slice off some path chunks or we f**k up our context. // // /butt // ugly // dirty // /butt/ugly/dirty, 2 poplevels both with content 1 (number of things we added to path) // nice // Here, we slice off 1 path segment, and add "nice", getting /butt/nice. for (int i = 0; i < (this.pindent - numtabs + 1); i++) { // Pop a poplevel out, find out how many path chunks we need to remove. var popsToDo = this.popLevels.Pop(); if (this.contextDebugOn) log.DebugFormat(" pop {0} {1}", popsToDo, this.popLevels); // Now pop off the path segments. for (int j = 0; j < popsToDo; j++) { this.cpath.RemoveAt(this.cpath.Count - 1); if (this.contextDebugOn) log.DebugFormat(" pop {0}/{1}: {2}", i + 1, popsToDo, "/".join(this.cpath)); } } // Add new stuff. this.cpath.AddRange(atom_path); // Add new poplevel for the new stuff. this.popLevels.Push(atom_path.Count); if (this.contextDebugOn) debug(filename, ln, this.cpath, "<"); } else if (numtabs == this.pindent) // Same level. { // Same as above, but we're only going down one indent. var levelsToPop = this.popLevels.Pop(); // Pop off path segments. for (int i = 0; i < levelsToPop; i++) this.cpath.RemoveAt(this.cpath.Count - 1); // New stuff this.cpath.AddRange(atom_path); // New poplevel. this.popLevels.Push(atom_path.Count); if (this.contextDebugOn) log.DebugFormat("popLevels: {0}", this.popLevels.Count); if (this.contextDebugOn) debug(filename, ln, this.cpath, ">"); } var origpath = string.Join("/", this.cpath); // definition? List<string> defs = new List<string>(); // Trim off /proc or /var, if needed. List<string> prep_path = new List<string>(this.cpath); foreach (string special in new string[] { "proc" }) { if (prep_path.Contains(special)) { defs.Add(special); prep_path.Remove(special); } } var npath = "/".join(prep_path); if (!Atoms.ContainsKey(npath)) { if (procArgs != null) { //assert npath.endswith(')') // if origpath != npath: // print(origpath,proc_def) var proc = new Proc(npath, procArgs, filename, ln); proc.origpath = origpath; proc.definition = defs.Contains("proc"); this.Atoms[npath] = proc; } else { this.Atoms[npath] = new Atom(npath, filename, ln); } // if this.debugOn: print('Added ' + npath) } this.pindent = numtabs; return this.Atoms[npath]; }