From 072932b6ff562a3f69cde399659ec6feb63e0575 Mon Sep 17 00:00:00 2001 From: Hackerpilot Date: Sat, 12 Oct 2013 12:34:14 -0700 Subject: [PATCH] Work in progress --- actypes.d | 4 ++++ astconverter.d | 59 ++++++++++++++++++++++++++++++-------------------- notes.txt | 31 ++++++++++++++++++++++++++ semantic.d | 22 +++++++++---------- stupidlog.d | 24 ++++++++++---------- 5 files changed, 93 insertions(+), 47 deletions(-) create mode 100644 notes.txt diff --git a/actypes.d b/actypes.d index 02e3aa2..e4949ae 100644 --- a/actypes.d +++ b/actypes.d @@ -138,6 +138,9 @@ public: */ string symbolFile; + /** + * Gets all parts whose name matches the given string. + */ const(ACSymbol)*[] getPartsByName(string name) const { return cast(typeof(return)) parts.filter!(a => a.name == name).array; @@ -206,6 +209,7 @@ struct Scope } ACSymbol*[] symbols; + string[][] imports; } diff --git a/astconverter.d b/astconverter.d index e00c4bd..eed5309 100644 --- a/astconverter.d +++ b/astconverter.d @@ -18,6 +18,28 @@ * along with this program. If not, see . ******************************************************************************/ +/** + * AST conversion takes place in several steps + * 1. AST is converted to a tree of SemanicSymbols, a tree of ACSymbols, and a + * tree of scopes. The following fields are set on the symbols: + * * name + * * location + * * alias this + * * base class names + * * protection level + * * symbol kind + * * function call tip + * * symbol file path + * Import statements are recorded in the scope tree. + * 2. Scope tree is traversed and all imports are resolved by adding appropriate + * ACSymbol instances. + * 3. Semantic symbol tree is traversed + * * types are resolved + * * base classes are resolved + * * mixin templates are resolved + * * alias this is resolved + */ + module astconverter; import std.array; @@ -34,22 +56,8 @@ import messages; import semantic; import stupidlog; -enum SemanticType +class FirstPass : ASTVisitor { - partial, - full -} - -/** - * Basic visitor class used for caching completions of imported modules. - */ -class SemanticVisitor : ASTVisitor -{ - this (SemanticType sType) - { - this.semanticType = sType; - } - override void visit(Constructor con) { // Log.trace(__FUNCTION__, " ", typeof(con).stringof); @@ -130,13 +138,13 @@ class SemanticVisitor : ASTVisitor foreach (declarator; dec.declarators) { SemanticSymbol* symbol = new SemanticSymbol; - symbol.type = t; - symbol.protection = protection; + symbol.acSymbol.type = t; symbol.kind = CompletionKind.variableName; symbol.name = declarator.name.value.dup; symbol.location = declarator.name.startIndex; + symbol.protection = protection; symbol.parent = currentSymbol; - currentSymbol.children ~= symbol; + currentSymbol.addChild(symbol); } } @@ -234,7 +242,7 @@ class SemanticVisitor : ASTVisitor // Create scope for block statements override void visit(BlockStatement blockStatement) { - Log.trace(__FUNCTION__, " ", typeof(blockStatement).stringof); +// Log.trace(__FUNCTION__, " ", typeof(blockStatement).stringof); Scope* s = new Scope; s.startLocation = blockStatement.startLocation; s.endLocation = blockStatement.endLocation; @@ -243,7 +251,7 @@ class SemanticVisitor : ASTVisitor { foreach (child; currentSymbol.children) { - Log.trace("Setting ", child.name, " location"); +// Log.trace("Setting ", child.name, " location"); child.location = s.startLocation + 1; } } @@ -324,7 +332,7 @@ private: parameter.kind = CompletionKind.variableName; parameter.startLocation = p.name.startIndex; symbol.children ~= parameter; - Log.trace("Parameter ", parameter.name, " added to ", symbol.name); +// Log.trace("Parameter ", parameter.name, " added to ", symbol.name); } } else @@ -393,8 +401,6 @@ private: /// Current scope Scope* currentScope; - - SemanticType semanticType; } @@ -412,6 +418,11 @@ public: { convertSemanticSymbol(symbol); assert (current !is null); + resolveTypes(current); + } + + void resolveTypes(const(ACSymbol*) symbol) + { } ACSymbol* convertSemanticSymbol(const(SemanticSymbol)* symbol) @@ -545,7 +556,7 @@ private: else if (t.type2.symbol !is null) { if (t.type2.symbol.dot) - Log.trace("TODO: global scoped symbol handling"); + Log.error("TODO: global scoped symbol handling"); string[] symbolParts = expandSymbol( t.type2.symbol.identifierOrTemplateChain); diff --git a/notes.txt b/notes.txt new file mode 100644 index 0000000..da15461 --- /dev/null +++ b/notes.txt @@ -0,0 +1,31 @@ +AST → Scopes + → SemanticSymbol → ACSymbol + +ModuleCache has ACSymbol tree +Completion Context has Scopes and ACSymbol instances + + + +Caching +======= + +# Load file +# Lex +# Parse +# BasicSemanticVisitor generates semantic object tree +# Semantic information used to create ACSymbol tree. +# ACSymbol tree stored in ModuleCache + +Completion +========== + +# Lex source +# Parse +# AST Visitor generates semantic objects and scope information +# Semantic informaton used to create ACSymbol tree. This pass is more involved + because it also looks at variables local to functions and other symbols + that would not be included in the module cache. +# Semantic and scope info used to associate ACSymbol nodes and scopes. ACSymbol + objects store their location information. Given a blank Scope tree, a method + can be wnitten to assign ACSymbol instances to the correct scope. +# Autocompletion will need to only look at this simplified Scope/ACSymbol tree. diff --git a/semantic.d b/semantic.d index 60dabb5..6c06000 100644 --- a/semantic.d +++ b/semantic.d @@ -30,21 +30,24 @@ import stdx.d.lexer; struct SemanticSymbol { public: - /// Symbol name - string name; + + void name(string n) @property { acSymbol.name = n; } + + void addChild(SemanticSymbol* child) + { + children ~= child; + acSymbol.parts ~= child.acSymbol; + } + + /// Autocompletion symbol + ACSymbol* acSymbol; /// Base classes string[][] baseClasses; - /// Completion kind - CompletionKind kind; - /// Variable type or function return type Type type; - /// Function call tip. Null if this is not a function - string callTip; - /// Alias this symbols string[] aliasThis; @@ -54,8 +57,5 @@ public: /// Protection level for this symobol TokenType protection; - /// Symbol location - size_t location; - mixin scopeImplementation!(SemanticSymbol); } diff --git a/stupidlog.d b/stupidlog.d index 86ca842..dc78a57 100644 --- a/stupidlog.d +++ b/stupidlog.d @@ -33,39 +33,39 @@ enum LogLevel : uint struct Log { - static void trace(T...)(lazy string message, T args) + static void trace(T...)(T args) { if (level < LogLevel.trace) return; if (output is stdout) - output.writeln("[\033[01;36mtrace\033[0m] " ~ message, args); + output.writeln("[\033[01;36mtrace\033[0m] ", args); else - output.writeln("[trace] " ~ message, args); + output.writeln("[trace] ", args); } - static void info(T...)(lazy string message, T args) + static void info(T...)(T args) { if (level < LogLevel.info) return; if (output is stdout) - output.writeln("[\033[01;32minfo\033[0m ] " ~ message, args); + output.writeln("[\033[01;32minfo\033[0m ] ", args); else - output.writeln("[info ] " ~ message, args); + output.writeln("[info ] ", args); } - static void error(T...)(lazy string message, T args) + static void error(T...)(T args) { if (level < LogLevel.error) return; if (output is stdout) - output.writeln("[\033[01;31merror\033[0m] " ~ message, args); + output.writeln("[\033[01;31merror\033[0m] ", args); else - output.writeln("[error] " ~ message, args); + output.writeln("[error] ", args); } - static void fatal(T...)(lazy string message, T args) + static void fatal(T...)(T args) { if (output is stdout) - output.writeln("[\033[01;35mfatal\033[0m] " ~ message, args); + output.writeln("[\033[01;35mfatal\033[0m] ", args); else - output.writeln("[fatal] " ~ message, args); + output.writeln("[fatal] ", args); } static LogLevel level; static File output;