Skip to content

Commit

Permalink
Polish language server and documentation.
Browse files Browse the repository at this point in the history
  • Loading branch information
Yong He committed Dec 14, 2023
1 parent 3979660 commit 9092fc7
Show file tree
Hide file tree
Showing 8 changed files with 111 additions and 79 deletions.
5 changes: 4 additions & 1 deletion docs/user-guide/03-convenience-features.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,16 @@ namespace ns

You can also use the `using` keyword to pull symbols defined in a different namespace to
the current scope, removing the requirement for using fully qualified names.
```csharp
```cpp
namespace ns1.ns2
{
int f();
}

using ns1.ns2;
// or:
using namespace ns1.ns2; // alternative syntax.

void test() { f(); } // OK.
```
Expand Down
24 changes: 17 additions & 7 deletions docs/user-guide/04-modules-and-access-control.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,13 @@ void f_b() { f_a(); }
// c.slang
implementing "m.slang"; // alternate syntax.
// OK to use f_a and f_b because they are part of module `m`, even
// if we are not including `a` and `b` here.
void f_c() { f_a(); f_b(); }
void f_c()
{
// OK, `c.slang` is part of module `m` because it is `__include`'d by
// `m.slang`.
f_a(); f_b();
}
// m.slang
module m;
Expand All @@ -79,8 +83,14 @@ __include "dir/file-name.slang";
__include "dir/file-name";
```

Also note that a file is considered a part of a module only if the file can be discovered
via transitive `__include`s from the primary module file. It is possible to have a dangling
file with the `implementing` declaration that is not `__include`'d by any other files in
the module. Such dangling files will not be considered as part of the module and will not
be compiled. The `implementing` declaration is for the purpose of verification and language server code assisting, and does not carry any other semantics that affect compilation.

> #### Note ####
> When using the identifier token syntax, Slang will translate any underscores(`_`) to hyphenators("-") to obtain the file name.
> When using the identifier token syntax, Slang will translate any underscores(`_`) to hyphens("-") to obtain the file name.
## Importing a Module

Expand Down Expand Up @@ -150,14 +160,14 @@ module a;
__include b;
public struct PS
{
int internalMember;
internal int internalMember;
public int publicMember;
}
internal void f() { f_b(); } // OK, f_b defined in the same module.
// b.slang
implementing a;
internal void f_b(); // Defines f_b in module a so they can within the module.
internal void f_b(); // Defines f_b in module `a`.
public void publicFunc();

// m.slang
Expand Down Expand Up @@ -190,7 +200,7 @@ The Slang compiler enforces the following rules regarding access control:
Slang used to not have support for access control, and all symbols were treated as having `public` visibility. To provide compatibility with existing code, the Slang compiler will detect if the module is written in the legacy language, and treat all symbols as `public` if so.

A module is determined to be written in legacy language if all the following conditions are met:
- The module is lacking `module` declaration at the begining.
- The module is lacking `module` declaration at the beginning.
- There is no use of `__include`.
- There is no use of any visibility modifiers -- `public`, `private` or `internal`.

Expand Down
2 changes: 2 additions & 0 deletions source/slang/slang-ast-expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ class OverloadedExpr : public Expr
// arose from a member-reference expression.
Expr* base = nullptr;

Expr* originalExpr = nullptr;

// The lookup result that was ambiguous
LookupResult lookupResult2;
};
Expand Down
1 change: 1 addition & 0 deletions source/slang/slang-ast-iterator.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ struct ASTIterator
{
iterator->maybeDispatchCallback(expr);
dispatchIfNotNull(expr->base);
dispatchIfNotNull(expr->originalExpr);
}
void visitOverloadedExpr2(OverloadedExpr2* expr)
{
Expand Down
1 change: 1 addition & 0 deletions source/slang/slang-check-expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -814,6 +814,7 @@ namespace Slang
m_astBuilder->getOverloadedType());
overloadedExpr->base = baseExpr;
overloadedExpr->lookupResult2 = lookupResult;
overloadedExpr->originalExpr = originalExpr;
return overloadedExpr;
}
else
Expand Down
9 changes: 7 additions & 2 deletions source/slang/slang-language-server-ast-lookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ struct ASTLookupExprVisitor: public ExprVisitor<ASTLookupExprVisitor, bool>
declLength = _getDeclNameLength(expr->name, expr->declRef.getDecl());
}
if (_isLocInRange(
context, expr->loc, declLength))
context, expr->loc, declLength))
{
ASTLookupResult result;
result.path = context->nodePath;
Expand All @@ -196,7 +196,7 @@ struct ASTLookupExprVisitor: public ExprVisitor<ASTLookupExprVisitor, bool>
return true;
}
}

return dispatchIfNotNull(expr->originalExpr);
}

