Work in progress
This commit is contained in:
parent
e2be6948e9
commit
072932b6ff
|
@ -138,6 +138,9 @@ public:
|
||||||
*/
|
*/
|
||||||
string symbolFile;
|
string symbolFile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all parts whose name matches the given string.
|
||||||
|
*/
|
||||||
const(ACSymbol)*[] getPartsByName(string name) const
|
const(ACSymbol)*[] getPartsByName(string name) const
|
||||||
{
|
{
|
||||||
return cast(typeof(return)) parts.filter!(a => a.name == name).array;
|
return cast(typeof(return)) parts.filter!(a => a.name == name).array;
|
||||||
|
@ -206,6 +209,7 @@ struct Scope
|
||||||
}
|
}
|
||||||
|
|
||||||
ACSymbol*[] symbols;
|
ACSymbol*[] symbols;
|
||||||
|
string[][] imports;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,28 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
module astconverter;
|
||||||
|
|
||||||
import std.array;
|
import std.array;
|
||||||
|
@ -34,22 +56,8 @@ import messages;
|
||||||
import semantic;
|
import semantic;
|
||||||
import stupidlog;
|
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)
|
override void visit(Constructor con)
|
||||||
{
|
{
|
||||||
// Log.trace(__FUNCTION__, " ", typeof(con).stringof);
|
// Log.trace(__FUNCTION__, " ", typeof(con).stringof);
|
||||||
|
@ -130,13 +138,13 @@ class SemanticVisitor : ASTVisitor
|
||||||
foreach (declarator; dec.declarators)
|
foreach (declarator; dec.declarators)
|
||||||
{
|
{
|
||||||
SemanticSymbol* symbol = new SemanticSymbol;
|
SemanticSymbol* symbol = new SemanticSymbol;
|
||||||
symbol.type = t;
|
symbol.acSymbol.type = t;
|
||||||
symbol.protection = protection;
|
|
||||||
symbol.kind = CompletionKind.variableName;
|
symbol.kind = CompletionKind.variableName;
|
||||||
symbol.name = declarator.name.value.dup;
|
symbol.name = declarator.name.value.dup;
|
||||||
symbol.location = declarator.name.startIndex;
|
symbol.location = declarator.name.startIndex;
|
||||||
|
symbol.protection = protection;
|
||||||
symbol.parent = currentSymbol;
|
symbol.parent = currentSymbol;
|
||||||
currentSymbol.children ~= symbol;
|
currentSymbol.addChild(symbol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -234,7 +242,7 @@ class SemanticVisitor : ASTVisitor
|
||||||
// Create scope for block statements
|
// Create scope for block statements
|
||||||
override void visit(BlockStatement blockStatement)
|
override void visit(BlockStatement blockStatement)
|
||||||
{
|
{
|
||||||
Log.trace(__FUNCTION__, " ", typeof(blockStatement).stringof);
|
// Log.trace(__FUNCTION__, " ", typeof(blockStatement).stringof);
|
||||||
Scope* s = new Scope;
|
Scope* s = new Scope;
|
||||||
s.startLocation = blockStatement.startLocation;
|
s.startLocation = blockStatement.startLocation;
|
||||||
s.endLocation = blockStatement.endLocation;
|
s.endLocation = blockStatement.endLocation;
|
||||||
|
@ -243,7 +251,7 @@ class SemanticVisitor : ASTVisitor
|
||||||
{
|
{
|
||||||
foreach (child; currentSymbol.children)
|
foreach (child; currentSymbol.children)
|
||||||
{
|
{
|
||||||
Log.trace("Setting ", child.name, " location");
|
// Log.trace("Setting ", child.name, " location");
|
||||||
child.location = s.startLocation + 1;
|
child.location = s.startLocation + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -324,7 +332,7 @@ private:
|
||||||
parameter.kind = CompletionKind.variableName;
|
parameter.kind = CompletionKind.variableName;
|
||||||
parameter.startLocation = p.name.startIndex;
|
parameter.startLocation = p.name.startIndex;
|
||||||
symbol.children ~= parameter;
|
symbol.children ~= parameter;
|
||||||
Log.trace("Parameter ", parameter.name, " added to ", symbol.name);
|
// Log.trace("Parameter ", parameter.name, " added to ", symbol.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -393,8 +401,6 @@ private:
|
||||||
|
|
||||||
/// Current scope
|
/// Current scope
|
||||||
Scope* currentScope;
|
Scope* currentScope;
|
||||||
|
|
||||||
SemanticType semanticType;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -412,6 +418,11 @@ public:
|
||||||
{
|
{
|
||||||
convertSemanticSymbol(symbol);
|
convertSemanticSymbol(symbol);
|
||||||
assert (current !is null);
|
assert (current !is null);
|
||||||
|
resolveTypes(current);
|
||||||
|
}
|
||||||
|
|
||||||
|
void resolveTypes(const(ACSymbol*) symbol)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ACSymbol* convertSemanticSymbol(const(SemanticSymbol)* symbol)
|
ACSymbol* convertSemanticSymbol(const(SemanticSymbol)* symbol)
|
||||||
|
@ -545,7 +556,7 @@ private:
|
||||||
else if (t.type2.symbol !is null)
|
else if (t.type2.symbol !is null)
|
||||||
{
|
{
|
||||||
if (t.type2.symbol.dot)
|
if (t.type2.symbol.dot)
|
||||||
Log.trace("TODO: global scoped symbol handling");
|
Log.error("TODO: global scoped symbol handling");
|
||||||
string[] symbolParts = expandSymbol(
|
string[] symbolParts = expandSymbol(
|
||||||
t.type2.symbol.identifierOrTemplateChain);
|
t.type2.symbol.identifierOrTemplateChain);
|
||||||
|
|
||||||
|
|
|
@ -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.
|
22
semantic.d
22
semantic.d
|
@ -30,21 +30,24 @@ import stdx.d.lexer;
|
||||||
struct SemanticSymbol
|
struct SemanticSymbol
|
||||||
{
|
{
|
||||||
public:
|
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
|
/// Base classes
|
||||||
string[][] baseClasses;
|
string[][] baseClasses;
|
||||||
|
|
||||||
/// Completion kind
|
|
||||||
CompletionKind kind;
|
|
||||||
|
|
||||||
/// Variable type or function return type
|
/// Variable type or function return type
|
||||||
Type type;
|
Type type;
|
||||||
|
|
||||||
/// Function call tip. Null if this is not a function
|
|
||||||
string callTip;
|
|
||||||
|
|
||||||
/// Alias this symbols
|
/// Alias this symbols
|
||||||
string[] aliasThis;
|
string[] aliasThis;
|
||||||
|
|
||||||
|
@ -54,8 +57,5 @@ public:
|
||||||
/// Protection level for this symobol
|
/// Protection level for this symobol
|
||||||
TokenType protection;
|
TokenType protection;
|
||||||
|
|
||||||
/// Symbol location
|
|
||||||
size_t location;
|
|
||||||
|
|
||||||
mixin scopeImplementation!(SemanticSymbol);
|
mixin scopeImplementation!(SemanticSymbol);
|
||||||
}
|
}
|
||||||
|
|
24
stupidlog.d
24
stupidlog.d
|
@ -33,39 +33,39 @@ enum LogLevel : uint
|
||||||
|
|
||||||
struct Log
|
struct Log
|
||||||
{
|
{
|
||||||
static void trace(T...)(lazy string message, T args)
|
static void trace(T...)(T args)
|
||||||
{
|
{
|
||||||
if (level < LogLevel.trace) return;
|
if (level < LogLevel.trace) return;
|
||||||
if (output is stdout)
|
if (output is stdout)
|
||||||
output.writeln("[\033[01;36mtrace\033[0m] " ~ message, args);
|
output.writeln("[\033[01;36mtrace\033[0m] ", args);
|
||||||
else
|
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 (level < LogLevel.info) return;
|
||||||
if (output is stdout)
|
if (output is stdout)
|
||||||
output.writeln("[\033[01;32minfo\033[0m ] " ~ message, args);
|
output.writeln("[\033[01;32minfo\033[0m ] ", args);
|
||||||
else
|
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 (level < LogLevel.error) return;
|
||||||
if (output is stdout)
|
if (output is stdout)
|
||||||
output.writeln("[\033[01;31merror\033[0m] " ~ message, args);
|
output.writeln("[\033[01;31merror\033[0m] ", args);
|
||||||
else
|
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)
|
if (output is stdout)
|
||||||
output.writeln("[\033[01;35mfatal\033[0m] " ~ message, args);
|
output.writeln("[\033[01;35mfatal\033[0m] ", args);
|
||||||
else
|
else
|
||||||
output.writeln("[fatal] " ~ message, args);
|
output.writeln("[fatal] ", args);
|
||||||
}
|
}
|
||||||
static LogLevel level;
|
static LogLevel level;
|
||||||
static File output;
|
static File output;
|
||||||
|
|
Loading…
Reference in New Issue