Expand Down Expand Up @@ -242,6 +242,11 @@ struct ASTLookupExprVisitor: public ExprVisitor<ASTLookupExprVisitor, bool>
if (dispatchIfNotNull(expr->base))
return true;
}
{
PushNode pushNode(context, expr);
if (dispatchIfNotNull(expr->originalExpr))
return true;
}
if (expr->lookupResult2.getName() &&
_isLocInRange(
context,
Expand Down
147 changes: 78 additions & 69 deletions source/slang/slang-language-server-semantic-tokens.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,78 @@ List<SemanticToken> getSemanticTokens(Linkage* linkage, Module* module, UnownedS
token.type != SemanticTokenType::NormalText)
result.add(token);
};
auto handleDeclRef = [&](DeclRef<Decl> declRef, Expr* originalExpr, SourceLoc loc)
{
if (!declRef)
return;
auto decl = declRef.getDecl();
if (auto genDecl = as<GenericDecl>(decl))
decl = genDecl->inner;
if (!decl)
return;
auto name = declRef.getDecl()->getName();
if (!name)
return;
// Don't look at the expr if it is defined in a different file.
if (!manager->getHumaneLoc(loc, SourceLocType::Actual)
.pathInfo.foundPath.getUnownedSlice()
.endsWithCaseInsensitive(fileName))
return;
SemanticToken token =
_createSemanticToken(manager, loc, name);
auto target = decl;
if (as<AggTypeDecl>(target))
{
if (target->hasModifier<BuiltinTypeModifier>())
return;
token.type = SemanticTokenType::Type;
}
else if (as<ConstructorDecl>(target))
{
token.type = SemanticTokenType::Type;
token.length = doc->getTokenLength(token.line, token.col);
}
else if (as<SimpleTypeDecl>(target))
{
token.type = SemanticTokenType::Type;
}
else if (as<PropertyDecl>(target))
{
token.type = SemanticTokenType::Property;
}
else if (as<ParamDecl>(target))
{
token.type = SemanticTokenType::Parameter;
}
else if (as<VarDecl>(target))
{
if (as<MemberExpr>(originalExpr) ||
as<StaticMemberExpr>(originalExpr))
{
return;
}
token.type = SemanticTokenType::Variable;
}
else if (as<FunctionDeclBase>(target))
{
token.type = SemanticTokenType::Function;
}
else if (as<EnumCaseDecl>(target))
{
token.type = SemanticTokenType::EnumMember;
}
else if (as<NamespaceDecl>(target))
{
token.type = SemanticTokenType::Namespace;
}

if (as<CallableDecl>(target))
{
if (target->hasModifier<ImplicitConversionModifier>())
return;
}
maybeInsertToken(token);
};
iterateAST(
fileName,
manager,
Expand All @@ -56,77 +128,14 @@ List<SemanticToken> getSemanticTokens(Linkage* linkage, Module* module, UnownedS
{
if (auto declRefExpr = as<DeclRefExpr>(node))
{
auto declRef = declRefExpr->declRef;
auto loc = declRefExpr->loc;
if (!declRef)
return;
auto decl = declRef.getDecl();
if (auto genDecl = as<GenericDecl>(decl))
decl = genDecl->inner;
if (!decl)
return;
auto name = declRef.getDecl()->getName();
if (!name)
return;
// Don't look at the expr if it is defined in a different file.
if (!manager->getHumaneLoc(loc, SourceLocType::Actual)
.pathInfo.foundPath.getUnownedSlice()
.endsWithCaseInsensitive(fileName))
return;
SemanticToken token =
_createSemanticToken(manager, loc, name);
auto target = decl;
if (as<AggTypeDecl>(target))
{
if (target->hasModifier<BuiltinTypeModifier>())
return;
token.type = SemanticTokenType::Type;
}
else if (as<ConstructorDecl>(target))
{
token.type = SemanticTokenType::Type;
token.length = doc->getTokenLength(token.line, token.col);
}
else if (as<SimpleTypeDecl>(target))
{
token.type = SemanticTokenType::Type;
}
else if (as<PropertyDecl>(target))
{
token.type = SemanticTokenType::Property;
}
else if (as<ParamDecl>(target))
{
token.type = SemanticTokenType::Parameter;
}
else if (as<VarDecl>(target))
{
if (as<MemberExpr>(declRefExpr->originalExpr) ||
as<StaticMemberExpr>(declRefExpr->originalExpr))
{
return;
}
token.type = SemanticTokenType::Variable;
}
else if (as<FunctionDeclBase>(target))
{
token.type = SemanticTokenType::Function;
}
else if (as<EnumCaseDecl>(target))
{
token.type = SemanticTokenType::EnumMember;
}
else if (as<NamespaceDecl>(target))
{
token.type = SemanticTokenType::Namespace;
}

if (as<CallableDecl>(target))
handleDeclRef(declRefExpr->declRef, declRefExpr->originalExpr, declRefExpr->loc);
}
else if (auto overloadedExpr = as<OverloadedExpr>(node))
{
if (overloadedExpr->lookupResult2.items.getCount())
{
if (target->hasModifier<ImplicitConversionModifier>())
return;
handleDeclRef(overloadedExpr->lookupResult2.items[0].declRef, overloadedExpr->originalExpr, overloadedExpr->loc);
}
maybeInsertToken(token);
}
else if (auto accessorDecl = as<AccessorDecl>(node))
{
Expand Down
1 change: 1 addition & 0 deletions source/slang/slang-parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3374,6 +3374,7 @@ namespace Slang
{
namespaceDecl = parser->astBuilder->create<NamespaceDecl>();
namespaceDecl->nameAndLoc = nameAndLoc;
namespaceDecl->loc = nameAndLoc.loc;
}
}
if (!result)
Expand Down

0 comments on commit 9092fc7

Please sign in to comment.