diff options
| author | Tim Foley <tim.foley.is@gmail.com> | 2017-06-30 13:12:50 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-06-30 13:12:50 -0700 |
| commit | f313df379dd9e0d4395f072ffb87016a6f20d5a1 (patch) | |
| tree | 6c2c07c3930ff68b5518e562b0b507d5ec54d0bf | |
| parent | b2b08679a32506d629df84730f36639dab9f9593 (diff) | |
| parent | cab694dcead92a554654d7fa3f08909d519425f0 (diff) | |
Merge pull request #52 from tfoleyNV/syntax-meta
Add meta-definitions for AST types
| -rw-r--r-- | source/slang/check.cpp | 457 | ||||
| -rw-r--r-- | source/slang/compiler.h | 3 | ||||
| -rw-r--r-- | source/slang/decl-defs.h | 232 | ||||
| -rw-r--r-- | source/slang/expr-defs.h | 109 | ||||
| -rw-r--r-- | source/slang/lookup.h | 3 | ||||
| -rw-r--r-- | source/slang/modifier-defs.h | 271 | ||||
| -rw-r--r-- | source/slang/object-meta-begin.h | 36 | ||||
| -rw-r--r-- | source/slang/object-meta-end.h | 11 | ||||
| -rw-r--r-- | source/slang/slang-stdlib.cpp | 83 | ||||
| -rw-r--r-- | source/slang/slang.cpp | 12 | ||||
| -rw-r--r-- | source/slang/slang.vcxproj | 11 | ||||
| -rw-r--r-- | source/slang/slang.vcxproj.filters | 11 | ||||
| -rw-r--r-- | source/slang/stmt-defs.h | 101 | ||||
| -rw-r--r-- | source/slang/syntax-base-defs.h | 261 | ||||
| -rw-r--r-- | source/slang/syntax-defs.h | 10 | ||||
| -rw-r--r-- | source/slang/syntax-visitors.h | 5 | ||||
| -rw-r--r-- | source/slang/syntax.cpp | 506 | ||||
| -rw-r--r-- | source/slang/syntax.h | 1923 | ||||
| -rw-r--r-- | source/slang/type-defs.h | 393 | ||||
| -rw-r--r-- | source/slang/val-defs.h | 37 | ||||
| -rw-r--r-- | source/slang/visitor.h | 346 | ||||
| -rw-r--r-- | tests/diagnostics/while-predicate-type.slang.expected | 2 |
22 files changed, 2259 insertions, 2564 deletions
diff --git a/source/slang/check.cpp b/source/slang/check.cpp index 4966b102f..a3e061a3b 100644 --- a/source/slang/check.cpp +++ b/source/slang/check.cpp @@ -2,6 +2,7 @@ #include "lookup.h" #include "compiler.h" +#include "visitor.h" #include <assert.h> @@ -42,14 +43,28 @@ namespace Slang return name; } - class SemanticsVisitor : public SyntaxVisitor + struct SemanticsVisitor + : ExprVisitor<SemanticsVisitor, RefPtr<ExpressionSyntaxNode>> + , StmtVisitor<SemanticsVisitor> + , DeclVisitor<SemanticsVisitor> { + DiagnosticSink* sink = nullptr; + DiagnosticSink* getSink() + { + return sink; + } + // ProgramSyntaxNode * program = nullptr; FunctionSyntaxNode * function = nullptr; CompileRequest* request = nullptr; TranslationUnitRequest* translationUnit = nullptr; + SourceLanguage getSourceLanguage() + { + return translationUnit->sourceLanguage; + } + // lexical outer statements List<StatementSyntaxNode*> outerStmts; @@ -62,10 +77,10 @@ namespace Slang public: SemanticsVisitor( - DiagnosticSink * pErr, + DiagnosticSink* sink, CompileRequest* request, TranslationUnitRequest* translationUnit) - : SyntaxVisitor(pErr) + : sink(sink) , request(request) , translationUnit(translationUnit) { @@ -80,7 +95,8 @@ namespace Slang RefPtr<ExpressionSyntaxNode> TranslateTypeNodeImpl(const RefPtr<ExpressionSyntaxNode> & node) { if (!node) return nullptr; - auto expr = node->Accept(this).As<ExpressionSyntaxNode>(); + + auto expr = CheckTerm(node); expr = ExpectATypeRepr(expr); return expr; } @@ -348,9 +364,8 @@ namespace Slang decl->SetCheckState(DeclCheckState::CheckingHeader); } - // TODO: not all of the `Visit` cases are ready to - // handle this being called on-the-fly - decl->Accept(this); + // Use visitor pattern to dispatch to correct case + DeclVisitor::dispatch(decl); decl->SetCheckState(DeclCheckState::Checked); } @@ -513,7 +528,7 @@ namespace Slang RefPtr<ExpressionSyntaxNode> CheckTerm(RefPtr<ExpressionSyntaxNode> term) { if (!term) return nullptr; - return term->Accept(this).As<ExpressionSyntaxNode>(); + return ExprVisitor::dispatch(term); } RefPtr<ExpressionSyntaxNode> CreateErrorExpr(ExpressionSyntaxNode* expr) @@ -1052,7 +1067,12 @@ namespace Slang decl->sup = TranslateTypeNode(decl->sup); } - virtual RefPtr<GenericDecl> VisitGenericDecl(GenericDecl* genericDecl) override + void checkDecl(Decl* decl) + { + EnsureDecl(decl, DeclCheckState::Checked); + } + + void visit(GenericDecl* genericDecl) { // check the parameters for (auto m : genericDecl->Members) @@ -1074,16 +1094,15 @@ namespace Slang // check the nested declaration // TODO: this needs to be done in an appropriate environment... - genericDecl->inner->Accept(this); - return genericDecl; + checkDecl(genericDecl->inner); } - virtual void visitInterfaceDecl(InterfaceDecl* /*decl*/) override + void visit(InterfaceDecl* /*decl*/) { // TODO: do some actual checking of members here } - virtual void visitInheritanceDecl(InheritanceDecl* inheritanceDecl) override + void visit(InheritanceDecl* inheritanceDecl) { // check the type being inherited from auto base = inheritanceDecl->base; @@ -1125,6 +1144,31 @@ namespace Slang return constIntVal; } + void visit(ModifierDecl* decl) + { + // These are only used in the stdlib, so no checking is needed + } + + void visit(GenericTypeParamDecl* decl) + { + // These are only used in the stdlib, so no checking is needed for now + } + + void visit(GenericValueParamDecl* decl) + { + // These are only used in the stdlib, so no checking is needed for now + } + + void visit(GenericTypeConstraintDecl* decl) + { + // These are only used in the stdlib, so no checking is needed for now + } + + void visit(Modifier* modifier) + { + // Do nothing with modifiers for now + } + RefPtr<Modifier> checkModifier( RefPtr<Modifier> m, Decl* /*decl*/) @@ -1226,7 +1270,7 @@ namespace Slang decl->modifiers.first = resultModifiers; } - virtual RefPtr<ProgramSyntaxNode> VisitProgram(ProgramSyntaxNode * programNode) override + void visit(ProgramSyntaxNode* programNode) { // Try to register all the builtin decls for (auto decl : programNode->Members) @@ -1256,37 +1300,37 @@ namespace Slang // - for (auto & s : programNode->GetTypeDefs()) - VisitTypeDefDecl(s.Ptr()); - for (auto & s : programNode->GetStructs()) + for (auto & s : programNode->getMembersOfType<TypeDefDecl>()) + checkDecl(s.Ptr()); + for (auto & s : programNode->getMembersOfType<StructSyntaxNode>()) { - VisitStruct(s.Ptr()); + checkDecl(s.Ptr()); } - for (auto & s : programNode->GetClasses()) + for (auto & s : programNode->getMembersOfType<ClassSyntaxNode>()) { - VisitClass(s.Ptr()); + checkDecl(s.Ptr()); } // HACK(tfoley): Visiting all generic declarations here, // because otherwise they won't get visited. for (auto & g : programNode->getMembersOfType<GenericDecl>()) { - VisitGenericDecl(g.Ptr()); + checkDecl(g.Ptr()); } - for (auto & func : programNode->GetFunctions()) + for (auto & func : programNode->getMembersOfType<FunctionSyntaxNode>()) { if (!func->IsChecked(DeclCheckState::Checked)) { VisitFunctionDeclaration(func.Ptr()); } } - for (auto & func : programNode->GetFunctions()) + for (auto & func : programNode->getMembersOfType<FunctionSyntaxNode>()) { EnsureDecl(func); } if (sink->GetErrorCount() != 0) - return programNode; + return; // Force everything to be fully checked, just in case // Note that we don't just call this on the program, @@ -1301,14 +1345,12 @@ namespace Slang { checkModifiers(d.Ptr()); } - - return programNode; } - virtual RefPtr<ClassSyntaxNode> VisitClass(ClassSyntaxNode * classNode) override + void visit(ClassSyntaxNode * classNode) { if (classNode->IsChecked(DeclCheckState::Checked)) - return classNode; + return; classNode->SetCheckState(DeclCheckState::Checked); for (auto field : classNode->GetFields()) @@ -1316,51 +1358,68 @@ namespace Slang field->Type = CheckUsableType(field->Type); field->SetCheckState(DeclCheckState::Checked); } - return classNode; } - virtual RefPtr<StructSyntaxNode> VisitStruct(StructSyntaxNode * structNode) override + void visit(StructField* field) + { + // TODO: bottleneck through general-case variable checking + + field->Type = CheckUsableType(field->Type); + field->SetCheckState(DeclCheckState::Checked); + } + + void visit(StructSyntaxNode * structNode) { if (structNode->IsChecked(DeclCheckState::Checked)) - return structNode; + return; structNode->SetCheckState(DeclCheckState::Checked); for (auto field : structNode->GetFields()) { - field->Type = CheckUsableType(field->Type); - field->SetCheckState(DeclCheckState::Checked); + checkDecl(field); } - return structNode; } - virtual RefPtr<TypeDefDecl> VisitTypeDefDecl(TypeDefDecl* decl) override + void visit(DeclGroup* declGroup) { - if (decl->IsChecked(DeclCheckState::Checked)) return decl; + for (auto decl : declGroup->decls) + { + checkDecl(decl); + } + } + + void visit(TypeDefDecl* decl) + { + if (decl->IsChecked(DeclCheckState::Checked)) return; decl->SetCheckState(DeclCheckState::CheckingHeader); decl->Type = CheckProperType(decl->Type); decl->SetCheckState(DeclCheckState::Checked); - return decl; } - virtual RefPtr<FunctionSyntaxNode> VisitFunction(FunctionSyntaxNode *functionNode) override + void checkStmt(StatementSyntaxNode* stmt) + { + if (!stmt) return; + StmtVisitor::dispatch(stmt); + } + + void visit(FunctionSyntaxNode *functionNode) { if (functionNode->IsChecked(DeclCheckState::Checked)) - return functionNode; + return; VisitFunctionDeclaration(functionNode); + // TODO: This should really onlye set "checked header" functionNode->SetCheckState(DeclCheckState::Checked); - if (!functionNode->IsExtern()) + // TODO: should put the checking of the body onto a "work list" + // to avoid recursion here. + if (functionNode->Body) { this->function = functionNode; - if (functionNode->Body) - { - functionNode->Body->Accept(this); - } + checkStmt(functionNode->Body); this->function = nullptr; } - return functionNode; } // Check if two functions have the same signature for the purposes @@ -1469,6 +1528,20 @@ namespace Slang } } + void visit(ScopeDecl*) + { + // Nothing to do + } + + void visit(ParameterSyntaxNode* para) + { + // TODO: This needs to bottleneck through the common variable checks + + para->Type = CheckUsableType(para->Type); + if (para->Type.Equals(ExpressionType::GetVoid())) + getSink()->diagnose(para, Diagnostics::parameterCannotBeVoid); + } + void VisitFunctionDeclaration(FunctionSyntaxNode *functionNode) { if (functionNode->IsChecked(DeclCheckState::CheckedHeader)) return; @@ -1480,13 +1553,12 @@ namespace Slang HashSet<String> paraNames; for (auto & para : functionNode->GetParameters()) { + checkDecl(para); + if (paraNames.Contains(para->Name.Content)) getSink()->diagnose(para, Diagnostics::parameterAlreadyDefined, para->Name); else paraNames.Add(para->Name.Content); - para->Type = CheckUsableType(para->Type); - if (para->Type.Equals(ExpressionType::GetVoid())) - getSink()->diagnose(para, Diagnostics::parameterCannotBeVoid); } this->function = NULL; functionNode->SetCheckState(DeclCheckState::CheckedHeader); @@ -1495,13 +1567,26 @@ namespace Slang ValidateFunctionRedeclaration(functionNode); } - virtual RefPtr<StatementSyntaxNode> VisitBlockStatement(BlockStatementSyntaxNode *stmt) override + void visit(VarDeclrStatementSyntaxNode* stmt) + { + // We directly dispatch here instead of using `EnsureDecl()` for two + // reasons: + // + // 1. We expect that a local declaration won't have been referenced + // before it is declared, so that we can just check things in-order + // + // 2. `EnsureDecl()` is specialized for `Decl*` instead of `DeclBase*` + // and trying to special case `DeclGroup*` here feels silly. + // + DeclVisitor::dispatch(stmt->decl); + } + + void visit(BlockStatementSyntaxNode *stmt) { for (auto & node : stmt->Statements) { - node->Accept(this); + checkStmt(node); } - return stmt; } template<typename T> @@ -1518,7 +1603,7 @@ namespace Slang return nullptr; } - virtual RefPtr<StatementSyntaxNode> VisitBreakStatement(BreakStatementSyntaxNode *stmt) override + void visit(BreakStatementSyntaxNode *stmt) { auto outer = FindOuterStmt<BreakableStmt>(); if (!outer) @@ -1526,9 +1611,8 @@ namespace Slang getSink()->diagnose(stmt, Diagnostics::breakOutsideLoop); } stmt->parentStmt = outer; - return stmt; } - virtual RefPtr<StatementSyntaxNode> VisitContinueStatement(ContinueStatementSyntaxNode *stmt) override + void visit(ContinueStatementSyntaxNode *stmt) { auto outer = FindOuterStmt<LoopStmt>(); if (!outer) @@ -1536,7 +1620,6 @@ namespace Slang getSink()->diagnose(stmt, Diagnostics::continueOutsideLoop); } stmt->parentStmt = outer; - return stmt; } void PushOuterStmt(StatementSyntaxNode* stmt) @@ -1549,59 +1632,55 @@ namespace Slang outerStmts.RemoveAt(outerStmts.Count() - 1); } - virtual RefPtr<StatementSyntaxNode> VisitDoWhileStatement(DoWhileStatementSyntaxNode *stmt) override + RefPtr<ExpressionSyntaxNode> checkPredicateExpr(ExpressionSyntaxNode* expr) + { + RefPtr<ExpressionSyntaxNode> e = expr; + e = CheckTerm(e); + e = Coerce(ExpressionType::GetBool(), e); + return e; + } + + void visit(DoWhileStatementSyntaxNode *stmt) { PushOuterStmt(stmt); - if (stmt->Predicate != NULL) - stmt->Predicate = stmt->Predicate->Accept(this).As<ExpressionSyntaxNode>(); - if (!stmt->Predicate->Type->Equals(ExpressionType::GetError()) && - !stmt->Predicate->Type->Equals(ExpressionType::GetInt()) && - !stmt->Predicate->Type->Equals(ExpressionType::GetBool())) - { - getSink()->diagnose(stmt, Diagnostics::whilePredicateTypeError); - } - stmt->Statement->Accept(this); + stmt->Predicate = checkPredicateExpr(stmt->Predicate); + checkStmt(stmt->Statement); PopOuterStmt(stmt); - return stmt; } - virtual RefPtr<StatementSyntaxNode> VisitForStatement(ForStatementSyntaxNode *stmt) override + void visit(ForStatementSyntaxNode *stmt) { PushOuterStmt(stmt); - if (stmt->InitialStatement) - { - stmt->InitialStatement = stmt->InitialStatement->Accept(this).As<StatementSyntaxNode>(); - } + checkStmt(stmt->InitialStatement); if (stmt->PredicateExpression) { - stmt->PredicateExpression = stmt->PredicateExpression->Accept(this).As<ExpressionSyntaxNode>(); - if (!stmt->PredicateExpression->Type->Equals(ExpressionType::GetBool()) && - !stmt->PredicateExpression->Type->Equals(ExpressionType::GetInt()) && - !stmt->PredicateExpression->Type->Equals(ExpressionType::GetUInt())) - { - getSink()->diagnose(stmt->PredicateExpression.Ptr(), Diagnostics::forPredicateTypeError); - } + stmt->PredicateExpression = checkPredicateExpr(stmt->PredicateExpression); } if (stmt->SideEffectExpression) { - stmt->SideEffectExpression = stmt->SideEffectExpression->Accept(this).As<ExpressionSyntaxNode>(); + stmt->SideEffectExpression = CheckExpr(stmt->SideEffectExpression); } - stmt->Statement->Accept(this); + checkStmt(stmt->Statement); PopOuterStmt(stmt); - return stmt; } - virtual RefPtr<SwitchStmt> VisitSwitchStmt(SwitchStmt* stmt) override + void visit(SwitchStmt* stmt) { PushOuterStmt(stmt); // TODO(tfoley): need to coerce condition to an integral type... stmt->condition = CheckExpr(stmt->condition); - stmt->body->Accept(this); + checkStmt(stmt->body); + + // TODO(tfoley): need to check that all case tags are unique + + // TODO(tfoley): check that there is at most one `default` clause + PopOuterStmt(stmt); - return stmt; } - virtual RefPtr<CaseStmt> VisitCaseStmt(CaseStmt* stmt) override + void visit(CaseStmt* stmt) { + // TODO(tfoley): Need to coerce to type being switch on, + // and ensure that value is a compile-time constant auto expr = CheckExpr(stmt->expr); auto switchStmt = FindOuterStmt<SwitchStmt>(); @@ -1617,10 +1696,8 @@ namespace Slang stmt->expr = expr; stmt->parentStmt = switchStmt; - - return stmt; } - virtual RefPtr<DefaultStmt> VisitDefaultStmt(DefaultStmt* stmt) override + void visit(DefaultStmt* stmt) { auto switchStmt = FindOuterStmt<SwitchStmt>(); if (!switchStmt) @@ -1628,33 +1705,31 @@ namespace Slang getSink()->diagnose(stmt, Diagnostics::defaultOutsideSwitch); } stmt->parentStmt = switchStmt; - return stmt; } - virtual RefPtr<StatementSyntaxNode> VisitIfStatement(IfStatementSyntaxNode *stmt) override + void visit(IfStatementSyntaxNode *stmt) { - auto condition = stmt->Predicate; - condition = CheckTerm(condition); - condition = Coerce(ExpressionType::GetBool(), condition); + stmt->Predicate = checkPredicateExpr(stmt->Predicate); + checkStmt(stmt->PositiveStatement); + checkStmt(stmt->NegativeStatement); + } - stmt->Predicate = condition; + void visit(UnparsedStmt*) + { + // Nothing to do + } -#if 0 - if (stmt->Predicate != NULL) - stmt->Predicate = stmt->Predicate->Accept(this).As<ExpressionSyntaxNode>(); - if (!stmt->Predicate->Type->Equals(ExpressionType::GetError()) - && (!stmt->Predicate->Type->Equals(ExpressionType::GetInt()) && - !stmt->Predicate->Type->Equals(ExpressionType::GetBool()))) - getSink()->diagnose(stmt, Diagnostics::ifPredicateTypeError); -#endif - if (stmt->PositiveStatement != NULL) - stmt->PositiveStatement->Accept(this); + void visit(EmptyStatementSyntaxNode*) + { + // Nothing to do + } - if (stmt->NegativeStatement != NULL) - stmt->NegativeStatement->Accept(this); - return stmt; + void visit(DiscardStatementSyntaxNode*) + { + // Nothing to do } - virtual RefPtr<StatementSyntaxNode> VisitReturnStatement(ReturnStatementSyntaxNode *stmt) override + + void visit(ReturnStatementSyntaxNode *stmt) { if (!stmt->Expression) { @@ -1663,7 +1738,7 @@ namespace Slang } else { - stmt->Expression = stmt->Expression->Accept(this).As<ExpressionSyntaxNode>(); + stmt->Expression = CheckTerm(stmt->Expression); if (!stmt->Expression->Type->Equals(ExpressionType::Error.Ptr())) { if (function) @@ -1680,7 +1755,6 @@ namespace Slang } } } - return stmt; } IntegerLiteralValue GetMinBound(RefPtr<IntVal> val) @@ -1758,7 +1832,7 @@ namespace Slang } } - virtual RefPtr<Variable> VisitDeclrVariable(Variable* varDecl) + void visit(Variable* varDecl) { TypeExp typeExp = CheckUsableType(varDecl->Type); #if 0 @@ -1806,86 +1880,21 @@ namespace Slang } varDecl->SetCheckState(DeclCheckState::Checked); - - return varDecl; } - virtual RefPtr<StatementSyntaxNode> VisitWhileStatement(WhileStatementSyntaxNode *stmt) override + void visit(WhileStatementSyntaxNode *stmt) { PushOuterStmt(stmt); - stmt->Predicate = stmt->Predicate->Accept(this).As<ExpressionSyntaxNode>(); - if (!stmt->Predicate->Type->Equals(ExpressionType::GetError()) && - !stmt->Predicate->Type->Equals(ExpressionType::GetInt()) && - !stmt->Predicate->Type->Equals(ExpressionType::GetBool())) - getSink()->diagnose(stmt, Diagnostics::whilePredicateTypeError2); - - stmt->Statement->Accept(this); + stmt->Predicate = checkPredicateExpr(stmt->Predicate); + checkStmt(stmt->Statement); PopOuterStmt(stmt); - return stmt; } - virtual RefPtr<StatementSyntaxNode> VisitExpressionStatement(ExpressionStatementSyntaxNode *stmt) override + void visit(ExpressionStatementSyntaxNode *stmt) { - stmt->Expression = stmt->Expression->Accept(this).As<ExpressionSyntaxNode>(); - return stmt; + stmt->Expression = CheckExpr(stmt->Expression); } - virtual RefPtr<ExpressionSyntaxNode> VisitOperatorExpression(OperatorExpressionSyntaxNode *expr) override - { -#if 0 - - for (int i = 0; i < expr->Arguments.Count(); i++) - expr->Arguments[i] = expr->Arguments[i]->Accept(this).As<ExpressionSyntaxNode>(); - auto & leftType = expr->Arguments[0]->Type; - QualType rightType; - if (expr->Arguments.Count() == 2) - rightType = expr->Arguments[1]->Type; - RefPtr<ExpressionType> matchedType; - auto checkAssign = [&]() - { - if (!leftType.IsLeftValue && - !leftType->Equals(ExpressionType::Error.Ptr())) - getSink()->diagnose(expr->Arguments[0].Ptr(), Diagnostics::assignNonLValue); - if (expr->Operator == Operator::AndAssign || - expr->Operator == Operator::OrAssign || - expr->Operator == Operator::XorAssign || - expr->Operator == Operator::LshAssign || - expr->Operator == Operator::RshAssign) - { -#if 0 - if (!(leftType->IsIntegral() && rightType->IsIntegral())) - { - // TODO(tfoley): This diagnostic shouldn't be handled here -// getSink()->diagnose(expr, Diagnostics::bitOperationNonIntegral); - } -#endif - } - // TODO(tfoley): Need to actual insert coercion here... - if(CanCoerce(leftType, expr->Type)) - expr->Type = leftType; - else - expr->Type = ExpressionType::Error; - }; -#if 0 - if (expr->Operator == Operator::Assign) - { - expr->Type = rightType; - checkAssign(); - } - else -#endif - { - expr->FunctionExpr = CheckExpr(expr->FunctionExpr); - CheckInvokeExprWithCheckedOperands(expr); - if (expr->Operator > Operator::Assign) - checkAssign(); - } - return expr; -#endif - - // Treat operator application just like a function call - return VisitInvokeExpression(expr); - } - virtual RefPtr<ExpressionSyntaxNode> VisitConstantExpression(ConstantExpressionSyntaxNode *expr) override + RefPtr<ExpressionSyntaxNode> visit(ConstantExpressionSyntaxNode *expr) { // The expression might already have a type, determined by its suffix if(expr->Type.type) @@ -2053,7 +2062,7 @@ namespace Slang { auto varDecl = varRef.getDecl(); - switch(sourceLanguage) + switch(getSourceLanguage()) { case SourceLanguage::Slang: case SourceLanguage::HLSL: @@ -2202,7 +2211,7 @@ namespace Slang return DeclRefType::Create(declRef)->As<VectorExpressionType>(); } - virtual RefPtr<ExpressionSyntaxNode> VisitIndexExpression(IndexExpressionSyntaxNode* subscriptExpr) override + RefPtr<ExpressionSyntaxNode> visit(IndexExpressionSyntaxNode* subscriptExpr) { auto baseExpr = subscriptExpr->BaseExpression; baseExpr = CheckExpr(baseExpr); @@ -2408,7 +2417,7 @@ namespace Slang // - virtual void VisitExtensionDecl(ExtensionDecl* decl) override + void visit(ExtensionDecl* decl) { if (decl->IsChecked(DeclCheckState::Checked)) return; @@ -2451,7 +2460,7 @@ namespace Slang decl->SetCheckState(DeclCheckState::Checked); } - virtual void VisitConstructorDecl(ConstructorDecl* decl) override + void visit(ConstructorDecl* decl) { if (decl->IsChecked(DeclCheckState::Checked)) return; decl->SetCheckState(DeclCheckState::CheckingHeader); @@ -2467,7 +2476,7 @@ namespace Slang } - virtual void visitSubscriptDecl(SubscriptDecl* decl) override + void visit(SubscriptDecl* decl) { if (decl->IsChecked(DeclCheckState::Checked)) return; decl->SetCheckState(DeclCheckState::CheckingHeader); @@ -2484,7 +2493,7 @@ namespace Slang decl->SetCheckState(DeclCheckState::Checked); } - virtual void visitAccessorDecl(AccessorDecl* decl) override + void visit(AccessorDecl* decl) { // TODO: check the body! @@ -4337,7 +4346,7 @@ namespace Slang } } - RefPtr<ExpressionSyntaxNode> VisitGenericApp(GenericAppExpr * genericAppExpr) override + RefPtr<ExpressionSyntaxNode> visit(GenericAppExpr * genericAppExpr) { // We are applying a generic to arguments, but there might be multiple generic // declarations with the same name, so this becomes a specialized case of @@ -4488,7 +4497,7 @@ namespace Slang #endif } - RefPtr<ExpressionSyntaxNode> VisitSharedTypeExpr(SharedTypeExpr* expr) override + RefPtr<ExpressionSyntaxNode> visit(SharedTypeExpr* expr) { if (!expr->Type.Ptr()) { @@ -4503,7 +4512,12 @@ namespace Slang RefPtr<ExpressionSyntaxNode> CheckExpr(RefPtr<ExpressionSyntaxNode> expr) { - return expr->Accept(this).As<ExpressionSyntaxNode>(); + auto term = CheckTerm(expr); + + // TODO(tfoley): Need a step here to ensure that the term actually + // resolves to a (single) expression with a real type. + + return term; } RefPtr<ExpressionSyntaxNode> CheckInvokeExprWithCheckedOperands(InvokeExpressionSyntaxNode *expr) @@ -4541,7 +4555,7 @@ namespace Slang return rs; } - virtual RefPtr<ExpressionSyntaxNode> VisitInvokeExpression(InvokeExpressionSyntaxNode *expr) override + RefPtr<ExpressionSyntaxNode> visit(InvokeExpressionSyntaxNode *expr) { // check the base expression first expr->FunctionExpr = CheckExpr(expr->FunctionExpr); @@ -4556,7 +4570,7 @@ namespace Slang } - virtual RefPtr<ExpressionSyntaxNode> VisitVarExpression(VarExpressionSyntaxNode *expr) override + RefPtr<ExpressionSyntaxNode> visit(VarExpressionSyntaxNode *expr) { // If we've already resolved this expression, don't try again. if (expr->declRef) @@ -4577,9 +4591,10 @@ namespace Slang return expr; } - virtual RefPtr<ExpressionSyntaxNode> VisitTypeCastExpression(TypeCastExpressionSyntaxNode * expr) override + + RefPtr<ExpressionSyntaxNode> visit(TypeCastExpressionSyntaxNode * expr) { - expr->Expression = expr->Expression->Accept(this).As<ExpressionSyntaxNode>(); + expr->Expression = CheckTerm(expr->Expression); auto targetType = CheckProperType(expr->TargetType); expr->TargetType = targetType; @@ -4608,6 +4623,8 @@ namespace Slang return expr; } } + // TODO: other cases? Should we allow a cast to succeeed whenever + // a single-argument constructor for the target type would work? fail: // Default: in no other case succeds, then the cast failed and we emit a diagnostic. @@ -4648,6 +4665,34 @@ namespace Slang &typeResult); } + // + // Some syntax nodes should not occur in the concrete input syntax, + // and will only appear *after* checking is complete. We need to + // deal with this cases here, even if they are no-ops. + // + + RefPtr<ExpressionSyntaxNode> visit(DerefExpr* expr) + { + assert(!"unexpected"); + return expr; + } + + RefPtr<ExpressionSyntaxNode> visit(SwizzleExpr* expr) + { + assert(!"unexpected"); + return expr; + } + + RefPtr<ExpressionSyntaxNode> visit(OverloadedExpr* expr) + { + assert(!"unexpected"); + return expr; + } + + // + // + // + RefPtr<ExpressionSyntaxNode> MaybeDereference(RefPtr<ExpressionSyntaxNode> inExpr) { RefPtr<ExpressionSyntaxNode> expr = inExpr; @@ -4782,7 +4827,7 @@ namespace Slang } - virtual RefPtr<ExpressionSyntaxNode> VisitMemberExpression(MemberExpressionSyntaxNode * expr) override + RefPtr<ExpressionSyntaxNode> visit(MemberExpressionSyntaxNode * expr) { expr->BaseExpression = CheckExpr(expr->BaseExpression); @@ -4881,7 +4926,7 @@ namespace Slang // - virtual RefPtr<ExpressionSyntaxNode> visitInitializerListExpr(InitializerListExpr* expr) override + RefPtr<ExpressionSyntaxNode> visit(InitializerListExpr* expr) { // When faced with an initializer list, we first just check the sub-expressions blindly. // Actually making them conform to a desired type will wait for when we know the desired @@ -4927,7 +4972,12 @@ namespace Slang } } - virtual void visitImportDecl(ImportDecl* decl) override + void visit(EmptyDecl* /*decl*/) + { + // nothing to do + } + + void visit(ImportDecl* decl) { if(decl->IsChecked(DeclCheckState::Checked)) return; @@ -4957,12 +5007,15 @@ namespace Slang } }; - SyntaxVisitor* CreateSemanticsVisitor( - DiagnosticSink* err, - CompileRequest* request, + void checkTranslationUnit( TranslationUnitRequest* translationUnit) { - return new SemanticsVisitor(err, request, translationUnit); + SemanticsVisitor visitor( + &translationUnit->compileRequest->mSink, + translationUnit->compileRequest, + translationUnit); + + visitor.checkDecl(translationUnit->SyntaxNode); } // diff --git a/source/slang/compiler.h b/source/slang/compiler.h index a6f3eee0e..b3bcd7ba1 100644 --- a/source/slang/compiler.h +++ b/source/slang/compiler.h @@ -224,9 +224,6 @@ namespace Slang void parseTranslationUnit( TranslationUnitRequest* translationUnit); - void CompileRequest::checkTranslationUnit( - TranslationUnitRequest* translationUnit); - void checkAllTranslationUnits(); int executeActionsInner(); diff --git a/source/slang/decl-defs.h b/source/slang/decl-defs.h new file mode 100644 index 000000000..f2405b0f0 --- /dev/null +++ b/source/slang/decl-defs.h @@ -0,0 +1,232 @@ +// decl-defs.h + +// Syntax class definitions for declarations. + +// A group of declarations that should be treated as a unit +SYNTAX_CLASS(DeclGroup, DeclBase) + SYNTAX_FIELD(List<RefPtr<Decl>>, decls) +END_SYNTAX_CLASS() + +// A "container" decl is a parent to other declarations +ABSTRACT_SYNTAX_CLASS(ContainerDecl, Decl) + SYNTAX_FIELD(List<RefPtr<Decl>>, Members) + + RAW( + template<typename T> + FilteredMemberList<T> getMembersOfType() + { + return FilteredMemberList<T>(Members); + } + + + // Dictionary for looking up members by name. + // This is built on demand before performing lookup. + Dictionary<String, Decl*> memberDictionary; + + // Whether the `memberDictionary` is valid. + // Should be set to `false` if any members get added/remoed. + bool memberDictionaryIsValid = false; + + // A list of transparent members, to be used in lookup + // Note: this is only valid if `memberDictionaryIsValid` is true + List<TransparentMemberInfo> transparentMembers; + ) +END_SYNTAX_CLASS() + +// Base class for all variable-like declarations +ABSTRACT_SYNTAX_CLASS(VarDeclBase, Decl) + + // Type of the variable + SYNTAX_FIELD(TypeExp, Type) + + RAW( + ExpressionType* getType() { return Type.type.Ptr(); } + ) + + // Initializer expression (optional) + SYNTAX_FIELD(RefPtr<ExpressionSyntaxNode>, Expr) +END_SYNTAX_CLASS() + + +// A field of a `struct` type +SIMPLE_SYNTAX_CLASS(StructField, VarDeclBase) + +// An `AggTypeDeclBase` captures the shared functionality +// between true aggregate type declarations and extension +// declarations: +// +// - Both can container members (they are `ContainerDecl`s) +// - Both can have declared bases +// - Both expose a `this` variable in their body +// +ABSTRACT_SYNTAX_CLASS(AggTypeDeclBase, ContainerDecl) +END_SYNTAX_CLASS() + +// An extension to apply to an existing type +SYNTAX_CLASS(ExtensionDecl, AggTypeDeclBase) + SYNTAX_FIELD(TypeExp, targetType) + + // next extension attached to the same nominal type + DECL_FIELD(ExtensionDecl*, nextCandidateExtension RAW(= nullptr)) +END_SYNTAX_CLASS() + +// Declaration of a type that represents some sort of aggregate +ABSTRACT_SYNTAX_CLASS(AggTypeDecl, AggTypeDeclBase) + +RAW( + // extensions that might apply to this declaration + ExtensionDecl* candidateExtensions = nullptr; + FilteredMemberList<StructField> GetFields() + { + return getMembersOfType<StructField>(); + } + StructField* FindField(String name) + { + for (auto field : GetFields()) + { + if (field->Name.Content == name) + return field.Ptr(); + } + return nullptr; + } + int FindFieldIndex(String name) + { + int index = 0; + for (auto field : GetFields()) + { + if (field->Name.Content == name) + return index; + index++; + } + return -1; + } + ) +END_SYNTAX_CLASS() + +SIMPLE_SYNTAX_CLASS(StructSyntaxNode, AggTypeDecl) + +SIMPLE_SYNTAX_CLASS(ClassSyntaxNode, AggTypeDecl) + +// An interface which other types can conform to +SIMPLE_SYNTAX_CLASS(InterfaceDecl, AggTypeDecl) + +// A kind of pseudo-member that represents an explicit +// or implicit inheritance relationship. +// +SYNTAX_CLASS(InheritanceDecl, Decl) + // The type expression as written + SYNTAX_FIELD(TypeExp, base) +END_SYNTAX_CLASS() + +// TODO: may eventually need sub-classes for explicit/direct vs. implicit/indirect inheritance + + +// A declaration that represents a simple (non-aggregate) type +// +// TODO: probably all types will be aggregate decls eventually, +// so that we can easily store conformances/constraints on type variables +ABSTRACT_SYNTAX_CLASS(SimpleTypeDecl, Decl) +END_SYNTAX_CLASS() + +// A `typedef` declaration +SYNTAX_CLASS(TypeDefDecl, SimpleTypeDecl) + SYNTAX_FIELD(TypeExp, Type) +END_SYNTAX_CLASS() + +// A scope for local declarations (e.g., as part of a statement) +SIMPLE_SYNTAX_CLASS(ScopeDecl, ContainerDecl) + +SIMPLE_SYNTAX_CLASS(ParameterSyntaxNode, VarDeclBase) + +// Base class for things that have parameter lists and can thus be applied to arguments ("called") +ABSTRACT_SYNTAX_CLASS(CallableDecl, ContainerDecl) + RAW( + FilteredMemberList<ParameterSyntaxNode> GetParameters() + { + return getMembersOfType<ParameterSyntaxNode>(); + }) + + SYNTAX_FIELD(TypeExp, ReturnType) +END_SYNTAX_CLASS() + +// Base class for callable things that may also have a body that is evaluated to produce their result +ABSTRACT_SYNTAX_CLASS(FunctionDeclBase, CallableDecl) + SYNTAX_FIELD(RefPtr<StatementSyntaxNode>, Body) +END_SYNTAX_CLASS() + +// A constructor/initializer to create instances of a type +SIMPLE_SYNTAX_CLASS(ConstructorDecl, FunctionDeclBase) + +// A subscript operation used to index instances of a type +SIMPLE_SYNTAX_CLASS(SubscriptDecl, CallableDecl) + +// An "accessor" for a subscript or property +SIMPLE_SYNTAX_CLASS(AccessorDecl, FunctionDeclBase) + +SIMPLE_SYNTAX_CLASS(GetterDecl, AccessorDecl) +SIMPLE_SYNTAX_CLASS(SetterDecl, AccessorDecl) + +SIMPLE_SYNTAX_CLASS(FunctionSyntaxNode, FunctionDeclBase) + +SIMPLE_SYNTAX_CLASS(Variable, VarDeclBase); + +// A "module" of code (essentiately, a single translation unit) +// that provides a scope for some number of declarations. +SIMPLE_SYNTAX_CLASS(ProgramSyntaxNode, ContainerDecl) + +SYNTAX_CLASS(ImportDecl, Decl) + // The name of the module we are trying to import + FIELD(Token, nameToken) + + // The scope that we want to import into + FIELD(RefPtr<Scope>, scope) + + // The module that actually got imported + DECL_FIELD(RefPtr<ProgramSyntaxNode>, importedModuleDecl) +END_SYNTAX_CLASS() + +// A generic declaration, parameterized on types/values +SYNTAX_CLASS(GenericDecl, ContainerDecl) + // The decl that is genericized... + SYNTAX_FIELD(RefPtr<Decl>, inner) +END_SYNTAX_CLASS() + +SYNTAX_CLASS(GenericTypeParamDecl, SimpleTypeDecl) + // The bound for the type parameter represents a trait that any + // type used as this parameter must conform to +// TypeExp bound; + + // The "initializer" for the parameter represents a default value + SYNTAX_FIELD(TypeExp, initType) +END_SYNTAX_CLASS() + +// A constraint placed as part of a generic declaration +SYNTAX_CLASS(GenericTypeConstraintDecl, Decl) + // A type constraint like `T : U` is constraining `T` to be "below" `U` + // on a lattice of types. This may not be a subtyping relationship + // per se, but it makes sense to use that terminology here, so we + // think of these fields as the sub-type and sup-ertype, respectively. + SYNTAX_FIELD(TypeExp, sub) + SYNTAX_FIELD(TypeExp, sup) +END_SYNTAX_CLASS() + +SIMPLE_SYNTAX_CLASS(GenericValueParamDecl, VarDeclBase) + +// Declaration of a user-defined modifier +SYNTAX_CLASS(ModifierDecl, Decl) + // The name of the C++ class to instantiate + // (this is a reference to a class in the compiler source code, + // and not the user's source code) + FIELD(Token, classNameToken) +END_SYNTAX_CLASS() + +// An empty declaration (which might still have modifiers attached). +// +// An empty declaration is uncommon in HLSL, but +// in GLSL it is often used at the global scope +// to declare metadata that logically belongs +// to the entry point, e.g.: +// +// layout(local_size_x = 16) in; +// +SIMPLE_SYNTAX_CLASS(EmptyDecl, Decl) diff --git a/source/slang/expr-defs.h b/source/slang/expr-defs.h new file mode 100644 index 000000000..59bad37e7 --- /dev/null +++ b/source/slang/expr-defs.h @@ -0,0 +1,109 @@ +// expr-defs.h + +// Syntax class definitions for expressions. + + +// Base class for expressions that will reference declarations +ABSTRACT_SYNTAX_CLASS(DeclRefExpr, ExpressionSyntaxNode) + +// The scope in which to perform lookup + FIELD(RefPtr<Scope>, scope) + + // The declaration of the symbol being referenced + DECL_FIELD(DeclRef<Decl>, declRef) + + // The name of the symbol being referenced + FIELD(String, name) +END_SYNTAX_CLASS() + +SIMPLE_SYNTAX_CLASS(VarExpressionSyntaxNode, DeclRefExpr) + +// An expression that references an overloaded set of declarations +// having the same name. +SYNTAX_CLASS(OverloadedExpr, ExpressionSyntaxNode) + + // Optional: the base expression is this overloaded result + // arose from a member-reference expression. + SYNTAX_FIELD(RefPtr<ExpressionSyntaxNode>, base) + + // The lookup result that was ambiguous + FIELD(LookupResult, lookupResult2) +END_SYNTAX_CLASS() + +SYNTAX_CLASS(ConstantExpressionSyntaxNode, ExpressionSyntaxNode) + FIELD(Token, token) + + RAW( + enum class ConstantType + { + Int, + Bool, + Float, + String, + }; + ConstantType ConstType; + union + { + IntegerLiteralValue integerValue; + FloatingPointLiteralValue floatingPointValue; + }; + String stringValue; + ) +END_SYNTAX_CLASS() + +// An initializer list, e.g. `{ 1, 2, 3 }` +SYNTAX_CLASS(InitializerListExpr, ExpressionSyntaxNode) + SYNTAX_FIELD(List<RefPtr<ExpressionSyntaxNode>>, args) +END_SYNTAX_CLASS() + +// A base expression being applied to arguments: covers +// both ordinary `()` function calls and `<>` generic application +ABSTRACT_SYNTAX_CLASS(AppExprBase, ExpressionSyntaxNode) + SYNTAX_FIELD(RefPtr<ExpressionSyntaxNode>, FunctionExpr) + SYNTAX_FIELD(List<RefPtr<ExpressionSyntaxNode>>, Arguments) +END_SYNTAX_CLASS() + +SIMPLE_SYNTAX_CLASS(InvokeExpressionSyntaxNode, AppExprBase) + +SIMPLE_SYNTAX_CLASS(OperatorExpressionSyntaxNode, InvokeExpressionSyntaxNode) + +SIMPLE_SYNTAX_CLASS(InfixExpr , OperatorExpressionSyntaxNode) +SIMPLE_SYNTAX_CLASS(PrefixExpr , OperatorExpressionSyntaxNode) +SIMPLE_SYNTAX_CLASS(PostfixExpr, OperatorExpressionSyntaxNode) + +SYNTAX_CLASS(IndexExpressionSyntaxNode, ExpressionSyntaxNode) + SYNTAX_FIELD(RefPtr<ExpressionSyntaxNode>, BaseExpression) + SYNTAX_FIELD(RefPtr<ExpressionSyntaxNode>, IndexExpression) +END_SYNTAX_CLASS() + +SYNTAX_CLASS(MemberExpressionSyntaxNode, DeclRefExpr) + SYNTAX_FIELD(RefPtr<ExpressionSyntaxNode>, BaseExpression) +END_SYNTAX_CLASS() + +SYNTAX_CLASS(SwizzleExpr, ExpressionSyntaxNode) + SYNTAX_FIELD(RefPtr<ExpressionSyntaxNode>, base) + FIELD(int, elementCount) + FIELD(int, elementIndices[4]) +END_SYNTAX_CLASS() + +// A dereference of a pointer or pointer-like type +SYNTAX_CLASS(DerefExpr, ExpressionSyntaxNode) + SYNTAX_FIELD(RefPtr<ExpressionSyntaxNode>, base) +END_SYNTAX_CLASS() + +SYNTAX_CLASS(TypeCastExpressionSyntaxNode, ExpressionSyntaxNode) + SYNTAX_FIELD(TypeExp, TargetType) + SYNTAX_FIELD(RefPtr<ExpressionSyntaxNode>, Expression) +END_SYNTAX_CLASS() + +SIMPLE_SYNTAX_CLASS(SelectExpressionSyntaxNode, OperatorExpressionSyntaxNode) + +SIMPLE_SYNTAX_CLASS(GenericAppExpr, AppExprBase) + +// An expression representing re-use of the syntax for a type in more +// than once conceptually-distinct declaration +SYNTAX_CLASS(SharedTypeExpr, ExpressionSyntaxNode) + // The underlying type expression that we want to share + SYNTAX_FIELD(TypeExp, base) +END_SYNTAX_CLASS() + diff --git a/source/slang/lookup.h b/source/slang/lookup.h index 52eaa9804..60e39bfcf 100644 --- a/source/slang/lookup.h +++ b/source/slang/lookup.h @@ -5,7 +5,7 @@ namespace Slang { -class SemanticsVisitor; +struct SemanticsVisitor; // Take an existing lookup result and refine it to only include // results that pass the given `LookupMask`. @@ -31,7 +31,6 @@ LookupResult LookUpLocal( // TODO: this belongs somewhere else -class SemanticsVisitor; QualType getTypeForDeclRef( SemanticsVisitor* sema, DiagnosticSink* sink, diff --git a/source/slang/modifier-defs.h b/source/slang/modifier-defs.h new file mode 100644 index 000000000..a1da47fb7 --- /dev/null +++ b/source/slang/modifier-defs.h @@ -0,0 +1,271 @@ +// modifier-defs.h + +// Syntax class definitions for modifiers. + +// Simple modifiers have no state beyond their identity +#define SIMPLE_MODIFIER(NAME) \ + SIMPLE_SYNTAX_CLASS(NAME##Modifier, Modifier) + +SIMPLE_MODIFIER(Uniform); +SIMPLE_MODIFIER(In); +SIMPLE_MODIFIER(Out); +SIMPLE_MODIFIER(Const); +SIMPLE_MODIFIER(Instance); +SIMPLE_MODIFIER(Builtin); +SIMPLE_MODIFIER(Inline); +SIMPLE_MODIFIER(Public); +SIMPLE_MODIFIER(Require); +SIMPLE_MODIFIER(Param); +SIMPLE_MODIFIER(Extern); +SIMPLE_MODIFIER(Input); +SIMPLE_MODIFIER(Transparent); +SIMPLE_MODIFIER(FromStdLib); +SIMPLE_MODIFIER(Prefix); +SIMPLE_MODIFIER(Postfix); +SIMPLE_MODIFIER(Exported); + +#undef SIMPLE_MODIFIER + +// Base class for modifiers that mark something as "intrinsic" +// and thus lacking a direct implementation in the language. +ABSTRACT_SYNTAX_CLASS(IntrinsicModifierBase, Modifier) +END_SYNTAX_CLASS() + +// A modifier that marks something as one of a small set of +// truly intrinsic operations that the compiler knows about +// directly. +SYNTAX_CLASS(IntrinsicOpModifier, IntrinsicModifierBase) + + // token that names the intrinsic op + FIELD(Token, opToken) + + // The opcode for the intrinsic operation + FIELD_INIT(IntrinsicOp, op, IntrinsicOp::Unknown) +END_SYNTAX_CLASS() + +// A modifier that marks something as an intrinsic function, +// for some subset of targets. +SYNTAX_CLASS(TargetIntrinsicModifier, IntrinsicModifierBase) + // Token that names the target that the operation + // is an intrisic for. + FIELD(Token, targetToken) + + // A custom definition for the operation + FIELD(Token, definitionToken) +END_SYNTAX_CLASS() + +SIMPLE_SYNTAX_CLASS(InOutModifier, OutModifier) + +// This is a special sentinel modifier that gets added +// to the list when we have multiple variable declarations +// all sharing the same modifiers: +// +// static uniform int a : FOO, *b : register(x0); +// +// In this case both `a` and `b` share the syntax +// for part of their modifier list, but then have +// their own modifiers as well: +// +// a: SemanticModifier("FOO") --> SharedModifiers --> StaticModifier --> UniformModifier +// / +// b: RegisterModifier("x0") / +// +SIMPLE_SYNTAX_CLASS(SharedModifiers, Modifier) + +// A GLSL `layout` modifier +// +// We use a distinct modifier for each key that +// appears within the `layout(...)` construct, +// and each key might have an optional value token. +// +// TODO: We probably want a notion of "modifier groups" +// so that we can recover good source location info +// for modifiers that were part of the same vs. +// different constructs. +ABSTRACT_SYNTAX_CLASS(GLSLLayoutModifier, Modifier) + + // The token used to introduce the modifier is stored + // as the `nameToken` field. + + // TODO: may want to accept a full expression here + FIELD(Token, valToken) +END_SYNTAX_CLASS() + +// We divide GLSL `layout` modifiers into those we have parsed +// (in the sense of having some notion of their semantics), and +// those we have not. +ABSTRACT_SYNTAX_CLASS(GLSLParsedLayoutModifier , GLSLLayoutModifier) +END_SYNTAX_CLASS() + +SIMPLE_SYNTAX_CLASS(GLSLUnparsedLayoutModifier , GLSLLayoutModifier) + +// Specific cases for known GLSL `layout` modifiers that we need to work with +SIMPLE_SYNTAX_CLASS(GLSLConstantIDLayoutModifier , GLSLParsedLayoutModifier) +SIMPLE_SYNTAX_CLASS(GLSLBindingLayoutModifier , GLSLParsedLayoutModifier) +SIMPLE_SYNTAX_CLASS(GLSLSetLayoutModifier , GLSLParsedLayoutModifier) +SIMPLE_SYNTAX_CLASS(GLSLLocationLayoutModifier , GLSLParsedLayoutModifier) + +// A catch-all for single-keyword modifiers +SIMPLE_SYNTAX_CLASS(SimpleModifier, Modifier) + +// Some GLSL-specific modifiers +SIMPLE_SYNTAX_CLASS(GLSLBufferModifier , SimpleModifier) +SIMPLE_SYNTAX_CLASS(GLSLWriteOnlyModifier, SimpleModifier) +SIMPLE_SYNTAX_CLASS(GLSLReadOnlyModifier , SimpleModifier) +SIMPLE_SYNTAX_CLASS(GLSLPatchModifier , SimpleModifier) + +// Indicates that this is a variable declaration that corresponds to +// a parameter block declaration in the source program. +SIMPLE_SYNTAX_CLASS(ImplicitParameterBlockVariableModifier , Modifier) + +// Indicates that this is a type that corresponds to the element +// type of a parameter block declaration in the source program. +SIMPLE_SYNTAX_CLASS(ImplicitParameterBlockElementTypeModifier, Modifier) + +// An HLSL semantic +ABSTRACT_SYNTAX_CLASS(HLSLSemantic, Modifier) + FIELD(Token, name) +END_SYNTAX_CLASS() + +// An HLSL semantic that affects layout +SYNTAX_CLASS(HLSLLayoutSemantic, HLSLSemantic) + + FIELD(Token, registerName) + FIELD(Token, componentMask) +END_SYNTAX_CLASS() + +// An HLSL `register` semantic +SIMPLE_SYNTAX_CLASS(HLSLRegisterSemantic, HLSLLayoutSemantic) + +// TODO(tfoley): `packoffset` +SIMPLE_SYNTAX_CLASS(HLSLPackOffsetSemantic, HLSLLayoutSemantic) + +// An HLSL semantic that just associated a declaration with a semantic name +SIMPLE_SYNTAX_CLASS(HLSLSimpleSemantic, HLSLSemantic) + +// GLSL + +// Directives that came in via the preprocessor, but +// that we need to keep around for later steps +SIMPLE_SYNTAX_CLASS(GLSLPreprocessorDirective, Modifier) + +// A GLSL `#version` directive +SYNTAX_CLASS(GLSLVersionDirective, GLSLPreprocessorDirective) + + // Token giving the version number to use + FIELD(Token, versionNumberToken) + + // Optional token giving the sub-profile to be used + FIELD(Token, glslProfileToken) +END_SYNTAX_CLASS() + +// A GLSL `#extension` directive +SYNTAX_CLASS(GLSLExtensionDirective, GLSLPreprocessorDirective) + + // Token giving the version number to use + FIELD(Token, extensionNameToken) + + // Optional token giving the sub-profile to be used + FIELD(Token, dispositionToken) +END_SYNTAX_CLASS() + +SYNTAX_CLASS(ParameterBlockReflectionName, Modifier) + FIELD(Token, nameToken) +END_SYNTAX_CLASS() + +// A modifier that indicates a built-in base type (e.g., `float`) +SYNTAX_CLASS(BuiltinTypeModifier, Modifier) + FIELD(BaseType, tag) +END_SYNTAX_CLASS() + +// A modifier that indicates a built-in type that isn't a base type (e.g., `vector`) +// +// TODO(tfoley): This deserves a better name than "magic" +SYNTAX_CLASS(MagicTypeModifier, Modifier) + FIELD(String, name) + FIELD(uint32_t, tag) +END_SYNTAX_CLASS() + +// Modifiers that affect the storage layout for matrices +SIMPLE_SYNTAX_CLASS(MatrixLayoutModifier, Modifier) + +// Modifiers that specify row- and column-major layout, respectively +SIMPLE_SYNTAX_CLASS(RowMajorLayoutModifier, MatrixLayoutModifier) +SIMPLE_SYNTAX_CLASS(ColumnMajorLayoutModifier, MatrixLayoutModifier) + +// The HLSL flavor of those modifiers +SIMPLE_SYNTAX_CLASS(HLSLRowMajorLayoutModifier, RowMajorLayoutModifier) +SIMPLE_SYNTAX_CLASS(HLSLColumnMajorLayoutModifier, ColumnMajorLayoutModifier) + +// The GLSL flavor of those modifiers +// +// Note(tfoley): The GLSL versions of these modifiers are "backwards" +// in the sense that when a GLSL programmer requests row-major layout, +// we actually interpret that as requesting column-major. This makes +// sense because we interpret matrix conventions backwards from how +// GLSL specifies them. +SIMPLE_SYNTAX_CLASS(GLSLRowMajorLayoutModifier, ColumnMajorLayoutModifier) +SIMPLE_SYNTAX_CLASS(GLSLColumnMajorLayoutModifier, RowMajorLayoutModifier) + +// More HLSL Keyword + +// HLSL `nointerpolation` modifier +SIMPLE_SYNTAX_CLASS(HLSLNoInterpolationModifier, Modifier) + +// HLSL `linear` modifier +SIMPLE_SYNTAX_CLASS(HLSLLinearModifier, Modifier) + +// HLSL `sample` modifier +SIMPLE_SYNTAX_CLASS(HLSLSampleModifier, Modifier) + +// HLSL `centroid` modifier +SIMPLE_SYNTAX_CLASS(HLSLCentroidModifier, Modifier) + +// HLSL `precise` modifier +SIMPLE_SYNTAX_CLASS(HLSLPreciseModifier, Modifier) + +// HLSL `shared` modifier (which is used by the effect system, +// and shouldn't be confused with `groupshared`) +SIMPLE_SYNTAX_CLASS(HLSLEffectSharedModifier, Modifier) + +// HLSL `groupshared` modifier +SIMPLE_SYNTAX_CLASS(HLSLGroupSharedModifier, Modifier) + +// HLSL `static` modifier (probably doesn't need to be +// treated as HLSL-specific) +SIMPLE_SYNTAX_CLASS(HLSLStaticModifier, Modifier) + +// HLSL `uniform` modifier (distinct meaning from GLSL +// use of the keyword) +SIMPLE_SYNTAX_CLASS(HLSLUniformModifier, Modifier) + +// HLSL `volatile` modifier (ignored) +SIMPLE_SYNTAX_CLASS(HLSLVolatileModifier, Modifier) + +// An HLSL `[name(arg0, ...)]` style attribute. +SYNTAX_CLASS(HLSLAttribute, Modifier) + FIELD(Token, nameToken) + SYNTAX_FIELD(List<RefPtr<ExpressionSyntaxNode>>, args) +END_SYNTAX_CLASS() + +// An HLSL `[name(...)]` attribute that hasn't undergone +// any semantic analysis. +// After analysis, this might be transformed into a more specific case. +SIMPLE_SYNTAX_CLASS(HLSLUncheckedAttribute, HLSLAttribute) + +// An HLSL `[numthreads(x,y,z)]` attribute +SYNTAX_CLASS(HLSLNumThreadsAttribute, HLSLAttribute) + // The number of threads to use along each axis + FIELD(int32_t, x) + FIELD(int32_t, y) + FIELD(int32_t, z) +END_SYNTAX_CLASS() + +// HLSL modifiers for geometry shader input topology +SIMPLE_SYNTAX_CLASS(HLSLGeometryShaderInputPrimitiveTypeModifier, Modifier) +SIMPLE_SYNTAX_CLASS(HLSLPointModifier , HLSLGeometryShaderInputPrimitiveTypeModifier) +SIMPLE_SYNTAX_CLASS(HLSLLineModifier , HLSLGeometryShaderInputPrimitiveTypeModifier) +SIMPLE_SYNTAX_CLASS(HLSLTriangleModifier , HLSLGeometryShaderInputPrimitiveTypeModifier) +SIMPLE_SYNTAX_CLASS(HLSLLineAdjModifier , HLSLGeometryShaderInputPrimitiveTypeModifier) +SIMPLE_SYNTAX_CLASS(HLSLTriangleAdjModifier , HLSLGeometryShaderInputPrimitiveTypeModifier) + diff --git a/source/slang/object-meta-begin.h b/source/slang/object-meta-begin.h new file mode 100644 index 000000000..e4187a600 --- /dev/null +++ b/source/slang/object-meta-begin.h @@ -0,0 +1,36 @@ +// object-meta-begin.h + +#ifndef SYNTAX_CLASS +#error The 'SYNTAX_CLASS' macro should be defined before including 'object-meta-begin.h' +#endif + +#ifndef ABSTRACT_SYNTAX_CLASS +#define ABSTRACT_SYNTAX_CLASS(NAME, BASE) SYNTAX_CLASS(NAME, BASE) +#endif + +#ifndef END_SYNTAX_CLASS +#define END_SYNTAX_CLASS() /* empty */ +#endif + +#ifndef DECL_FIELD +#define DECL_FIELD(TYPE, NAME) SYNTAX_FIELD(TYPE, NAME) +#endif + +#ifndef SYNTAX_FIELD +#define SYNTAX_FIELD(TYPE, NAME) FIELD(TYPE, NAME) +#endif + +#ifndef FIELD_INIT +#define FIELD_INIT(TYPE, NAME, INIT) FIELD(TYPE, NAME) +#endif + +#ifndef FIELD +#define FIELD(...) /* empty */ +#endif + +#ifndef RAW +#define RAW(...) /* empty */ +#endif + +#define SIMPLE_SYNTAX_CLASS(NAME, BASE) SYNTAX_CLASS(NAME, BASE) END_SYNTAX_CLASS() + diff --git a/source/slang/object-meta-end.h b/source/slang/object-meta-end.h new file mode 100644 index 000000000..ccfd5f96e --- /dev/null +++ b/source/slang/object-meta-end.h @@ -0,0 +1,11 @@ +// object-meta-end.h + +#undef SYNTAX_CLASS +#undef ABSTRACT_SYNTAX_CLASS +#undef END_SYNTAX_CLASS +#undef SYNTAX_FIELD +#undef FIELD +#undef FIELD_INIT +#undef DECL_FIELD +#undef RAW +#undef SIMPLE_SYNTAX_CLASS diff --git a/source/slang/slang-stdlib.cpp b/source/slang/slang-stdlib.cpp index b43387ddd..513fa3b96 100644 --- a/source/slang/slang-stdlib.cpp +++ b/source/slang/slang-stdlib.cpp @@ -1722,85 +1722,6 @@ namespace Slang } } -#if 0 - for (auto op : intUnaryOps) - { - String opName = GetOperatorFunctionName(op); - for (int i = 0; i < 4; i++) - { - auto itype = intTypes[i]; - auto utype = uintTypes[i]; - for (int j = 0; j < 2; j++) - { - auto retType = (op == Operator::Not) ? "bool" : j == 0 ? itype : utype; - sb << "__intrinsic " << retType << " operator " << opName << "(" << (j == 0 ? itype : utype) << ");\n"; - } - } - } - - for (auto op : floatUnaryOps) - { - String opName = GetOperatorFunctionName(op); - for (int i = 0; i < 4; i++) - { - auto type = floatTypes[i]; - auto retType = (op == Operator::Not) ? "bool" : type; - sb << "__intrinsic " << retType << " operator " << opName << "(" << type << ");\n"; - } - } - - for (auto op : floatOps) - { - String opName = GetOperatorFunctionName(op); - for (int i = 0; i < 4; i++) - { - auto type = floatTypes[i]; - auto itype = intTypes[i]; - auto utype = uintTypes[i]; - auto retType = ((op >= Operator::Eql && op <= Operator::Leq) || op == Operator::And || op == Operator::Or) ? "bool" : type; - sb << "__intrinsic " << retType << " operator " << opName << "(" << type << ", " << type << ");\n"; - sb << "__intrinsic " << retType << " operator " << opName << "(" << itype << ", " << type << ");\n"; - sb << "__intrinsic " << retType << " operator " << opName << "(" << utype << ", " << type << ");\n"; - sb << "__intrinsic " << retType << " operator " << opName << "(" << type << ", " << itype << ");\n"; - sb << "__intrinsic " << retType << " operator " << opName << "(" << type << ", " << utype << ");\n"; - if (i > 0) - { - sb << "__intrinsic " << retType << " operator " << opName << "(" << type << ", " << floatTypes[0] << ");\n"; - sb << "__intrinsic " << retType << " operator " << opName << "(" << floatTypes[0] << ", " << type << ");\n"; - - sb << "__intrinsic " << retType << " operator " << opName << "(" << type << ", " << intTypes[0] << ");\n"; - sb << "__intrinsic " << retType << " operator " << opName << "(" << intTypes[0] << ", " << type << ");\n"; - - sb << "__intrinsic " << retType << " operator " << opName << "(" << type << ", " << uintTypes[0] << ");\n"; - sb << "__intrinsic " << retType << " operator " << opName << "(" << uintTypes[0] << ", " << type << ");\n"; - } - } - } - - for (auto op : intOps) - { - String opName = GetOperatorFunctionName(op); - for (int i = 0; i < 4; i++) - { - auto type = intTypes[i]; - auto utype = uintTypes[i]; - auto retType = ((op >= Operator::Eql && op <= Operator::Leq) || op == Operator::And || op == Operator::Or) ? "bool" : type; - sb << "__intrinsic " << retType << " operator " << opName << "(" << type << ", " << type << ");\n"; - sb << "__intrinsic " << retType << " operator " << opName << "(" << utype << ", " << type << ");\n"; - sb << "__intrinsic " << retType << " operator " << opName << "(" << type << ", " << utype << ");\n"; - sb << "__intrinsic " << retType << " operator " << opName << "(" << utype << ", " << utype << ");\n"; - if (i > 0) - { - sb << "__intrinsic " << retType << " operator " << opName << "(" << type << ", " << intTypes[0] << ");\n"; - sb << "__intrinsic " << retType << " operator " << opName << "(" << intTypes[0] << ", " << type << ");\n"; - - sb << "__intrinsic " << retType << " operator " << opName << "(" << type << ", " << uintTypes[0] << ");\n"; - sb << "__intrinsic " << retType << " operator " << opName << "(" << uintTypes[0] << ", " << type << ");\n"; - } - } - } -#endif - // Output a suitable `#line` directive to point at our raw stdlib code above sb << "\n#line " << kLibIncludeStringLine << " \"" << path << "\"\n"; @@ -1828,10 +1749,6 @@ namespace Slang StringBuilder sb; -#define RAW(TEXT) \ -EMIT_LINE_DIRECTIVE(); \ -sb << TEXT; - static const struct { char const* name; char const* glslPrefix; diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp index cd48a4152..182a5818d 100644 --- a/source/slang/slang.cpp +++ b/source/slang/slang.cpp @@ -178,18 +178,6 @@ void CompileRequest::parseTranslationUnit( } } -void CompileRequest::checkTranslationUnit( - TranslationUnitRequest* translationUnit) -{ - RefPtr<SyntaxVisitor> visitor = CreateSemanticsVisitor( - &mSink, - this, - translationUnit); - - visitor->setSourceLanguage(translationUnit->sourceLanguage); - translationUnit->SyntaxNode->Accept(visitor.Ptr()); -} - void CompileRequest::checkAllTranslationUnits() { for( auto& translationUnit : translationUnits ) diff --git a/source/slang/slang.vcxproj b/source/slang/slang.vcxproj index ba97cb03a..3fde10e4b 100644 --- a/source/slang/slang.vcxproj +++ b/source/slang/slang.vcxproj @@ -167,12 +167,17 @@ <ClInclude Include="..\..\slang.h" /> <ClInclude Include="compiled-program.h" /> <ClInclude Include="compiler.h" /> + <ClInclude Include="decl-defs.h" /> <ClInclude Include="diagnostic-defs.h" /> <ClInclude Include="diagnostics.h" /> <ClInclude Include="emit.h" /> + <ClInclude Include="expr-defs.h" /> <ClInclude Include="intrinsic-defs.h" /> <ClInclude Include="lexer.h" /> <ClInclude Include="lookup.h" /> + <ClInclude Include="modifier-defs.h" /> + <ClInclude Include="object-meta-begin.h" /> + <ClInclude Include="object-meta-end.h" /> <ClInclude Include="parameter-binding.h" /> <ClInclude Include="parser.h" /> <ClInclude Include="preprocessor.h" /> @@ -181,11 +186,17 @@ <ClInclude Include="reflection.h" /> <ClInclude Include="slang-stdlib.h" /> <ClInclude Include="source-loc.h" /> + <ClInclude Include="stmt-defs.h" /> + <ClInclude Include="syntax-base-defs.h" /> + <ClInclude Include="syntax-defs.h" /> <ClInclude Include="syntax-visitors.h" /> <ClInclude Include="syntax.h" /> <ClInclude Include="token-defs.h" /> <ClInclude Include="token.h" /> + <ClInclude Include="type-defs.h" /> <ClInclude Include="type-layout.h" /> + <ClInclude Include="val-defs.h" /> + <ClInclude Include="visitor.h" /> </ItemGroup> <ItemGroup> <ClCompile Include="check.cpp" /> diff --git a/source/slang/slang.vcxproj.filters b/source/slang/slang.vcxproj.filters index aa2edb34a..0ed4457dc 100644 --- a/source/slang/slang.vcxproj.filters +++ b/source/slang/slang.vcxproj.filters @@ -26,6 +26,17 @@ <ClInclude Include="token-defs.h" /> <ClInclude Include="type-layout.h" /> <ClInclude Include="..\..\slang.h" /> + <ClInclude Include="syntax-defs.h" /> + <ClInclude Include="decl-defs.h" /> + <ClInclude Include="expr-defs.h" /> + <ClInclude Include="modifier-defs.h" /> + <ClInclude Include="stmt-defs.h" /> + <ClInclude Include="object-meta-begin.h" /> + <ClInclude Include="object-meta-end.h" /> + <ClInclude Include="syntax-base-defs.h" /> + <ClInclude Include="type-defs.h" /> + <ClInclude Include="val-defs.h" /> + <ClInclude Include="visitor.h" /> </ItemGroup> <ItemGroup> <ClCompile Include="check.cpp" /> diff --git a/source/slang/stmt-defs.h b/source/slang/stmt-defs.h new file mode 100644 index 000000000..9cc1978bd --- /dev/null +++ b/source/slang/stmt-defs.h @@ -0,0 +1,101 @@ +// stmt-defs.h + +// Syntax class definitions for statements. + +ABSTRACT_SYNTAX_CLASS(ScopeStmt, StatementSyntaxNode) + SYNTAX_FIELD(RefPtr<ScopeDecl>, scopeDecl) +END_SYNTAX_CLASS() + +SYNTAX_CLASS(BlockStatementSyntaxNode, ScopeStmt) + SYNTAX_FIELD(List<RefPtr<StatementSyntaxNode>>, Statements) +END_SYNTAX_CLASS() + +SYNTAX_CLASS(UnparsedStmt, StatementSyntaxNode) + // The tokens that were contained between `{` and `}` + FIELD(List<Token>, tokens) +END_SYNTAX_CLASS() + +SIMPLE_SYNTAX_CLASS(EmptyStatementSyntaxNode, StatementSyntaxNode) + +SIMPLE_SYNTAX_CLASS(DiscardStatementSyntaxNode, StatementSyntaxNode) + +SYNTAX_CLASS(VarDeclrStatementSyntaxNode, StatementSyntaxNode) + SYNTAX_FIELD(RefPtr<DeclBase>, decl) +END_SYNTAX_CLASS() + +SYNTAX_CLASS(IfStatementSyntaxNode, StatementSyntaxNode) + SYNTAX_FIELD(RefPtr<ExpressionSyntaxNode>, Predicate) + SYNTAX_FIELD(RefPtr<StatementSyntaxNode>, PositiveStatement) + SYNTAX_FIELD(RefPtr<StatementSyntaxNode>, NegativeStatement) +END_SYNTAX_CLASS() + +// A statement that can be escaped with a `break` +ABSTRACT_SYNTAX_CLASS(BreakableStmt, ScopeStmt) +END_SYNTAX_CLASS() + +SYNTAX_CLASS(SwitchStmt, BreakableStmt) + SYNTAX_FIELD(RefPtr<ExpressionSyntaxNode>, condition) + SYNTAX_FIELD(RefPtr<StatementSyntaxNode>, body) +END_SYNTAX_CLASS() + +// A statement that is expected to appear lexically nested inside +// some other construct, and thus needs to keep track of the +// outer statement that it is associated with... +ABSTRACT_SYNTAX_CLASS(ChildStmt, StatementSyntaxNode) + DECL_FIELD(StatementSyntaxNode*, parentStmt RAW(= nullptr)) +END_SYNTAX_CLASS() + +// a `case` or `default` statement inside a `switch` +// +// Note(tfoley): A correct AST for a C-like language would treat +// these as a labelled statement, and so they would contain a +// sub-statement. I'm leaving that out for now for simplicity. +ABSTRACT_SYNTAX_CLASS(CaseStmtBase, ChildStmt) +END_SYNTAX_CLASS() + +// a `case` statement inside a `switch` +SYNTAX_CLASS(CaseStmt, CaseStmtBase) + SYNTAX_FIELD(RefPtr<ExpressionSyntaxNode>, expr) +END_SYNTAX_CLASS() + +// a `default` statement inside a `switch` +SIMPLE_SYNTAX_CLASS(DefaultStmt, CaseStmtBase) + +// A statement that represents a loop, and can thus be escaped with a `continue` +ABSTRACT_SYNTAX_CLASS(LoopStmt, BreakableStmt) +END_SYNTAX_CLASS() + +SYNTAX_CLASS(ForStatementSyntaxNode, LoopStmt) + SYNTAX_FIELD(RefPtr<StatementSyntaxNode>, InitialStatement) + SYNTAX_FIELD(RefPtr<ExpressionSyntaxNode>, SideEffectExpression) + SYNTAX_FIELD(RefPtr<ExpressionSyntaxNode>, PredicateExpression) + SYNTAX_FIELD(RefPtr<StatementSyntaxNode>, Statement) +END_SYNTAX_CLASS() + + +SYNTAX_CLASS(WhileStatementSyntaxNode, LoopStmt) + SYNTAX_FIELD(RefPtr<ExpressionSyntaxNode>, Predicate) + SYNTAX_FIELD(RefPtr<StatementSyntaxNode>, Statement) +END_SYNTAX_CLASS() + +SYNTAX_CLASS(DoWhileStatementSyntaxNode, LoopStmt) + SYNTAX_FIELD(RefPtr<StatementSyntaxNode>, Statement) + SYNTAX_FIELD(RefPtr<ExpressionSyntaxNode>, Predicate) +END_SYNTAX_CLASS() + +// The case of child statements that do control flow relative +// to their parent statement. +ABSTRACT_SYNTAX_CLASS(JumpStmt, ChildStmt) +END_SYNTAX_CLASS() + +SIMPLE_SYNTAX_CLASS(BreakStatementSyntaxNode, JumpStmt) + +SIMPLE_SYNTAX_CLASS(ContinueStatementSyntaxNode, JumpStmt) + +SYNTAX_CLASS(ReturnStatementSyntaxNode, StatementSyntaxNode) + SYNTAX_FIELD(RefPtr<ExpressionSyntaxNode>, Expression) +END_SYNTAX_CLASS() + +SYNTAX_CLASS(ExpressionStatementSyntaxNode, StatementSyntaxNode) + SYNTAX_FIELD(RefPtr<ExpressionSyntaxNode>, Expression) +END_SYNTAX_CLASS() diff --git a/source/slang/syntax-base-defs.h b/source/slang/syntax-base-defs.h new file mode 100644 index 000000000..11ec30e62 --- /dev/null +++ b/source/slang/syntax-base-defs.h @@ -0,0 +1,261 @@ +// syntax-base-defs.h + +// This file defines the primary base classes for the hierarchy of +// AST nodes and related objects. For example, this is where the +// basic `Decl`, `Stmt`, `Expr`, `Type`, etc. definitions come from. + +// Base class for all nodes representing actual syntax +// (thus having a location in the source code) +ABSTRACT_SYNTAX_CLASS(SyntaxNodeBase, RefObject) + + // The primary source location associated with this AST node + FIELD(CodePosition, Position) +END_SYNTAX_CLASS() + +// Base class for compile-time values (most often a type). +// These are *not* syntax nodes, because they do not have +// a unique location, and any two `Val`s representing +// the same value should be conceptually equal. +ABSTRACT_SYNTAX_CLASS(Val, RefObject) + RAW(typedef IValVisitor Visitor;) + + RAW(virtual void accept(IValVisitor* visitor, void* extra) = 0;) + + RAW( + // construct a new value by applying a set of parameter + // substitutions to this one + RefPtr<Val> Substitute(Substitutions* subst); + + // Lower-level interface for substition. Like the basic + // `Substitute` above, but also takes a by-reference + // integer parameter that should be incremented when + // returning a modified value (this can help the caller + // decide whether they need to do anything). + virtual RefPtr<Val> SubstituteImpl(Substitutions* subst, int* ioDiff); + + virtual bool EqualsVal(Val* val) = 0; + virtual String ToString() = 0; + virtual int GetHashCode() = 0; + bool operator == (const Val & v) + { + return EqualsVal(const_cast<Val*>(&v)); + } + ) +END_SYNTAX_CLASS() + +// A type, representing a classifier for some term in the AST. +// +// Types can include "sugar" in that they may refer to a +// `typedef` which gives them a good name when printed as +// part of diagnostic messages. +// +// In order to operation on types, though, we often want +// to look past any sugar, and operate on an underlying +// "canonical" type. The reprsentation caches a pointer to +// a canonical type on every type, so we can easily +// operate on the raw representation when needed. +ABSTRACT_SYNTAX_CLASS(ExpressionType, Val) + RAW(typedef ITypeVisitor Visitor;) + + RAW(virtual void accept(IValVisitor* visitor, void* extra) override;) + RAW(virtual void accept(ITypeVisitor* visitor, void* extra) = 0;) + +RAW( +public: + static RefPtr<ExpressionType> Error; + static RefPtr<ExpressionType> initializerListType; + static RefPtr<ExpressionType> Overloaded; + + static Dictionary<int, RefPtr<ExpressionType>> sBuiltinTypes; + static Dictionary<String, Decl*> sMagicDecls; + + // Note: just exists to make sure we can clean up + // canonical types we create along the way + static List<RefPtr<ExpressionType>> sCanonicalTypes; + + + + static ExpressionType* GetBool(); + static ExpressionType* GetFloat(); + static ExpressionType* getDoubleType(); + static ExpressionType* GetInt(); + static ExpressionType* GetUInt(); + static ExpressionType* GetVoid(); + static ExpressionType* getInitializerListType(); + static ExpressionType* GetError(); + +public: + virtual String ToString() = 0; + + bool Equals(ExpressionType * type); + bool Equals(RefPtr<ExpressionType> type); + + bool IsVectorType() { return As<VectorExpressionType>() != nullptr; } + bool IsArray() { return As<ArrayExpressionType>() != nullptr; } + + template<typename T> + T* As() + { + return dynamic_cast<T*>(GetCanonicalType()); + } + + // Convenience/legacy wrappers for `As<>` + ArithmeticExpressionType * AsArithmeticType() { return As<ArithmeticExpressionType>(); } + BasicExpressionType * AsBasicType() { return As<BasicExpressionType>(); } + VectorExpressionType * AsVectorType() { return As<VectorExpressionType>(); } + MatrixExpressionType * AsMatrixType() { return As<MatrixExpressionType>(); } + ArrayExpressionType * AsArrayType() { return As<ArrayExpressionType>(); } + + DeclRefType* AsDeclRefType() { return As<DeclRefType>(); } + + NamedExpressionType* AsNamedType(); + + bool IsTextureOrSampler(); + bool IsTexture() { return As<TextureType>() != nullptr; } + bool IsSampler() { return As<SamplerStateType>() != nullptr; } + bool IsStruct(); + bool IsClass(); + static void Init(); + static void Finalize(); + ExpressionType* GetCanonicalType(); + + virtual RefPtr<Val> SubstituteImpl(Substitutions* subst, int* ioDiff) override; + + virtual bool EqualsVal(Val* val) override; +protected: + virtual bool EqualsImpl(ExpressionType * type) = 0; + + virtual ExpressionType* CreateCanonicalType() = 0; + ExpressionType* canonicalType = nullptr; + ) +END_SYNTAX_CLASS() + +// A substitution represents a binding of certain +// type-level variables to concrete argument values +SYNTAX_CLASS(Substitutions, RefObject) + + // The generic declaration that defines the + // parametesr we are binding to arguments + DECL_FIELD(GenericDecl*, genericDecl) + + // The actual values of the arguments + SYNTAX_FIELD(List<RefPtr<Val>>, args) + + // Any further substitutions, relating to outer generic declarations + SYNTAX_FIELD(RefPtr<Substitutions>, outer) + + RAW( + // Apply a set of substitutions to the bindings in this substitution + RefPtr<Substitutions> SubstituteImpl(Substitutions* subst, int* ioDiff); + + // Check if these are equivalent substitutiosn to another set + bool Equals(Substitutions* subst); + bool operator == (const Substitutions & subst) + { + return Equals(const_cast<Substitutions*>(&subst)); + } + int GetHashCode() const + { + int rs = 0; + for (auto && v : args) + { + rs ^= v->GetHashCode(); + rs *= 16777619; + } + return rs; + } + ) +END_SYNTAX_CLASS() + +ABSTRACT_SYNTAX_CLASS(SyntaxNode, SyntaxNodeBase) +END_SYNTAX_CLASS() + +// +// All modifiers are represented as full-fledged objects in the AST +// (that is, we don't use a bitfield, even for simple/common flags). +// This ensures that we can track source locations for all modifiers. +// +ABSTRACT_SYNTAX_CLASS(Modifier, SyntaxNodeBase) + RAW(typedef IModifierVisitor Visitor;) + + RAW(virtual void accept(IModifierVisitor* visitor, void* extra) = 0;) + + // Next modifier in linked list of modifiers on same piece of syntax + SYNTAX_FIELD(RefPtr<Modifier>, next) + + // The token that was used to name this modifier. + FIELD(Token, nameToken) +END_SYNTAX_CLASS() + +// A syntax node which can have modifiers appled +ABSTRACT_SYNTAX_CLASS(ModifiableSyntaxNode, SyntaxNode) + + SYNTAX_FIELD(Modifiers, modifiers) + + RAW( + template<typename T> + FilteredModifierList<T> GetModifiersOfType() { return FilteredModifierList<T>(modifiers.first.Ptr()); } + + // Find the first modifier of a given type, or return `nullptr` if none is found. + template<typename T> + T* FindModifier() + { + return *GetModifiersOfType<T>().begin(); + } + + template<typename T> + bool HasModifier() { return FindModifier<T>() != nullptr; } + ) +END_SYNTAX_CLASS() + + +// An intermediate type to represent either a single declaration, or a group of declarations +ABSTRACT_SYNTAX_CLASS(DeclBase, ModifiableSyntaxNode) + RAW(typedef IDeclVisitor Visitor;) + + RAW(virtual void accept(IDeclVisitor* visitor, void* extra) = 0;) + + +END_SYNTAX_CLASS() + +ABSTRACT_SYNTAX_CLASS(Decl, DeclBase) + DECL_FIELD(ContainerDecl*, ParentDecl RAW(=nullptr)) + + FIELD(Token, Name) + + RAW( + String const& getName() { return Name.Content; } + Token const& getNameToken() { return Name; } + ) + + + FIELD_INIT(DeclCheckState, checkState, DeclCheckState::Unchecked) + + // The next declaration defined in the same container with the same name + DECL_FIELD(Decl*, nextInContainerWithSameName RAW(= nullptr)) + + RAW( + bool IsChecked(DeclCheckState state) { return checkState >= state; } + void SetCheckState(DeclCheckState state) + { + assert(state >= checkState); + checkState = state; + } + ) +END_SYNTAX_CLASS() + +ABSTRACT_SYNTAX_CLASS(ExpressionSyntaxNode, SyntaxNode) + RAW(typedef IExprVisitor Visitor;) + + FIELD(QualType, Type) + + RAW(virtual void accept(IExprVisitor* visitor, void* extra) = 0;) + +END_SYNTAX_CLASS() + +ABSTRACT_SYNTAX_CLASS(StatementSyntaxNode, ModifiableSyntaxNode) + RAW(typedef IStmtVisitor Visitor;) + + RAW(virtual void accept(IStmtVisitor* visitor, void* extra) = 0;) + +END_SYNTAX_CLASS() diff --git a/source/slang/syntax-defs.h b/source/slang/syntax-defs.h new file mode 100644 index 000000000..4ff4a55a6 --- /dev/null +++ b/source/slang/syntax-defs.h @@ -0,0 +1,10 @@ +// syntax-defs.h + +#include "syntax-base-defs.h" + +#include "expr-defs.h" +#include "decl-defs.h" +#include "modifier-defs.h" +#include "stmt-defs.h" +#include "type-defs.h" +#include "val-defs.h" diff --git a/source/slang/syntax-visitors.h b/source/slang/syntax-visitors.h index 5d712b671..85a20a7cf 100644 --- a/source/slang/syntax-visitors.h +++ b/source/slang/syntax-visitors.h @@ -11,11 +11,10 @@ namespace Slang class ShaderCompiler; class ShaderLinkInfo; class ShaderSymbol; + class TranslationUnitRequest; - SyntaxVisitor* CreateSemanticsVisitor( - DiagnosticSink* err, - CompileRequest* request, + void checkTranslationUnit( TranslationUnitRequest* translationUnit); // Look for a module that matches the given name: diff --git a/source/slang/syntax.cpp b/source/slang/syntax.cpp index cf529e55e..983f18bb7 100644 --- a/source/slang/syntax.cpp +++ b/source/slang/syntax.cpp @@ -1,5 +1,9 @@ #include "syntax.h" -#include "syntax-visitors.h" + +#pragma warning AAA +#include "visitor.h" +#pragma warning BBB + #include <typeinfo> #include <assert.h> @@ -51,176 +55,47 @@ namespace Slang return res.ProduceString(); } - RefPtr<SyntaxNode> ProgramSyntaxNode::Accept(SyntaxVisitor * visitor) - { - return visitor->VisitProgram(this); - } - - RefPtr<SyntaxNode> FunctionSyntaxNode::Accept(SyntaxVisitor * visitor) - { - return visitor->VisitFunction(this); - } - - // - - RefPtr<SyntaxNode> ScopeDecl::Accept(SyntaxVisitor * visitor) - { - return visitor->VisitScopeDecl(this); - } - - // +#pragma warning CCC - RefPtr<SyntaxNode> BlockStatementSyntaxNode::Accept(SyntaxVisitor * visitor) - { - return visitor->VisitBlockStatement(this); - } - RefPtr<SyntaxNode> BreakStatementSyntaxNode::Accept(SyntaxVisitor * visitor) - { - return visitor->VisitBreakStatement(this); - } + // Generate dispatch logic and other definitions for all syntax classes +#define SYNTAX_CLASS(NAME, BASE) /* empty */ +#include "object-meta-begin.h" - RefPtr<SyntaxNode> ContinueStatementSyntaxNode::Accept(SyntaxVisitor * visitor) - { - return visitor->VisitContinueStatement(this); - } +#include "syntax-base-defs.h" +#undef SYNTAX_CLASS +#undef ABSTRACT_SYNTAX_CLASS - RefPtr<SyntaxNode> DoWhileStatementSyntaxNode::Accept(SyntaxVisitor * visitor) - { - return visitor->VisitDoWhileStatement(this); - } +#define ABSTRACT_SYNTAX_CLASS(NAME, BASE) /* empty */ +#define SYNTAX_CLASS(NAME, BASE) \ + void NAME::accept(NAME::Visitor* visitor, void* extra) \ + { visitor->dispatch_##NAME(this, extra); } +#include "expr-defs.h" +#include "decl-defs.h" +#include "modifier-defs.h" +#include "stmt-defs.h" +#include "type-defs.h" +#include "val-defs.h" - RefPtr<SyntaxNode> EmptyStatementSyntaxNode::Accept(SyntaxVisitor * visitor) - { - return visitor->VisitEmptyStatement(this); - } +#include "object-meta-end.h" - RefPtr<SyntaxNode> ForStatementSyntaxNode::Accept(SyntaxVisitor * visitor) - { - return visitor->VisitForStatement(this); - } +#pragma warning DDD - RefPtr<SyntaxNode> IfStatementSyntaxNode::Accept(SyntaxVisitor * visitor) - { - return visitor->VisitIfStatement(this); - } - - RefPtr<SyntaxNode> ReturnStatementSyntaxNode::Accept(SyntaxVisitor * visitor) - { - return visitor->VisitReturnStatement(this); - } - - RefPtr<SyntaxNode> VarDeclrStatementSyntaxNode::Accept(SyntaxVisitor * visitor) - { - return visitor->VisitVarDeclrStatement(this); - } - - RefPtr<SyntaxNode> Variable::Accept(SyntaxVisitor * visitor) - { - return visitor->VisitDeclrVariable(this); - } - - RefPtr<SyntaxNode> WhileStatementSyntaxNode::Accept(SyntaxVisitor * visitor) - { - return visitor->VisitWhileStatement(this); - } - - RefPtr<SyntaxNode> ExpressionStatementSyntaxNode::Accept(SyntaxVisitor * visitor) - { - return visitor->VisitExpressionStatement(this); - } - - RefPtr<SyntaxNode> ConstantExpressionSyntaxNode::Accept(SyntaxVisitor * visitor) - { - return visitor->VisitConstantExpression(this); - } - - RefPtr<SyntaxNode> IndexExpressionSyntaxNode::Accept(SyntaxVisitor * visitor) - { - return visitor->VisitIndexExpression(this); - } - RefPtr<SyntaxNode> MemberExpressionSyntaxNode::Accept(SyntaxVisitor * visitor) - { - return visitor->VisitMemberExpression(this); - } - - // SwizzleExpr - - RefPtr<SyntaxNode> SwizzleExpr::Accept(SyntaxVisitor * visitor) - { - return visitor->VisitSwizzleExpression(this); - } - - // DerefExpr - - RefPtr<SyntaxNode> DerefExpr::Accept(SyntaxVisitor * /*visitor*/) - { - // throw "unimplemented"; - return this; - } - - // - - RefPtr<SyntaxNode> InvokeExpressionSyntaxNode::Accept(SyntaxVisitor * visitor) - { - return visitor->VisitInvokeExpression(this); - } - - RefPtr<SyntaxNode> TypeCastExpressionSyntaxNode::Accept(SyntaxVisitor * visitor) - { - return visitor->VisitTypeCastExpression(this); - } - - RefPtr<SyntaxNode> VarExpressionSyntaxNode::Accept(SyntaxVisitor * visitor) - { - return visitor->VisitVarExpression(this); - } - - // OverloadedExpr - - RefPtr<SyntaxNode> OverloadedExpr::Accept(SyntaxVisitor * /*visitor*/) - { -// throw "unimplemented"; - return this; - } - - // - - RefPtr<SyntaxNode> ParameterSyntaxNode::Accept(SyntaxVisitor * visitor) - { - return visitor->VisitParameter(this); - } - - // ImportDecl - - RefPtr<SyntaxNode> ImportDecl::Accept(SyntaxVisitor * visitor) - { - visitor->visitImportDecl(this); - return this; - } +void ExpressionType::accept(IValVisitor* visitor, void* extra) +{ + accept((ITypeVisitor*)visitor, extra); +} - // + // TypeExp - RefPtr<SyntaxNode> StructField::Accept(SyntaxVisitor * visitor) + bool TypeExp::Equals(ExpressionType* other) { - return visitor->VisitStructField(this); - } - RefPtr<SyntaxNode> StructSyntaxNode::Accept(SyntaxVisitor * visitor) - { - return visitor->VisitStruct(this); - } - RefPtr<SyntaxNode> ClassSyntaxNode::Accept(SyntaxVisitor * visitor) - { - return visitor->VisitClass(this); - } - RefPtr<SyntaxNode> TypeDefDecl::Accept(SyntaxVisitor * visitor) - { - return visitor->VisitTypeDefDecl(this); + return type->Equals(other); } - RefPtr<SyntaxNode> DiscardStatementSyntaxNode::Accept(SyntaxVisitor * visitor) + bool TypeExp::Equals(RefPtr<ExpressionType> other) { - return visitor->VisitDiscardStatement(this); + return type->Equals(other.Ptr()); } // BasicExpressionType @@ -358,10 +233,6 @@ namespace Slang else return BaseType->ToString() + "[]"; } - RefPtr<SyntaxNode> GenericAppExpr::Accept(SyntaxVisitor * visitor) - { - return visitor->VisitGenericApp(this); - } // DeclRefType @@ -826,190 +697,6 @@ namespace Slang return this->declRef.substitutions->args[2].As<IntVal>().Ptr(); } - // - -#if 0 - String GetOperatorFunctionName(Operator op) - { - switch (op) - { - case Operator::Add: - case Operator::AddAssign: - return "+"; - case Operator::Sub: - case Operator::SubAssign: - return "-"; - case Operator::Neg: - return "-"; - case Operator::Not: - return "!"; - case Operator::BitNot: - return "~"; - case Operator::PreInc: - case Operator::PostInc: - return "++"; - case Operator::PreDec: - case Operator::PostDec: - return "--"; - case Operator::Mul: - case Operator::MulAssign: - return "*"; - case Operator::Div: - case Operator::DivAssign: - return "/"; - case Operator::Mod: - case Operator::ModAssign: - return "%"; - case Operator::Lsh: - case Operator::LshAssign: - return "<<"; - case Operator::Rsh: - case Operator::RshAssign: - return ">>"; - case Operator::Eql: - return "=="; - case Operator::Neq: - return "!="; - case Operator::Greater: - return ">"; - case Operator::Less: - return "<"; - case Operator::Geq: - return ">="; - case Operator::Leq: - return "<="; - case Operator::BitAnd: - case Operator::AndAssign: - return "&"; - case Operator::BitXor: - case Operator::XorAssign: - return "^"; - case Operator::BitOr: - case Operator::OrAssign: - return "|"; - case Operator::And: - return "&&"; - case Operator::Or: - return "||"; - case Operator::Sequence: - return ","; - case Operator::Select: - return "?:"; - case Operator::Assign: - return "="; - default: - return ""; - } - } -#endif - String OperatorToString(Operator op) - { - switch (op) - { - case Slang::Operator::Neg: - return "-"; - case Slang::Operator::Not: - return "!"; - case Slang::Operator::PreInc: - return "++"; - case Slang::Operator::PreDec: - return "--"; - case Slang::Operator::PostInc: - return "++"; - case Slang::Operator::PostDec: - return "--"; - case Slang::Operator::Mul: - case Slang::Operator::MulAssign: - return "*"; - case Slang::Operator::Div: - case Slang::Operator::DivAssign: - return "/"; - case Slang::Operator::Mod: - case Slang::Operator::ModAssign: - return "%"; - case Slang::Operator::Add: - case Slang::Operator::AddAssign: - return "+"; - case Slang::Operator::Sub: - case Slang::Operator::SubAssign: - return "-"; - case Slang::Operator::Lsh: - case Slang::Operator::LshAssign: - return "<<"; - case Slang::Operator::Rsh: - case Slang::Operator::RshAssign: - return ">>"; - case Slang::Operator::Eql: - return "=="; - case Slang::Operator::Neq: - return "!="; - case Slang::Operator::Greater: - return ">"; - case Slang::Operator::Less: - return "<"; - case Slang::Operator::Geq: - return ">="; - case Slang::Operator::Leq: - return "<="; - case Slang::Operator::BitAnd: - case Slang::Operator::AndAssign: - return "&"; - case Slang::Operator::BitXor: - case Slang::Operator::XorAssign: - return "^"; - case Slang::Operator::BitOr: - case Slang::Operator::OrAssign: - return "|"; - case Slang::Operator::And: - return "&&"; - case Slang::Operator::Or: - return "||"; - case Slang::Operator::Assign: - return "="; - default: - return "ERROR"; - } - } - - // TypeExp - - TypeExp TypeExp::Accept(SyntaxVisitor* visitor) - { - return visitor->VisitTypeExp(*this); - } - - // BuiltinTypeModifier - - // MagicTypeModifier - - // GenericDecl - - RefPtr<SyntaxNode> GenericDecl::Accept(SyntaxVisitor * visitor) - { - return visitor->VisitGenericDecl(this); - } - - // GenericTypeParamDecl - - RefPtr<SyntaxNode> GenericTypeParamDecl::Accept(SyntaxVisitor * /*visitor*/) { - //throw "unimplemented"; - return this; - } - - // GenericTypeConstraintDecl - - RefPtr<SyntaxNode> GenericTypeConstraintDecl::Accept(SyntaxVisitor * visitor) - { - return this; - } - - // GenericValueParamDecl - - RefPtr<SyntaxNode> GenericValueParamDecl::Accept(SyntaxVisitor * /*visitor*/) { - //throw "unimplemented"; - return this; - } - // GenericParamIntVal bool GenericParamIntVal::EqualsVal(Val* val) @@ -1069,38 +756,6 @@ namespace Slang return this; } - // ExtensionDecl - - RefPtr<SyntaxNode> ExtensionDecl::Accept(SyntaxVisitor * visitor) - { - visitor->VisitExtensionDecl(this); - return this; - } - - // ConstructorDecl - - RefPtr<SyntaxNode> ConstructorDecl::Accept(SyntaxVisitor * visitor) - { - visitor->VisitConstructorDecl(this); - return this; - } - - // SubscriptDecl - - RefPtr<SyntaxNode> SubscriptDecl::Accept(SyntaxVisitor * visitor) - { - visitor->visitSubscriptDecl(this); - return this; - } - - // AccessorDecl - - RefPtr<SyntaxNode> AccessorDecl::Accept(SyntaxVisitor * visitor) - { - visitor->visitAccessorDecl(this); - return this; - } - // Substitutions RefPtr<Substitutions> Substitutions::SubstituteImpl(Substitutions* subst, int* ioDiff) @@ -1297,73 +952,6 @@ namespace Slang return (int) value; } - // SwitchStmt - - RefPtr<SyntaxNode> SwitchStmt::Accept(SyntaxVisitor * visitor) - { - return visitor->VisitSwitchStmt(this); - } - - RefPtr<SyntaxNode> CaseStmt::Accept(SyntaxVisitor * visitor) - { - return visitor->VisitCaseStmt(this); - } - - RefPtr<SyntaxNode> DefaultStmt::Accept(SyntaxVisitor * visitor) - { - return visitor->VisitDefaultStmt(this); - } - - // InterfaceDecl - - RefPtr<SyntaxNode> InterfaceDecl::Accept(SyntaxVisitor * visitor) - { - visitor->visitInterfaceDecl(this); - return this; - } - - // InheritanceDecl - - RefPtr<SyntaxNode> InheritanceDecl::Accept(SyntaxVisitor * visitor) - { - visitor->visitInheritanceDecl(this); - return this; - } - - // SharedTypeExpr - - RefPtr<SyntaxNode> SharedTypeExpr::Accept(SyntaxVisitor * visitor) - { - return visitor->VisitSharedTypeExpr(this); - } - - // OperatorExpressionSyntaxNode - -#if 0 - void OperatorExpressionSyntaxNode::SetOperator(RefPtr<Scope> scope, Slang::Operator op) - { - this->Operator = op; - auto opExpr = new VarExpressionSyntaxNode(); - opExpr->Variable = GetOperatorFunctionName(Operator); - opExpr->scope = scope; - opExpr->Position = this->Position; - this->FunctionExpr = opExpr; - } -#endif - - RefPtr<SyntaxNode> OperatorExpressionSyntaxNode::Accept(SyntaxVisitor * visitor) - { - return visitor->VisitOperatorExpression(this); - } - - // DeclGroup - - RefPtr<SyntaxNode> DeclGroup::Accept(SyntaxVisitor * visitor) - { - visitor->VisitDeclGroup(this); - return this; - } - // void RegisterBuiltinDecl( @@ -1429,34 +1017,6 @@ namespace Slang // - RefPtr<SyntaxNode> UnparsedStmt::Accept(SyntaxVisitor * visitor) - { - return this; - } - - // - - RefPtr<SyntaxNode> InitializerListExpr::Accept(SyntaxVisitor * visitor) - { - return visitor->visitInitializerListExpr(this); - } - - // - - RefPtr<SyntaxNode> ModifierDecl::Accept(SyntaxVisitor * visitor) - { - return this; - } - - // - - RefPtr<SyntaxNode> EmptyDecl::Accept(SyntaxVisitor * visitor) - { - return this; - } - - // - SyntaxNodeBase* createInstanceOfSyntaxClassByName( String const& name) { diff --git a/source/slang/syntax.h b/source/slang/syntax.h index b4d7e146e..47427b130 100644 --- a/source/slang/syntax.h +++ b/source/slang/syntax.h @@ -11,55 +11,22 @@ namespace Slang { + class Substitutions; class SyntaxVisitor; class FunctionSyntaxNode; - class SyntaxNodeBase : public RefObject - { - public: - CodePosition Position; - }; - - + struct IExprVisitor; + struct IDeclVisitor; + struct IModifierVisitor; + struct IStmtVisitor; + struct ITypeVisitor; + struct IValVisitor; - - // - // Other modifiers may have more elaborate data, and so - // are represented as heap-allocated objects, in a linked - // list. - // - class Modifier : public SyntaxNodeBase - { - public: - // Next modifier in linked list of modifiers on same piece of syntax - RefPtr<Modifier> next; - - // The token that was used to name this modifier. - Token nameToken; - }; - -#define SIMPLE_MODIFIER(NAME) \ - class NAME##Modifier : public Modifier {} - - SIMPLE_MODIFIER(Uniform); - SIMPLE_MODIFIER(In); - SIMPLE_MODIFIER(Out); - SIMPLE_MODIFIER(Const); - SIMPLE_MODIFIER(Instance); - SIMPLE_MODIFIER(Builtin); - SIMPLE_MODIFIER(Inline); - SIMPLE_MODIFIER(Public); - SIMPLE_MODIFIER(Require); - SIMPLE_MODIFIER(Param); - SIMPLE_MODIFIER(Extern); - SIMPLE_MODIFIER(Input); - SIMPLE_MODIFIER(Transparent); - SIMPLE_MODIFIER(FromStdLib); - SIMPLE_MODIFIER(Prefix); - SIMPLE_MODIFIER(Postfix); - SIMPLE_MODIFIER(Exported); - -#undef SIMPLE_MODIFIER + // Forward-declare all syntax classes +#define SYNTAX_CLASS(NAME, BASE, ...) class NAME; +#include "object-meta-begin.h" +#include "syntax-defs.h" +#include "object-meta-end.h" enum class IntrinsicOp { @@ -70,174 +37,6 @@ namespace Slang IntrinsicOp findIntrinsicOp(char const* name); - // Base class for modifiers that mark something as "intrinsic" - // and thus lacking a direct implementation in the language. - class IntrinsicModifierBase : public Modifier - { - }; - - // A modifier that marks something as one of a small set of - // truly intrinsic operations that the compiler knows about - // directly. - class IntrinsicOpModifier : public IntrinsicModifierBase - { - public: - // token that names the intrinsic op - Token opToken; - - // The opcode for the intrinsic operation - IntrinsicOp op = IntrinsicOp::Unknown; - }; - - // A modifier that marks something as an intrinsic function, - // for some subset of targets. - class TargetIntrinsicModifier : public IntrinsicModifierBase - { - public: - // Token that names the target that the operation - // is an intrisic for. - Token targetToken; - - // A custom definition for the operation - Token definitionToken; - }; - - - - class InOutModifier : public OutModifier {}; - - // This is a special sentinel modifier that gets added - // to the list when we have multiple variable declarations - // all sharing the same modifiers: - // - // static uniform int a : FOO, *b : register(x0); - // - // In this case both `a` and `b` share the syntax - // for part of their modifier list, but then have - // their own modifiers as well: - // - // a: SemanticModifier("FOO") --> SharedModifiers --> StaticModifier --> UniformModifier - // / - // b: RegisterModifier("x0") / - // - class SharedModifiers : public Modifier {}; - - // A GLSL `layout` modifier - // - // We use a distinct modifier for each key that - // appears within the `layout(...)` construct, - // and each key might have an optional value token. - // - // TODO: We probably want a notion of "modifier groups" - // so that we can recover good source location info - // for modifiers that were part of the same vs. - // different constructs. - class GLSLLayoutModifier : public Modifier - { - public: - // THe token used to introduce the modifier is stored - // as the `nameToken` field. - - // TODO: may want to accept a full expression here - Token valToken; - }; - - // We divide GLSL `layout` modifiers into those we have parsed - // (in the sense of having some notion of their semantics), and - // those we have not. - class GLSLParsedLayoutModifier : public GLSLLayoutModifier {}; - class GLSLUnparsedLayoutModifier : public GLSLLayoutModifier {}; - - // Specific cases for known GLSL `layout` modifiers that we need to work with - class GLSLConstantIDLayoutModifier : public GLSLParsedLayoutModifier {}; - class GLSLBindingLayoutModifier : public GLSLParsedLayoutModifier {}; - class GLSLSetLayoutModifier : public GLSLParsedLayoutModifier {}; - class GLSLLocationLayoutModifier : public GLSLParsedLayoutModifier {}; - - // A catch-all for single-keyword modifiers - class SimpleModifier : public Modifier {}; - - // Some GLSL-specific modifiers - class GLSLBufferModifier : public SimpleModifier {}; - class GLSLWriteOnlyModifier : public SimpleModifier {}; - class GLSLReadOnlyModifier : public SimpleModifier {}; - class GLSLPatchModifier : public SimpleModifier {}; - - // Indicates that this is a variable declaration that corresponds to - // a parameter block declaration in the source program. - class ImplicitParameterBlockVariableModifier : public Modifier {}; - - // Indicates that this is a type that corresponds to the element - // type of a parameter block declaration in the source program. - class ImplicitParameterBlockElementTypeModifier : public Modifier {}; - - // An HLSL semantic - class HLSLSemantic : public Modifier - { - public: - Token name; - }; - - - // An HLSL semantic that affects layout - class HLSLLayoutSemantic : public HLSLSemantic - { - public: - Token registerName; - Token componentMask; - }; - - // An HLSL `register` semantic - class HLSLRegisterSemantic : public HLSLLayoutSemantic - { - }; - - // TODO(tfoley): `packoffset` - class HLSLPackOffsetSemantic : public HLSLLayoutSemantic - { - }; - - // An HLSL semantic that just associated a declaration with a semantic name - class HLSLSimpleSemantic : public HLSLSemantic - { - }; - - // GLSL - - // Directives that came in via the preprocessor, but - // that we need to keep around for later steps - class GLSLPreprocessorDirective : public Modifier - { - }; - - // A GLSL `#version` directive - class GLSLVersionDirective : public GLSLPreprocessorDirective - { - public: - // Token giving the version number to use - Token versionNumberToken; - - // Optional token giving the sub-profile to be used - Token glslProfileToken; - }; - - // A GLSL `#extension` directive - class GLSLExtensionDirective : public GLSLPreprocessorDirective - { - public: - // Token giving the version number to use - Token extensionNameToken; - - // Optional token giving the sub-profile to be used - Token dispositionToken; - }; - - class ParameterBlockReflectionName : public Modifier - { - public: - Token nameToken; - }; - // Helper class for iterating over a list of heap-allocated modifiers struct ModifierList { @@ -250,10 +49,12 @@ namespace Slang return current; } - void operator++() + void operator++(); +#if 0 { current = current->next.Ptr(); } +#endif bool operator!=(Iterator other) { @@ -376,213 +177,16 @@ namespace Slang UInt64, Float, Double, -#if 0 - Texture2D = 48, - TextureCube = 49, - Texture2DArray = 50, - Texture2DShadow = 51, - TextureCubeShadow = 52, - Texture2DArrayShadow = 53, - Texture3D = 54, - SamplerState = 4096, SamplerComparisonState = 4097, - Error = 16384, -#endif }; - class Decl; - class StructSyntaxNode; - class BasicExpressionType; - class ArrayExpressionType; - class TypeDefDecl; - class DeclRefType; class NamedExpressionType; - class TypeType; - class GenericDeclRefType; - class VectorExpressionType; - class MatrixExpressionType; - class ArithmeticExpressionType; class GenericDecl; - class Substitutions; - class TextureType; - class SamplerStateType; - - // A compile-time constant value (usually a type) - class Val : public RefObject - { - public: - // construct a new value by applying a set of parameter - // substitutions to this one - RefPtr<Val> Substitute(Substitutions* subst); - - // Lower-level interface for substition. Like the basic - // `Substitute` above, but also takes a by-reference - // integer parameter that should be incremented when - // returning a modified value (this can help the caller - // decide whether they need to do anything). - virtual RefPtr<Val> SubstituteImpl(Substitutions* subst, int* ioDiff); - - virtual bool EqualsVal(Val* val) = 0; - virtual String ToString() = 0; - virtual int GetHashCode() = 0; - bool operator == (const Val & v) - { - return EqualsVal(const_cast<Val*>(&v)); - } - }; - - // A compile-time integer (may not have a specific concrete value) - class IntVal : public Val - { - }; + class ContainerDecl; // Try to extract a simple integer value from an `IntVal`. // This fill assert-fail if the object doesn't represent a literal value. IntegerLiteralValue GetIntVal(RefPtr<IntVal> val); - // Trivial case of a value that is just a constant integer - class ConstantIntVal : public IntVal - { - public: - IntegerLiteralValue value; - - ConstantIntVal(IntegerLiteralValue value) - : value(value) - {} - - virtual bool EqualsVal(Val* val) override; - virtual String ToString() override; - virtual int GetHashCode() override; - }; - - // TODO(tfoley): classes for more general compile-time integers, - // including references to template parameters - - // A type, representing a classifier for some term in the AST. - // - // Types can include "sugar" in that they may refer to a - // `typedef` which gives them a good name when printed as - // part of diagnostic messages. - // - // In order to operation on types, though, we often want - // to look past any sugar, and operate on an underlying - // "canonical" type. The reprsentation caches a pointer to - // a canonical type on every type, so we can easily - // operate on the raw representation when needed. - class ExpressionType : public Val - { - public: - static RefPtr<ExpressionType> Error; - static RefPtr<ExpressionType> initializerListType; - static RefPtr<ExpressionType> Overloaded; - - static Dictionary<int, RefPtr<ExpressionType>> sBuiltinTypes; - static Dictionary<String, Decl*> sMagicDecls; - - // Note: just exists to make sure we can clean up - // canonical types we create along the way - static List<RefPtr<ExpressionType>> sCanonicalTypes; - - - - static ExpressionType* GetBool(); - static ExpressionType* GetFloat(); - static ExpressionType* getDoubleType(); - static ExpressionType* GetInt(); - static ExpressionType* GetUInt(); - static ExpressionType* GetVoid(); - static ExpressionType* getInitializerListType(); - static ExpressionType* GetError(); - - public: - virtual String ToString() = 0; - - bool Equals(ExpressionType * type); - bool Equals(RefPtr<ExpressionType> type); - - bool IsVectorType() { return As<VectorExpressionType>() != nullptr; } - bool IsArray() { return As<ArrayExpressionType>() != nullptr; } - - template<typename T> - T* As() - { - return dynamic_cast<T*>(GetCanonicalType()); - } - - // Convenience/legacy wrappers for `As<>` - ArithmeticExpressionType * AsArithmeticType() { return As<ArithmeticExpressionType>(); } - BasicExpressionType * AsBasicType() { return As<BasicExpressionType>(); } - VectorExpressionType * AsVectorType() { return As<VectorExpressionType>(); } - MatrixExpressionType * AsMatrixType() { return As<MatrixExpressionType>(); } - ArrayExpressionType * AsArrayType() { return As<ArrayExpressionType>(); } - - DeclRefType* AsDeclRefType() { return As<DeclRefType>(); } - - NamedExpressionType* AsNamedType(); - - bool IsTextureOrSampler(); - bool IsTexture() { return As<TextureType>() != nullptr; } - bool IsSampler() { return As<SamplerStateType>() != nullptr; } - bool IsStruct(); - bool IsClass(); - static void Init(); - static void Finalize(); - ExpressionType* GetCanonicalType(); - - virtual RefPtr<Val> SubstituteImpl(Substitutions* subst, int* ioDiff) override; - - virtual bool EqualsVal(Val* val) override; - protected: - virtual bool EqualsImpl(ExpressionType * type) = 0; - - virtual ExpressionType* CreateCanonicalType() = 0; - ExpressionType* canonicalType = nullptr; - }; - - // A substitution represents a binding of certain - // type-level variables to concrete argument values - class Substitutions : public RefObject - { - public: - // The generic declaration that defines the - // parametesr we are binding to arguments - GenericDecl* genericDecl; - - // The actual values of the arguments - List<RefPtr<Val>> args; - - // Any further substitutions, relating to outer generic declarations - RefPtr<Substitutions> outer; - - // Apply a set of substitutions to the bindings in this substitution - RefPtr<Substitutions> SubstituteImpl(Substitutions* subst, int* ioDiff); - - // Check if these are equivalent substitutiosn to another set - bool Equals(Substitutions* subst); - bool operator == (const Substitutions & subst) - { - return Equals(const_cast<Substitutions*>(&subst)); - } - int GetHashCode() const - { - int rs = 0; - for (auto && v : args) - { - rs ^= v->GetHashCode(); - rs *= 16777619; - } - return rs; - } - }; - - class SyntaxNode : public SyntaxNodeBase - { - public: - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) = 0; - }; - - class ContainerDecl; - class SpecializeModifier; - // Represents how much checking has been applied to a declaration. enum class DeclCheckState : uint8_t { @@ -601,60 +205,10 @@ namespace Slang Checked, }; - // A syntax node which can have modifiers appled - class ModifiableSyntaxNode : public SyntaxNode - { - public: - Modifiers modifiers; - - template<typename T> - FilteredModifierList<T> GetModifiersOfType() { return FilteredModifierList<T>(modifiers.first.Ptr()); } - - // Find the first modifier of a given type, or return `nullptr` if none is found. - template<typename T> - T* FindModifier() - { - return *GetModifiersOfType<T>().begin(); - } - - template<typename T> - bool HasModifier() { return FindModifier<T>() != nullptr; } - }; - void addModifier( RefPtr<ModifiableSyntaxNode> syntax, RefPtr<Modifier> modifier); - - // An intermediate type to represent either a single declaration, or a group of declarations - class DeclBase : public ModifiableSyntaxNode - { - public: - }; - - class Decl : public DeclBase - { - public: - ContainerDecl* ParentDecl = nullptr; - - Token Name; - String const& getName() { return Name.Content; } - Token const& getNameToken() { return Name; } - - - DeclCheckState checkState = DeclCheckState::Unchecked; - - // The next declaration defined in the same container with the same name - Decl* nextInContainerWithSameName = nullptr; - - bool IsChecked(DeclCheckState state) { return checkState >= state; } - void SetCheckState(DeclCheckState state) - { - assert(state >= checkState); - checkState = state; - } - }; - struct QualType { RefPtr<ExpressionType> type; @@ -675,16 +229,6 @@ namespace Slang RefPtr<ExpressionType> operator->() { return type; } }; - class ExpressionSyntaxNode : public SyntaxNode - { - public: - QualType Type; - ExpressionSyntaxNode() - {} - }; - - - // A reference to a declaration, which may include // substitutions for generic parameters. @@ -806,390 +350,6 @@ namespace Slang }; - // The type of a reference to an overloaded name - class OverloadGroupType : public ExpressionType - { - public: - virtual String ToString() override; - - protected: - virtual bool EqualsImpl(ExpressionType * type) override; - virtual ExpressionType* CreateCanonicalType() override; - virtual int GetHashCode() override; - }; - - // The type of an initializer-list expression (before it has - // been coerced to some other type) - class InitializerListType : public ExpressionType - { - public: - virtual String ToString() override; - - protected: - virtual bool EqualsImpl(ExpressionType * type) override; - virtual ExpressionType* CreateCanonicalType() override; - virtual int GetHashCode() override; - }; - - // The type of an expression that was erroneous - class ErrorType : public ExpressionType - { - public: - virtual String ToString() override; - - protected: - virtual bool EqualsImpl(ExpressionType * type) override; - virtual ExpressionType* CreateCanonicalType() override; - virtual int GetHashCode() override; - }; - - // A type that takes the form of a reference to some declaration - class DeclRefType : public ExpressionType - { - public: - DeclRef<Decl> declRef; - - virtual String ToString() override; - virtual RefPtr<Val> SubstituteImpl(Substitutions* subst, int* ioDiff) override; - - static DeclRefType* Create(DeclRef<Decl> declRef); - - protected: - DeclRefType() - {} - DeclRefType(DeclRef<Decl> declRef) - : declRef(declRef) - {} - virtual int GetHashCode() override; - virtual bool EqualsImpl(ExpressionType * type) override; - virtual ExpressionType* CreateCanonicalType() override; - }; - - // Base class for types that can be used in arithmetic expressions - class ArithmeticExpressionType : public DeclRefType - { - public: - virtual BasicExpressionType* GetScalarType() = 0; - }; - - class FunctionDeclBase; - - class BasicExpressionType : public ArithmeticExpressionType - { - public: - BaseType BaseType; - - BasicExpressionType() - { - BaseType = Slang::BaseType::Int; - } - BasicExpressionType(Slang::BaseType baseType) - { - BaseType = baseType; - } - virtual Slang::String ToString() override; - protected: - virtual BasicExpressionType* GetScalarType() override; - virtual bool EqualsImpl(ExpressionType * type) override; - virtual ExpressionType* CreateCanonicalType() override; - }; - - - class TextureTypeBase : public DeclRefType - { - public: - // The type that results from fetching an element from this texture - RefPtr<ExpressionType> elementType; - - // Bits representing the kind of texture type we are looking at - // (e.g., `Texture2DMS` vs. `TextureCubeArray`) - typedef uint16_t Flavor; - Flavor flavor; - - enum - { - // Mask for the overall "shape" of the texture - ShapeMask = SLANG_RESOURCE_BASE_SHAPE_MASK, - - // Flag for whether the shape has "array-ness" - ArrayFlag = SLANG_TEXTURE_ARRAY_FLAG, - - // Whether or not the texture stores multiple samples per pixel - MultisampleFlag = SLANG_TEXTURE_MULTISAMPLE_FLAG, - - // Whether or not this is a shadow texture - // - // TODO(tfoley): is this even meaningful/used? - // ShadowFlag = 0x80, - }; - - enum Shape : uint8_t - { - Shape1D = SLANG_TEXTURE_1D, - Shape2D = SLANG_TEXTURE_2D, - Shape3D = SLANG_TEXTURE_3D, - ShapeCube = SLANG_TEXTURE_CUBE, - - Shape1DArray = Shape1D | ArrayFlag, - Shape2DArray = Shape2D | ArrayFlag, - // No Shape3DArray - ShapeCubeArray = ShapeCube | ArrayFlag, - }; - - - Shape GetBaseShape() const { return Shape(flavor & ShapeMask); } - bool isArray() const { return (flavor & ArrayFlag) != 0; } - bool isMultisample() const { return (flavor & MultisampleFlag) != 0; } -// bool isShadow() const { return (flavor & ShadowFlag) != 0; } - - SlangResourceShape getShape() const { return flavor & 0xFF; } - SlangResourceAccess getAccess() const { return (flavor >> 8) & 0xFF; } - - TextureTypeBase( - Flavor flavor, - RefPtr<ExpressionType> elementType) - : elementType(elementType) - , flavor(flavor) - {} - }; - - class TextureType : public TextureTypeBase - { - public: - TextureType( - Flavor flavor, - RefPtr<ExpressionType> elementType) - : TextureTypeBase(flavor, elementType) - {} - }; - - // This is a base type for texture/sampler pairs, - // as they exist in, e.g., GLSL - class TextureSamplerType : public TextureTypeBase - { - public: - TextureSamplerType( - Flavor flavor, - RefPtr<ExpressionType> elementType) - : TextureTypeBase(flavor, elementType) - {} - }; - - // This is a base type for `image*` types, as they exist in GLSL - class GLSLImageType : public TextureTypeBase - { - public: - GLSLImageType( - Flavor flavor, - RefPtr<ExpressionType> elementType) - : TextureTypeBase(flavor, elementType) - {} - }; - - class SamplerStateType : public DeclRefType - { - public: - // What flavor of sampler state is this - enum class Flavor : uint8_t - { - SamplerState, - SamplerComparisonState, - }; - Flavor flavor; - }; - - // Other cases of generic types known to the compiler - class BuiltinGenericType : public DeclRefType - { - public: - RefPtr<ExpressionType> elementType; - }; - - // Types that behave like pointers, in that they can be - // dereferenced (implicitly) to access members defined - // in the element type. - class PointerLikeType : public BuiltinGenericType - {}; - - // Generic types used in existing Slang code - // TODO(tfoley): check that these are actually working right... - class PatchType : public PointerLikeType {}; - class StorageBufferType : public BuiltinGenericType {}; - class UniformBufferType : public PointerLikeType {}; - class PackedBufferType : public BuiltinGenericType {}; - - // HLSL buffer-type resources - - class HLSLBufferType : public BuiltinGenericType {}; - class HLSLRWBufferType : public BuiltinGenericType {}; - class HLSLStructuredBufferType : public BuiltinGenericType {}; - class HLSLRWStructuredBufferType : public BuiltinGenericType {}; - - class UntypedBufferResourceType : public DeclRefType {}; - class HLSLByteAddressBufferType : public UntypedBufferResourceType {}; - class HLSLRWByteAddressBufferType : public UntypedBufferResourceType {}; - - class HLSLAppendStructuredBufferType : public BuiltinGenericType {}; - class HLSLConsumeStructuredBufferType : public BuiltinGenericType {}; - - class HLSLPatchType : public DeclRefType - { - public: - ExpressionType* getElementType(); - IntVal* getElementCount(); - }; - - class HLSLInputPatchType : public HLSLPatchType {}; - class HLSLOutputPatchType : public HLSLPatchType {}; - - // HLSL geometry shader output stream types - - class HLSLStreamOutputType : public BuiltinGenericType {}; - class HLSLPointStreamType : public HLSLStreamOutputType {}; - class HLSLLineStreamType : public HLSLStreamOutputType {}; - class HLSLTriangleStreamType : public HLSLStreamOutputType {}; - - // - class GLSLInputAttachmentType : public DeclRefType {}; - - // Base class for types used when desugaring parameter block - // declarations, includeing HLSL `cbuffer` or GLSL `uniform` blocks. - class ParameterBlockType : public PointerLikeType {}; - - class UniformParameterBlockType : public ParameterBlockType {}; - class VaryingParameterBlockType : public ParameterBlockType {}; - - // Type for HLSL `cbuffer` declarations, and `ConstantBuffer<T>` - // ALso used for GLSL `uniform` blocks. - class ConstantBufferType : public UniformParameterBlockType {}; - - // Type for HLSL `tbuffer` declarations, and `TextureBuffer<T>` - class TextureBufferType : public UniformParameterBlockType {}; - - // Type for GLSL `in` and `out` blocks - class GLSLInputParameterBlockType : public VaryingParameterBlockType {}; - class GLSLOutputParameterBlockType : public VaryingParameterBlockType {}; - - // Type for GLLSL `buffer` blocks - class GLSLShaderStorageBufferType : public UniformParameterBlockType {}; - - class ArrayExpressionType : public ExpressionType - { - public: - RefPtr<ExpressionType> BaseType; - RefPtr<IntVal> ArrayLength; - virtual Slang::String ToString() override; - protected: - virtual bool EqualsImpl(ExpressionType * type) override; - virtual ExpressionType* CreateCanonicalType() override; - virtual int GetHashCode() override; - }; - - // The "type" of an expression that resolves to a type. - // For example, in the expression `float(2)` the sub-expression, - // `float` would have the type `TypeType(float)`. - class TypeType : public ExpressionType - { - public: - TypeType(RefPtr<ExpressionType> type) - : type(type) - {} - - // The type that this is the type of... - RefPtr<ExpressionType> type; - - - virtual String ToString() override; - - protected: - virtual bool EqualsImpl(ExpressionType * type) override; - virtual ExpressionType* CreateCanonicalType() override; - virtual int GetHashCode() override; - }; - - class GenericDecl; - - // A vector type, e.g., `vector<T,N>` - class VectorExpressionType : public ArithmeticExpressionType - { - public: -#if 0 - VectorExpressionType( - RefPtr<ExpressionType> elementType, - RefPtr<IntVal> elementCount) - : elementType(elementType) - , elementCount(elementCount) - {} -#endif - - // The type of vector elements. - // As an invariant, this should be a basic type or an alias. - RefPtr<ExpressionType> elementType; - - // The number of elements - RefPtr<IntVal> elementCount; - - virtual String ToString() override; - - protected: - virtual BasicExpressionType* GetScalarType() override; - }; - - // A matrix type, e.g., `matrix<T,R,C>` - class MatrixExpressionType : public ArithmeticExpressionType - { - public: - // TODO: consider adding these back for convenience, - // with a way to initialize them on-demand from the - // real storage (which is in the `DeclRefType` -#if 0 - // The type of vector elements. - // As an invariant, this should be a basic type or an alias. - RefPtr<ExpressionType> elementType; - - // The type of the matrix rows - RefPtr<VectorExpressionType> rowType; - - // The number of rows and columns - RefPtr<IntVal> rowCount; - RefPtr<IntVal> colCount; -#endif - ExpressionType* getElementType(); - IntVal* getRowCount(); - IntVal* getColumnCount(); - - - virtual String ToString() override; - - protected: - virtual BasicExpressionType* GetScalarType() override; - }; - - inline BaseType GetVectorBaseType(VectorExpressionType* vecType) { - return vecType->elementType->AsBasicType()->BaseType; - } - - inline int GetVectorSize(VectorExpressionType* vecType) - { - auto constantVal = vecType->elementCount.As<ConstantIntVal>(); - if (constantVal) - return (int) constantVal->value; - // TODO: what to do in this case? - return 0; - } - - class ContainerDecl; - - - // A group of declarations that should be treated as a unit - class DeclGroup : public DeclBase - { - public: - List<RefPtr<Decl>> decls; - - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - template<typename T> struct FilteredMemberList { @@ -1284,32 +444,6 @@ namespace Slang Decl* decl; }; - // A "container" decl is a parent to other declarations - class ContainerDecl : public Decl - { - public: - List<RefPtr<Decl>> Members; - - template<typename T> - FilteredMemberList<T> getMembersOfType() - { - return FilteredMemberList<T>(Members); - } - - - // Dictionary for looking up members by name. - // This is built on demand before performing lookup. - Dictionary<String, Decl*> memberDictionary; - - // Whether the `memberDictionary` is valid. - // Should be set to `false` if any members get added/remoed. - bool memberDictionaryIsValid = false; - - // A list of transparent members, to be used in lookup - // Note: this is only valid if `memberDictionaryIsValid` is true - List<TransparentMemberInfo> transparentMembers; - }; - template<typename T> struct FilteredMemberRefList { @@ -1387,17 +521,6 @@ namespace Slang } }; - inline FilteredMemberRefList<Decl> getMembers(DeclRef<ContainerDecl> const& declRef) - { - return FilteredMemberRefList<Decl>(declRef.getDecl()->Members, declRef.substitutions); - } - - template<typename T> - inline FilteredMemberRefList<T> getMembersOfType(DeclRef<ContainerDecl> const& declRef) - { - return FilteredMemberRefList<T>(declRef.getDecl()->Members, declRef.substitutions); - } - // // Type Expressions // @@ -1422,12 +545,18 @@ namespace Slang RefPtr<ExpressionSyntaxNode> exp; RefPtr<ExpressionType> type; - bool Equals(ExpressionType* other) { + bool Equals(ExpressionType* other); +#if 0 + { return type->Equals(other); } - bool Equals(RefPtr<ExpressionType> other) { +#endif + bool Equals(RefPtr<ExpressionType> other); +#if 0 + { return type->Equals(other.Ptr()); } +#endif ExpressionType* Ptr() { return type.Ptr(); } operator ExpressionType*() { @@ -1439,320 +568,6 @@ namespace Slang }; - // - // Declarations - // - - // Base class for all variable-like declarations - class VarDeclBase : public Decl - { - public: - // Type of the variable - TypeExp Type; - - ExpressionType* getType() { return Type.type.Ptr(); } - - // Initializer expression (optional) - RefPtr<ExpressionSyntaxNode> Expr; - }; - - inline RefPtr<ExpressionType> GetType(DeclRef<VarDeclBase> const& declRef) - { - return declRef.Substitute(declRef.getDecl()->Type.Ptr()); - } - - inline RefPtr<ExpressionSyntaxNode> getInitExpr(DeclRef<VarDeclBase> const& declRef) - { - return declRef.Substitute(declRef.getDecl()->Expr); - } - - // A field of a `struct` type - class StructField : public VarDeclBase - { - public: - StructField() - {} - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - // An `AggTypeDeclBase` captures the shared functionality - // between true aggregate type declarations and extension - // declarations: - // - // - Both can container members (they are `ContainerDecl`s) - // - Both can have declared bases - // - Both expose a `this` variable in their body - // - class AggTypeDeclBase : public ContainerDecl - { - public: - }; - - // An extension to apply to an existing type - class ExtensionDecl : public AggTypeDeclBase - { - public: - TypeExp targetType; - - // next extension attached to the same nominal type - ExtensionDecl* nextCandidateExtension = nullptr; - - - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - - inline RefPtr<ExpressionType> GetTargetType(DeclRef<ExtensionDecl> const& declRef) - { - return declRef.Substitute(declRef.getDecl()->targetType.Ptr()); - } - - // Declaration of a type that represents some sort of aggregate - class AggTypeDecl : public AggTypeDeclBase - { - public: - - // extensions that might apply to this declaration - ExtensionDecl* candidateExtensions = nullptr; - FilteredMemberList<StructField> GetFields() - { - return getMembersOfType<StructField>(); - } - StructField* FindField(String name) - { - for (auto field : GetFields()) - { - if (field->Name.Content == name) - return field.Ptr(); - } - return nullptr; - } - int FindFieldIndex(String name) - { - int index = 0; - for (auto field : GetFields()) - { - if (field->Name.Content == name) - return index; - index++; - } - return -1; - } - }; - - inline ExtensionDecl* GetCandidateExtensions(DeclRef<AggTypeDecl> const& declRef) - { - return declRef.getDecl()->candidateExtensions; - } - - class StructSyntaxNode : public AggTypeDecl - { - public: - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - inline FilteredMemberRefList<StructField> GetFields(DeclRef<StructSyntaxNode> const& declRef) - { - return getMembersOfType<StructField>(declRef); - } - - class ClassSyntaxNode : public AggTypeDecl - { - public: - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - // An interface which other types can conform to - class InterfaceDecl : public AggTypeDecl - { - public: - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - // A kind of pseudo-member that represents an explicit - // or implicit inheritance relationship. - // - class InheritanceDecl : public Decl - { - public: - // The type expression as written - TypeExp base; - - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - inline RefPtr<ExpressionType> getBaseType(DeclRef<InheritanceDecl> const& declRef) - { - return declRef.Substitute(declRef.getDecl()->base.type); - } - - // TODO: may eventually need sub-classes for explicit/direct vs. implicit/indirect inheritance - - - // A declaration that represents a simple (non-aggregate) type - class SimpleTypeDecl : public Decl - { - }; - - // A `typedef` declaration - class TypeDefDecl : public SimpleTypeDecl - { - public: - TypeExp Type; - - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - inline RefPtr<ExpressionType> GetType(DeclRef<TypeDefDecl> const& declRef) - { - return declRef.Substitute(declRef.getDecl()->Type.Ptr()); - } - - // A type alias of some kind (e.g., via `typedef`) - class NamedExpressionType : public ExpressionType - { - public: - NamedExpressionType(DeclRef<TypeDefDecl> declRef) - : declRef(declRef) - {} - - DeclRef<TypeDefDecl> declRef; - - virtual String ToString() override; - - protected: - virtual bool EqualsImpl(ExpressionType * type) override; - virtual ExpressionType* CreateCanonicalType() override; - virtual int GetHashCode() override; - }; - - - class StatementSyntaxNode : public ModifiableSyntaxNode - { - public: - }; - - // A scope for local declarations (e.g., as part of a statement) - class ScopeDecl : public ContainerDecl - { - public: - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - class ScopeStmt : public StatementSyntaxNode - { - public: - RefPtr<ScopeDecl> scopeDecl; - }; - - class BlockStatementSyntaxNode : public ScopeStmt - { - public: - List<RefPtr<StatementSyntaxNode>> Statements; - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - class UnparsedStmt : public StatementSyntaxNode - { - public: - // The tokens that were contained between `{` and `}` - List<Token> tokens; - - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - class ParameterSyntaxNode : public VarDeclBase - { - public: - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - // Base class for things that have parameter lists and can thus be applied to arguments ("called") - class CallableDecl : public ContainerDecl - { - public: - FilteredMemberList<ParameterSyntaxNode> GetParameters() - { - return getMembersOfType<ParameterSyntaxNode>(); - } - TypeExp ReturnType; - }; - - inline RefPtr<ExpressionType> GetResultType(DeclRef<CallableDecl> const& declRef) - { - return declRef.Substitute(declRef.getDecl()->ReturnType.type.Ptr()); - } - - inline FilteredMemberRefList<ParameterSyntaxNode> GetParameters(DeclRef<CallableDecl> const& declRef) - { - return getMembersOfType<ParameterSyntaxNode>(declRef); - } - - // Base class for callable things that may also have a body that is evaluated to produce their result - class FunctionDeclBase : public CallableDecl - { - public: - RefPtr<StatementSyntaxNode> Body; - }; - - // Function types are currently used for references to symbols that name - // either ordinary functions, or "component functions." - // We do not directly store a representation of the type, and instead - // use a reference to the symbol to stand in for its logical type - class FuncType : public ExpressionType - { - public: - DeclRef<CallableDecl> declRef; - - virtual String ToString() override; - protected: - virtual bool EqualsImpl(ExpressionType * type) override; - virtual ExpressionType* CreateCanonicalType() override; - virtual int GetHashCode() override; - }; - - // A constructor/initializer to create instances of a type - class ConstructorDecl : public FunctionDeclBase - { - public: - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - // A subscript operation used to index instances of a type - class SubscriptDecl : public CallableDecl - { - public: - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - // An "accessor" for a subscript or property - class AccessorDecl : public FunctionDeclBase - { - public: - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - class GetterDecl : public AccessorDecl - { - }; - - class SetterDecl : public AccessorDecl - { - }; - - // - - class FunctionSyntaxNode : public FunctionDeclBase - { - public: - String InternalName; - bool IsInline() { return HasModifier<InlineModifier>(); } - bool IsExtern() { return HasModifier<ExternModifier>(); } - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - FunctionSyntaxNode() - { - } - }; struct Scope : public RefObject { @@ -1770,26 +585,6 @@ namespace Slang ContainerDecl* containerDecl; }; - // Base class for expressions that will reference declarations - class DeclRefExpr : public ExpressionSyntaxNode - { - public: - // The scope in which to perform lookup - RefPtr<Scope> scope; - - // The declaration of the symbol being referenced - DeclRef<Decl> declRef; - - // The name of the symbol being referenced - String name; - }; - - class VarExpressionSyntaxNode : public DeclRefExpr - { - public: - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - // Masks to be applied when lookup up declarations enum class LookupMask : uint8_t { @@ -1871,7 +666,7 @@ namespace Slang bool isOverloaded() const { return items.Count() > 1; } }; - class SemanticsVisitor; + struct SemanticsVisitor; struct LookupRequest { @@ -1883,43 +678,6 @@ namespace Slang LookupMask mask = LookupMask::All; }; - // An expression that references an overloaded set of declarations - // having the same name. - class OverloadedExpr : public ExpressionSyntaxNode - { - public: - // Optional: the base expression is this overloaded result - // arose from a member-reference expression. - RefPtr<ExpressionSyntaxNode> base; - - // The lookup result that was ambiguous - LookupResult lookupResult2; - - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - class ConstantExpressionSyntaxNode : public ExpressionSyntaxNode - { - public: - Token token; - - enum class ConstantType - { - Int, - Bool, - Float, - String, - }; - ConstantType ConstType; - union - { - IntegerLiteralValue integerValue; - FloatingPointLiteralValue floatingPointValue; - }; - String stringValue; - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - enum class Operator { Neg, Not, BitNot, PreInc, PreDec, PostInc, PostDec, @@ -1935,476 +693,35 @@ namespace Slang Assign = 200, AddAssign, SubAssign, MulAssign, DivAssign, ModAssign, LshAssign, RshAssign, OrAssign, AndAssign, XorAssign, }; - String GetOperatorFunctionName(Operator op); - String OperatorToString(Operator op); - - // An initializer list, e.g. `{ 1, 2, 3 }` - class InitializerListExpr : public ExpressionSyntaxNode - { - public: - List<RefPtr<ExpressionSyntaxNode>> args; - - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - // A base expression being applied to arguments: covers - // both ordinary `()` function calls and `<>` generic application - class AppExprBase : public ExpressionSyntaxNode - { - public: - RefPtr<ExpressionSyntaxNode> FunctionExpr; - List<RefPtr<ExpressionSyntaxNode>> Arguments; - }; - - - class InvokeExpressionSyntaxNode : public AppExprBase - { - public: - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - class OperatorExpressionSyntaxNode : public InvokeExpressionSyntaxNode - { - public: -// Operator Operator; -// void SetOperator(RefPtr<Scope> scope, Slang::Operator op); - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - class InfixExpr : public OperatorExpressionSyntaxNode {}; - class PrefixExpr : public OperatorExpressionSyntaxNode {}; - class PostfixExpr : public OperatorExpressionSyntaxNode {}; - - class IndexExpressionSyntaxNode : public ExpressionSyntaxNode - { - public: - RefPtr<ExpressionSyntaxNode> BaseExpression; - RefPtr<ExpressionSyntaxNode> IndexExpression; - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - class MemberExpressionSyntaxNode : public DeclRefExpr - { - public: - RefPtr<ExpressionSyntaxNode> BaseExpression; - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - class SwizzleExpr : public ExpressionSyntaxNode - { - public: - RefPtr<ExpressionSyntaxNode> base; - int elementCount; - int elementIndices[4]; - - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - // A dereference of a pointer or pointer-like type - class DerefExpr : public ExpressionSyntaxNode - { - public: - RefPtr<ExpressionSyntaxNode> base; - - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - class TypeCastExpressionSyntaxNode : public ExpressionSyntaxNode - { - public: - TypeExp TargetType; - RefPtr<ExpressionSyntaxNode> Expression; - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - class SelectExpressionSyntaxNode : public OperatorExpressionSyntaxNode - { - public: - }; - - - class EmptyStatementSyntaxNode : public StatementSyntaxNode - { - public: - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - class DiscardStatementSyntaxNode : public StatementSyntaxNode - { - public: - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - struct Variable : public VarDeclBase - { - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - class VarDeclrStatementSyntaxNode : public StatementSyntaxNode - { - public: - RefPtr<DeclBase> decl; - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - // A "module" of code (essentiately, a single translation unit) - // that provides a scope for some number of declarations. - class ProgramSyntaxNode : public ContainerDecl - { - public: - // Access members of specific types - FilteredMemberList<FunctionSyntaxNode> GetFunctions() - { - return getMembersOfType<FunctionSyntaxNode>(); - } - - FilteredMemberList<ClassSyntaxNode> GetClasses() - { - return getMembersOfType<ClassSyntaxNode>(); - } - FilteredMemberList<StructSyntaxNode> GetStructs() - { - return getMembersOfType<StructSyntaxNode>(); - } - FilteredMemberList<TypeDefDecl> GetTypeDefs() - { - return getMembersOfType<TypeDefDecl>(); - } - - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - class ImportDecl : public Decl - { - public: - // The name of the module we are trying to import - Token nameToken; - - // The scope that we want to import into - RefPtr<Scope> scope; - - // The module that actually got imported - RefPtr<ProgramSyntaxNode> importedModuleDecl; - - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - - class IfStatementSyntaxNode : public StatementSyntaxNode - { - public: - RefPtr<ExpressionSyntaxNode> Predicate; - RefPtr<StatementSyntaxNode> PositiveStatement; - RefPtr<StatementSyntaxNode> NegativeStatement; - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - // A statement that can be escaped with a `break` - class BreakableStmt : public ScopeStmt - {}; - - class SwitchStmt : public BreakableStmt - { - public: - RefPtr<ExpressionSyntaxNode> condition; - RefPtr<StatementSyntaxNode> body; - - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - // A statement that is expected to appear lexically nested inside - // some other construct, and thus needs to keep track of the - // outer statement that it is associated with... - class ChildStmt : public StatementSyntaxNode - { - public: - StatementSyntaxNode* parentStmt = nullptr; - }; - - // a `case` or `default` statement inside a `switch` - // - // Note(tfoley): A correct AST for a C-like language would treat - // these as a labelled statement, and so they would contain a - // sub-statement. I'm leaving that out for now for simplicity. - class CaseStmtBase : public ChildStmt - { - public: - }; - - // a `case` statement inside a `switch` - class CaseStmt : public CaseStmtBase - { - public: - RefPtr<ExpressionSyntaxNode> expr; - - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - // a `default` statement inside a `switch` - class DefaultStmt : public CaseStmtBase - { - public: - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - // A statement that represents a loop, and can thus be escaped with a `continue` - class LoopStmt : public BreakableStmt - {}; - - class ForStatementSyntaxNode : public LoopStmt - { - public: - RefPtr<StatementSyntaxNode> InitialStatement; - RefPtr<ExpressionSyntaxNode> SideEffectExpression, PredicateExpression; - RefPtr<StatementSyntaxNode> Statement; - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - class WhileStatementSyntaxNode : public LoopStmt - { - public: - RefPtr<ExpressionSyntaxNode> Predicate; - RefPtr<StatementSyntaxNode> Statement; - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - class DoWhileStatementSyntaxNode : public LoopStmt - { - public: - RefPtr<StatementSyntaxNode> Statement; - RefPtr<ExpressionSyntaxNode> Predicate; - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - // The case of child statements that do control flow relative - // to their parent statement. - class JumpStmt : public ChildStmt - { - public: - StatementSyntaxNode* parentStmt = nullptr; - }; - - class BreakStatementSyntaxNode : public JumpStmt - { - public: - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - class ContinueStatementSyntaxNode : public JumpStmt - { - public: - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - class ReturnStatementSyntaxNode : public StatementSyntaxNode - { - public: - RefPtr<ExpressionSyntaxNode> Expression; - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - class ExpressionStatementSyntaxNode : public StatementSyntaxNode - { - public: - RefPtr<ExpressionSyntaxNode> Expression; - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - // Note(tfoley): Moved this further down in the file because it depends on - // `ExpressionSyntaxNode` and a forward reference just isn't good enough - // for `RefPtr`. - // - class GenericAppExpr : public AppExprBase - { - public: - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - // An expression representing re-use of the syntax for a type in more - // than once conceptually-distinct declaration - class SharedTypeExpr : public ExpressionSyntaxNode - { - public: - // The underlying type expression that we want to share - TypeExp base; - - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - - // A modifier that indicates a built-in base type (e.g., `float`) - class BuiltinTypeModifier : public Modifier - { - public: - BaseType tag; - }; - - // A modifier that indicates a built-in type that isn't a base type (e.g., `vector`) - // - // TODO(tfoley): This deserves a better name than "magic" - class MagicTypeModifier : public Modifier - { - public: - String name; - uint32_t tag; - }; - - // Modifiers that affect the storage layout for matrices - class MatrixLayoutModifier : public Modifier {}; - - // Modifiers that specify row- and column-major layout, respectively - class RowMajorLayoutModifier : public MatrixLayoutModifier {}; - class ColumnMajorLayoutModifier : public MatrixLayoutModifier {}; - - // The HLSL flavor of those modifiers - class HLSLRowMajorLayoutModifier : public RowMajorLayoutModifier {}; - class HLSLColumnMajorLayoutModifier : public ColumnMajorLayoutModifier {}; - - // The GLSL flavor of those modifiers - // - // Note(tfoley): The GLSL versions of these modifiers are "backwards" - // in the sense that when a GLSL programmer requests row-major layout, - // we actually interpret that as requesting column-major. This makes - // sense because we interpret matrix conventions backwards from how - // GLSL specifies them. - class GLSLRowMajorLayoutModifier : public ColumnMajorLayoutModifier {}; - class GLSLColumnMajorLayoutModifier : public RowMajorLayoutModifier {}; - - // More HLSL Keyword - - // HLSL `nointerpolation` modifier - class HLSLNoInterpolationModifier : public Modifier {}; - - // HLSL `linear` modifier - class HLSLLinearModifier : public Modifier {}; - - // HLSL `sample` modifier - class HLSLSampleModifier : public Modifier {}; - - // HLSL `centroid` modifier - class HLSLCentroidModifier : public Modifier {}; - - // HLSL `precise` modifier - class HLSLPreciseModifier : public Modifier {}; - - // HLSL `shared` modifier (which is used by the effect system, - // and shouldn't be confused with `groupshared`) - class HLSLEffectSharedModifier : public Modifier {}; - - // HLSL `groupshared` modifier - class HLSLGroupSharedModifier : public Modifier {}; - - // HLSL `static` modifier (probably doesn't need to be - // treated as HLSL-specific) - class HLSLStaticModifier : public Modifier {}; - - // HLSL `uniform` modifier (distinct meaning from GLSL - // use of the keyword) - class HLSLUniformModifier : public Modifier {}; - - // HLSL `volatile` modifier (ignored) - class HLSLVolatileModifier : public Modifier {}; - - // An HLSL `[name(arg0, ...)]` style attribute. - class HLSLAttribute : public Modifier - { - public: - Token nameToken; - List<RefPtr<ExpressionSyntaxNode>> args; - }; - - // An HLSL `[name(...)]` attribute that hasn't undergone - // any semantic analysis. - // After analysis, this might be transformed into a more specific case. - class HLSLUncheckedAttribute : public HLSLAttribute - { - public: - }; - - // An HLSL `[numthreads(x,y,z)]` attribute - class HLSLNumThreadsAttribute : public HLSLAttribute - { - public: - // The number of threads to use along each axis - int32_t x; - int32_t y; - int32_t z; - }; - - // HLSL modifiers for geometry shader input topology - class HLSLGeometryShaderInputPrimitiveTypeModifier : public Modifier {}; - class HLSLPointModifier : public HLSLGeometryShaderInputPrimitiveTypeModifier {}; - class HLSLLineModifier : public HLSLGeometryShaderInputPrimitiveTypeModifier {}; - class HLSLTriangleModifier : public HLSLGeometryShaderInputPrimitiveTypeModifier {}; - class HLSLLineAdjModifier : public HLSLGeometryShaderInputPrimitiveTypeModifier {}; - class HLSLTriangleAdjModifier : public HLSLGeometryShaderInputPrimitiveTypeModifier {}; - - // - - // A generic declaration, parameterized on types/values - class GenericDecl : public ContainerDecl - { - public: - // The decl that is genericized... - RefPtr<Decl> inner; - - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - inline Decl* GetInner(DeclRef<GenericDecl> const& declRef) - { - // TODO: Should really return a `DeclRef<Decl>` for the inner - // declaration, and not just a raw pointer - return declRef.getDecl()->inner.Ptr(); - } - - // The "type" of an expression that names a generic declaration. - class GenericDeclRefType : public ExpressionType - { - public: - GenericDeclRefType(DeclRef<GenericDecl> declRef) - : declRef(declRef) - {} - - DeclRef<GenericDecl> declRef; - DeclRef<GenericDecl> const& GetDeclRef() const { return declRef; } - - virtual String ToString() override; - - protected: - virtual bool EqualsImpl(ExpressionType * type) override; - virtual int GetHashCode() override; - virtual ExpressionType* CreateCanonicalType() override; - }; - - - - class GenericTypeParamDecl : public SimpleTypeDecl - { - public: - // The bound for the type parameter represents a trait that any - // type used as this parameter must conform to -// TypeExp bound; - - // The "initializer" for the parameter represents a default value - TypeExp initType; - - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - // A constraint placed as part of a generic declaration - class GenericTypeConstraintDecl : public Decl - { - public: - // A type constraint like `T : U` is constraining `T` to be "below" `U` - // on a lattice of types. This may not be a subtyping relationship - // per se, but it makes sense to use that terminology here, so we - // think of these fields as the sub-type and sup-ertype, respectively. - TypeExp sub; - TypeExp sup; - - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; + // Generate class definition for all syntax classes +#define SYNTAX_FIELD(TYPE, NAME) TYPE NAME; +#define FIELD(TYPE, NAME) TYPE NAME; +#define FIELD_INIT(TYPE, NAME, INIT) TYPE NAME = INIT; +#define RAW(...) __VA_ARGS__ +#define END_SYNTAX_CLASS() }; +#define SYNTAX_CLASS(NAME, BASE, ...) class NAME : public BASE {public: +#include "object-meta-begin.h" + +#include "syntax-base-defs.h" +#undef SYNTAX_CLASS + +#undef ABSTRACT_SYNTAX_CLASS +#define ABSTRACT_SYNTAX_CLASS(NAME, BASE, ...) \ + class NAME : public BASE { \ + public: /* ... */ +#define SYNTAX_CLASS(NAME, BASE, ...) \ + class NAME : public BASE { \ + virtual void accept(NAME::Visitor* visitor, void* extra) override; \ + public: /* ... */ +#include "expr-defs.h" +#include "decl-defs.h" +#include "modifier-defs.h" +#include "stmt-defs.h" +#include "type-defs.h" +#include "val-defs.h" + +#include "object-meta-end.h" inline RefPtr<ExpressionType> GetSub(DeclRef<GenericTypeConstraintDecl> const& declRef) { @@ -2416,56 +733,8 @@ namespace Slang return declRef.Substitute(declRef.getDecl()->sup.Ptr()); } - class GenericValueParamDecl : public VarDeclBase - { - public: - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - // The logical "value" of a rererence to a generic value parameter - class GenericParamIntVal : public IntVal - { - public: - DeclRef<VarDeclBase> declRef; - - GenericParamIntVal(DeclRef<VarDeclBase> declRef) - : declRef(declRef) - {} - - virtual bool EqualsVal(Val* val) override; - virtual String ToString() override; - virtual int GetHashCode() override; - virtual RefPtr<Val> SubstituteImpl(Substitutions* subst, int* ioDiff) override; - }; - - // Declaration of a user-defined modifier - class ModifierDecl : public Decl - { - public: - // The name of the C++ class to instantiate - // (this is a reference to a class in the compiler source code, - // and not the user's source code) - Token classNameToken; - - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - - // An empty declaration (which might still have modifiers attached). - // - // An empty declaration is uncommon in HLSL, but - // in GLSL it is often used at the global scope - // to declare metadata that logically belongs - // to the entry point, e.g.: - // - // layout(local_size_x = 16) in; - // - class EmptyDecl : public Decl - { - public: - virtual RefPtr<SyntaxNode> Accept(SyntaxVisitor * visitor) override; - }; - // +#if 0 class SyntaxVisitor : public RefObject { @@ -2742,6 +1011,8 @@ namespace Slang virtual RefPtr<ExpressionSyntaxNode> visitInitializerListExpr(InitializerListExpr* expr) = 0; }; +#endif + // Note(tfoley): These logically belong to `ExpressionType`, // but order-of-declaration stuff makes that tricky // @@ -2762,6 +1033,88 @@ namespace Slang SyntaxNodeBase* createInstanceOfSyntaxClassByName( String const& name); + // + + inline BaseType GetVectorBaseType(VectorExpressionType* vecType) { + return vecType->elementType->AsBasicType()->BaseType; + } + + inline int GetVectorSize(VectorExpressionType* vecType) + { + auto constantVal = vecType->elementCount.As<ConstantIntVal>(); + if (constantVal) + return (int) constantVal->value; + // TODO: what to do in this case? + return 0; + } + + // + // Declarations + // + + inline FilteredMemberRefList<Decl> getMembers(DeclRef<ContainerDecl> const& declRef) + { + return FilteredMemberRefList<Decl>(declRef.getDecl()->Members, declRef.substitutions); + } + + template<typename T> + inline FilteredMemberRefList<T> getMembersOfType(DeclRef<ContainerDecl> const& declRef) + { + return FilteredMemberRefList<T>(declRef.getDecl()->Members, declRef.substitutions); + } + + inline RefPtr<ExpressionType> GetType(DeclRef<VarDeclBase> const& declRef) + { + return declRef.Substitute(declRef.getDecl()->Type.Ptr()); + } + + inline RefPtr<ExpressionSyntaxNode> getInitExpr(DeclRef<VarDeclBase> const& declRef) + { + return declRef.Substitute(declRef.getDecl()->Expr); + } + + inline RefPtr<ExpressionType> GetTargetType(DeclRef<ExtensionDecl> const& declRef) + { + return declRef.Substitute(declRef.getDecl()->targetType.Ptr()); + } + + inline ExtensionDecl* GetCandidateExtensions(DeclRef<AggTypeDecl> const& declRef) + { + return declRef.getDecl()->candidateExtensions; + } + + inline FilteredMemberRefList<StructField> GetFields(DeclRef<StructSyntaxNode> const& declRef) + { + return getMembersOfType<StructField>(declRef); + } + + inline RefPtr<ExpressionType> getBaseType(DeclRef<InheritanceDecl> const& declRef) + { + return declRef.Substitute(declRef.getDecl()->base.type); + } + + inline RefPtr<ExpressionType> GetType(DeclRef<TypeDefDecl> const& declRef) + { + return declRef.Substitute(declRef.getDecl()->Type.Ptr()); + } + + inline RefPtr<ExpressionType> GetResultType(DeclRef<CallableDecl> const& declRef) + { + return declRef.Substitute(declRef.getDecl()->ReturnType.type.Ptr()); + } + + inline FilteredMemberRefList<ParameterSyntaxNode> GetParameters(DeclRef<CallableDecl> const& declRef) + { + return getMembersOfType<ParameterSyntaxNode>(declRef); + } + + inline Decl* GetInner(DeclRef<GenericDecl> const& declRef) + { + // TODO: Should really return a `DeclRef<Decl>` for the inner + // declaration, and not just a raw pointer + return declRef.getDecl()->inner.Ptr(); + } + } // namespace Slang #endif
\ No newline at end of file diff --git a/source/slang/type-defs.h b/source/slang/type-defs.h new file mode 100644 index 000000000..a01b49277 --- /dev/null +++ b/source/slang/type-defs.h @@ -0,0 +1,393 @@ +// type-defs.h + +// Syntax class definitions for types. + +// The type of a reference to an overloaded name +SYNTAX_CLASS(OverloadGroupType, ExpressionType) +RAW( +public: + virtual String ToString() override; + +protected: + virtual bool EqualsImpl(ExpressionType * type) override; + virtual ExpressionType* CreateCanonicalType() override; + virtual int GetHashCode() override; +) +END_SYNTAX_CLASS() + +// The type of an initializer-list expression (before it has +// been coerced to some other type) +SYNTAX_CLASS(InitializerListType, ExpressionType) +RAW( + virtual String ToString() override; + +protected: + virtual bool EqualsImpl(ExpressionType * type) override; + virtual ExpressionType* CreateCanonicalType() override; + virtual int GetHashCode() override; +) +END_SYNTAX_CLASS() + +// The type of an expression that was erroneous +SYNTAX_CLASS(ErrorType, ExpressionType) +RAW( +public: + virtual String ToString() override; + +protected: + virtual bool EqualsImpl(ExpressionType * type) override; + virtual ExpressionType* CreateCanonicalType() override; + virtual int GetHashCode() override; +) +END_SYNTAX_CLASS() + +// A type that takes the form of a reference to some declaration +SYNTAX_CLASS(DeclRefType, ExpressionType) + DECL_FIELD(DeclRef<Decl>, declRef) + +RAW( + virtual String ToString() override; + virtual RefPtr<Val> SubstituteImpl(Substitutions* subst, int* ioDiff) override; + + static DeclRefType* Create(DeclRef<Decl> declRef); + +protected: + DeclRefType() + {} + DeclRefType(DeclRef<Decl> declRef) + : declRef(declRef) + {} + virtual int GetHashCode() override; + virtual bool EqualsImpl(ExpressionType * type) override; + virtual ExpressionType* CreateCanonicalType() override; +) +END_SYNTAX_CLASS() + +// Base class for types that can be used in arithmetic expressions +SYNTAX_CLASS(ArithmeticExpressionType, DeclRefType) +RAW( + virtual BasicExpressionType* GetScalarType() = 0; +) +END_SYNTAX_CLASS() + +SYNTAX_CLASS(BasicExpressionType, ArithmeticExpressionType) + + FIELD(BaseType, BaseType) + +RAW( + BasicExpressionType() + { + BaseType = Slang::BaseType::Int; + } + BasicExpressionType(Slang::BaseType baseType) + { + BaseType = baseType; + } + virtual Slang::String ToString() override; +protected: + virtual BasicExpressionType* GetScalarType() override; + virtual bool EqualsImpl(ExpressionType * type) override; + virtual ExpressionType* CreateCanonicalType() override; +) +END_SYNTAX_CLASS() + + +SYNTAX_CLASS(TextureTypeBase, DeclRefType) + // The type that results from fetching an element from this texture + SYNTAX_FIELD(RefPtr<ExpressionType>, elementType) + + // Bits representing the kind of texture type we are looking at + // (e.g., `Texture2DMS` vs. `TextureCubeArray`) + RAW(typedef uint16_t Flavor;) + FIELD(Flavor, flavor) + +RAW( + enum + { + // Mask for the overall "shape" of the texture + ShapeMask = SLANG_RESOURCE_BASE_SHAPE_MASK, + + // Flag for whether the shape has "array-ness" + ArrayFlag = SLANG_TEXTURE_ARRAY_FLAG, + + // Whether or not the texture stores multiple samples per pixel + MultisampleFlag = SLANG_TEXTURE_MULTISAMPLE_FLAG, + + // Whether or not this is a shadow texture + // + // TODO(tfoley): is this even meaningful/used? + // ShadowFlag = 0x80, + }; + + enum Shape : uint8_t + { + Shape1D = SLANG_TEXTURE_1D, + Shape2D = SLANG_TEXTURE_2D, + Shape3D = SLANG_TEXTURE_3D, + ShapeCube = SLANG_TEXTURE_CUBE, + + Shape1DArray = Shape1D | ArrayFlag, + Shape2DArray = Shape2D | ArrayFlag, + // No Shape3DArray + ShapeCubeArray = ShapeCube | ArrayFlag, + }; + + + Shape GetBaseShape() const { return Shape(flavor & ShapeMask); } + bool isArray() const { return (flavor & ArrayFlag) != 0; } + bool isMultisample() const { return (flavor & MultisampleFlag) != 0; } +// bool isShadow() const { return (flavor & ShadowFlag) != 0; } + + SlangResourceShape getShape() const { return flavor & 0xFF; } + SlangResourceAccess getAccess() const { return (flavor >> 8) & 0xFF; } + + TextureTypeBase( + Flavor flavor, + RefPtr<ExpressionType> elementType) + : elementType(elementType) + , flavor(flavor) + {} +) +END_SYNTAX_CLASS() + +SYNTAX_CLASS(TextureType, TextureTypeBase) +RAW( + TextureType( + Flavor flavor, + RefPtr<ExpressionType> elementType) + : TextureTypeBase(flavor, elementType) + {} +) +END_SYNTAX_CLASS() + +// This is a base type for texture/sampler pairs, +// as they exist in, e.g., GLSL +SYNTAX_CLASS(TextureSamplerType, TextureTypeBase) +RAW( + TextureSamplerType( + Flavor flavor, + RefPtr<ExpressionType> elementType) + : TextureTypeBase(flavor, elementType) + {} +) +END_SYNTAX_CLASS() + +// This is a base type for `image*` types, as they exist in GLSL +SYNTAX_CLASS(GLSLImageType, TextureTypeBase) +RAW( + GLSLImageType( + Flavor flavor, + RefPtr<ExpressionType> elementType) + : TextureTypeBase(flavor, elementType) + {} +) +END_SYNTAX_CLASS() + +SYNTAX_CLASS(SamplerStateType, DeclRefType) + + // What flavor of sampler state is this + RAW(enum class Flavor : uint8_t + { + SamplerState, + SamplerComparisonState, + };) + FIELD(Flavor, flavor) +END_SYNTAX_CLASS() + +// Other cases of generic types known to the compiler +SYNTAX_CLASS(BuiltinGenericType, DeclRefType) + SYNTAX_FIELD(RefPtr<ExpressionType>, elementType) +END_SYNTAX_CLASS() + +// Types that behave like pointers, in that they can be +// dereferenced (implicitly) to access members defined +// in the element type. +SIMPLE_SYNTAX_CLASS(PointerLikeType, BuiltinGenericType) + +// Generic types used in existing Slang code +// TODO(tfoley): check that these are actually working right... +SIMPLE_SYNTAX_CLASS(PatchType, PointerLikeType) +SIMPLE_SYNTAX_CLASS(StorageBufferType, BuiltinGenericType) +SIMPLE_SYNTAX_CLASS(UniformBufferType, PointerLikeType) +SIMPLE_SYNTAX_CLASS(PackedBufferType, BuiltinGenericType) + +// HLSL buffer-type resources + +SIMPLE_SYNTAX_CLASS(HLSLBufferType, BuiltinGenericType) +SIMPLE_SYNTAX_CLASS(HLSLRWBufferType, BuiltinGenericType) +SIMPLE_SYNTAX_CLASS(HLSLStructuredBufferType, BuiltinGenericType) +SIMPLE_SYNTAX_CLASS(HLSLRWStructuredBufferType, BuiltinGenericType) + +SIMPLE_SYNTAX_CLASS(UntypedBufferResourceType, DeclRefType) +SIMPLE_SYNTAX_CLASS(HLSLByteAddressBufferType, UntypedBufferResourceType) +SIMPLE_SYNTAX_CLASS(HLSLRWByteAddressBufferType, UntypedBufferResourceType) + +SIMPLE_SYNTAX_CLASS(HLSLAppendStructuredBufferType, BuiltinGenericType) +SIMPLE_SYNTAX_CLASS(HLSLConsumeStructuredBufferType, BuiltinGenericType) + +SYNTAX_CLASS(HLSLPatchType, DeclRefType) +RAW( + ExpressionType* getElementType(); + IntVal* getElementCount(); +) +END_SYNTAX_CLASS() + +SIMPLE_SYNTAX_CLASS(HLSLInputPatchType, HLSLPatchType) +SIMPLE_SYNTAX_CLASS(HLSLOutputPatchType, HLSLPatchType) + +// HLSL geometry shader output stream types + +SIMPLE_SYNTAX_CLASS(HLSLStreamOutputType, BuiltinGenericType) +SIMPLE_SYNTAX_CLASS(HLSLPointStreamType, HLSLStreamOutputType) +SIMPLE_SYNTAX_CLASS(HLSLLineStreamType, HLSLStreamOutputType) +SIMPLE_SYNTAX_CLASS(HLSLTriangleStreamType, HLSLStreamOutputType) + +// +SIMPLE_SYNTAX_CLASS(GLSLInputAttachmentType, DeclRefType) + +// Base class for types used when desugaring parameter block +// declarations, includeing HLSL `cbuffer` or GLSL `uniform` blocks. +SIMPLE_SYNTAX_CLASS(ParameterBlockType, PointerLikeType) + +SIMPLE_SYNTAX_CLASS(UniformParameterBlockType, ParameterBlockType) +SIMPLE_SYNTAX_CLASS(VaryingParameterBlockType, ParameterBlockType) + +// Type for HLSL `cbuffer` declarations, and `ConstantBuffer<T>` +// ALso used for GLSL `uniform` blocks. +SIMPLE_SYNTAX_CLASS(ConstantBufferType, UniformParameterBlockType) + +// Type for HLSL `tbuffer` declarations, and `TextureBuffer<T>` +SIMPLE_SYNTAX_CLASS(TextureBufferType, UniformParameterBlockType) + +// Type for GLSL `in` and `out` blocks +SIMPLE_SYNTAX_CLASS(GLSLInputParameterBlockType, VaryingParameterBlockType) +SIMPLE_SYNTAX_CLASS(GLSLOutputParameterBlockType, VaryingParameterBlockType) + +// Type for GLLSL `buffer` blocks +SIMPLE_SYNTAX_CLASS(GLSLShaderStorageBufferType, UniformParameterBlockType) + +SYNTAX_CLASS(ArrayExpressionType, ExpressionType) + SYNTAX_FIELD(RefPtr<ExpressionType>, BaseType) + SYNTAX_FIELD(RefPtr<IntVal>, ArrayLength) + +RAW( + virtual Slang::String ToString() override; +protected: + virtual bool EqualsImpl(ExpressionType * type) override; + virtual ExpressionType* CreateCanonicalType() override; + virtual int GetHashCode() override; +) +END_SYNTAX_CLASS() + +// The "type" of an expression that resolves to a type. +// For example, in the expression `float(2)` the sub-expression, +// `float` would have the type `TypeType(float)`. +SYNTAX_CLASS(TypeType, ExpressionType) + // The type that this is the type of... + SYNTAX_FIELD(RefPtr<ExpressionType>, type) + +RAW( +public: + TypeType(RefPtr<ExpressionType> type) + : type(type) + {} + + virtual String ToString() override; + +protected: + virtual bool EqualsImpl(ExpressionType * type) override; + virtual ExpressionType* CreateCanonicalType() override; + virtual int GetHashCode() override; +) +END_SYNTAX_CLASS() + +// A vector type, e.g., `vector<T,N>` +SYNTAX_CLASS(VectorExpressionType, ArithmeticExpressionType) + + // The type of vector elements. + // As an invariant, this should be a basic type or an alias. + SYNTAX_FIELD(RefPtr<ExpressionType>, elementType) + + // The number of elements + SYNTAX_FIELD(RefPtr<IntVal>, elementCount) + +RAW( + virtual String ToString() override; + +protected: + virtual BasicExpressionType* GetScalarType() override; +) +END_SYNTAX_CLASS() + +// A matrix type, e.g., `matrix<T,R,C>` +SYNTAX_CLASS(MatrixExpressionType, ArithmeticExpressionType) +RAW( + ExpressionType* getElementType(); + IntVal* getRowCount(); + IntVal* getColumnCount(); + + + virtual String ToString() override; + +protected: + virtual BasicExpressionType* GetScalarType() override; +) +END_SYNTAX_CLASS() + +// A type alias of some kind (e.g., via `typedef`) +SYNTAX_CLASS(NamedExpressionType, ExpressionType) + DECL_FIELD(DeclRef<TypeDefDecl>, declRef) + +RAW( + NamedExpressionType(DeclRef<TypeDefDecl> declRef) + : declRef(declRef) + {} + + + virtual String ToString() override; + +protected: + virtual bool EqualsImpl(ExpressionType * type) override; + virtual ExpressionType* CreateCanonicalType() override; + virtual int GetHashCode() override; +) +END_SYNTAX_CLASS() + +// Function types are currently used for references to symbols that name +// either ordinary functions, or "component functions." +// We do not directly store a representation of the type, and instead +// use a reference to the symbol to stand in for its logical type +SYNTAX_CLASS(FuncType, ExpressionType) + DECL_FIELD(DeclRef<CallableDecl>, declRef) + +RAW( + virtual String ToString() override; +protected: + virtual bool EqualsImpl(ExpressionType * type) override; + virtual ExpressionType* CreateCanonicalType() override; + virtual int GetHashCode() override; +) +END_SYNTAX_CLASS() + +// The "type" of an expression that names a generic declaration. +SYNTAX_CLASS(GenericDeclRefType, ExpressionType) + + DECL_FIELD(DeclRef<GenericDecl>, declRef) + + RAW( + GenericDeclRefType(DeclRef<GenericDecl> declRef) + : declRef(declRef) + {} + + + DeclRef<GenericDecl> const& GetDeclRef() const { return declRef; } + + virtual String ToString() override; + +protected: + virtual bool EqualsImpl(ExpressionType * type) override; + virtual int GetHashCode() override; + virtual ExpressionType* CreateCanonicalType() override; +) +END_SYNTAX_CLASS() + diff --git a/source/slang/val-defs.h b/source/slang/val-defs.h new file mode 100644 index 000000000..316981842 --- /dev/null +++ b/source/slang/val-defs.h @@ -0,0 +1,37 @@ +// val-defs.h + +// Syntax class definitions for compile-time values. + +// A compile-time integer (may not have a specific concrete value) +SIMPLE_SYNTAX_CLASS(IntVal, Val) + +// Trivial case of a value that is just a constant integer +SYNTAX_CLASS(ConstantIntVal, IntVal) + FIELD(IntegerLiteralValue, value) + + RAW( + ConstantIntVal(IntegerLiteralValue value) + : value(value) + {} + + virtual bool EqualsVal(Val* val) override; + virtual String ToString() override; + virtual int GetHashCode() override; + ) +END_SYNTAX_CLASS() + +// The logical "value" of a rererence to a generic value parameter +SYNTAX_CLASS(GenericParamIntVal, IntVal) + DECL_FIELD(DeclRef<VarDeclBase>, declRef) + + RAW( + GenericParamIntVal(DeclRef<VarDeclBase> declRef) + : declRef(declRef) + {} + + virtual bool EqualsVal(Val* val) override; + virtual String ToString() override; + virtual int GetHashCode() override; + virtual RefPtr<Val> SubstituteImpl(Substitutions* subst, int* ioDiff) override; +) +END_SYNTAX_CLASS() diff --git a/source/slang/visitor.h b/source/slang/visitor.h new file mode 100644 index 000000000..391769eca --- /dev/null +++ b/source/slang/visitor.h @@ -0,0 +1,346 @@ +// visitor.h +#ifndef SLANG_VISITOR_H_INCLUDED +#define SLANG_VISITOR_H_INCLUDED + +// This file defines the basic "Visitor" pattern for doing dispatch +// over the various categories of syntax node. + +#include "syntax.h" + +namespace Slang { + +// +// Type Visitors +// + +struct ITypeVisitor +{ +#define ABSTRACT_SYNTAX_CLASS(NAME,BASE) /* empty */ +#define SYNTAX_CLASS(NAME, BASE) \ + virtual void dispatch_##NAME(NAME* obj, void* extra) = 0; + +#include "object-meta-begin.h" +#include "type-defs.h" +#include "object-meta-end.h" +}; + +template<typename Derived, typename Result = void> +struct TypeVisitor : ITypeVisitor +{ + Result dispatch(ExpressionType* type) + { + Result result; + type->accept(this, &result); + return result; + } + +#define ABSTRACT_SYNTAX_CLASS(NAME,BASE) /* empty */ +#define SYNTAX_CLASS(NAME, BASE) \ + virtual void dispatch_##NAME(NAME* obj, void* extra) override \ + { *(Result*)extra = ((Derived*) this)->visit(obj); } + +#include "object-meta-begin.h" +#include "type-defs.h" +#include "object-meta-end.h" + +}; + +template<typename Derived> +struct TypeVisitor<Derived,void> : ITypeVisitor +{ + void dispatch(ExpressionType* type) + { + type->accept(this, 0); + } + +#define ABSTRACT_SYNTAX_CLASS(NAME,BASE) /* empty */ +#define SYNTAX_CLASS(NAME, BASE) \ + virtual void dispatch_##NAME(NAME* obj, void*) override \ + { ((Derived*) this)->visit(obj); } + +#include "object-meta-begin.h" +#include "type-defs.h" +#include "object-meta-end.h" + +}; + +// +// Expression Visitors +// + +struct IExprVisitor +{ +#define ABSTRACT_SYNTAX_CLASS(NAME,BASE) /* empty */ +#define SYNTAX_CLASS(NAME, BASE) \ + virtual void dispatch_##NAME(NAME* obj, void* extra) = 0; + +#include "object-meta-begin.h" +#include "expr-defs.h" +#include "object-meta-end.h" +}; + +template<typename Derived, typename Result = void> +struct ExprVisitor : IExprVisitor +{ + Result dispatch(ExpressionSyntaxNode* expr) + { + Result result; + expr->accept(this, &result); + return result; + } + +#define ABSTRACT_SYNTAX_CLASS(NAME,BASE) /* empty */ +#define SYNTAX_CLASS(NAME, BASE) \ + virtual void dispatch_##NAME(NAME* obj, void* extra) override \ + { *(Result*)extra = ((Derived*) this)->visit(obj); } + +#include "object-meta-begin.h" +#include "expr-defs.h" +#include "object-meta-end.h" + +}; + +template<typename Derived> +struct ExprVisitor<Derived,void> : IExprVisitor +{ + void dispatch(ExpressionSyntaxNode* expr) + { + expr->accept(this, 0); + } + +#define ABSTRACT_SYNTAX_CLASS(NAME,BASE) /* empty */ +#define SYNTAX_CLASS(NAME, BASE) \ + virtual void dispatch_##NAME(NAME* obj, void*) override \ + { ((Derived*) this)->visit(obj); } + +#include "object-meta-begin.h" +#include "expr-defs.h" +#include "object-meta-end.h" + +}; + +// +// Statement Visitors +// + +struct IStmtVisitor +{ +#define ABSTRACT_SYNTAX_CLASS(NAME,BASE) /* empty */ +#define SYNTAX_CLASS(NAME, BASE) \ + virtual void dispatch_##NAME(NAME* obj, void* extra) = 0; + +#include "object-meta-begin.h" +#include "stmt-defs.h" +#include "object-meta-end.h" +}; + +template<typename Derived, typename Result = void> +struct StmtVisitor : IStmtVisitor +{ + Result dispatch(StatementSyntaxNode* stmt) + { + Result result; + stmt->accept(this, &result); + return result; + } + +#define ABSTRACT_SYNTAX_CLASS(NAME,BASE) /* empty */ +#define SYNTAX_CLASS(NAME, BASE) \ + virtual void dispatch_##NAME(NAME* obj, void* extra) override \ + { *(Result*)extra = ((Derived*) this)->visit(obj); } + +#include "object-meta-begin.h" +#include "stmt-defs.h" +#include "object-meta-end.h" + +}; + +template<typename Derived> +struct StmtVisitor<Derived,void> : IStmtVisitor +{ + void dispatch(StatementSyntaxNode* stmt) + { + stmt->accept(this, 0); + } + +#define ABSTRACT_SYNTAX_CLASS(NAME,BASE) /* empty */ +#define SYNTAX_CLASS(NAME, BASE) \ + virtual void dispatch_##NAME(NAME* obj, void*) override \ + { ((Derived*) this)->visit(obj); } + +#include "object-meta-begin.h" +#include "stmt-defs.h" +#include "object-meta-end.h" + +}; + +// +// Declaration Visitors +// + +struct IDeclVisitor +{ +#define ABSTRACT_SYNTAX_CLASS(NAME,BASE) /* empty */ +#define SYNTAX_CLASS(NAME, BASE) \ + virtual void dispatch_##NAME(NAME* obj, void* extra) = 0; + +#include "object-meta-begin.h" +#include "decl-defs.h" +#include "object-meta-end.h" +}; + +template<typename Derived, typename Result = void> +struct DeclVisitor : IDeclVisitor +{ + Result dispatch(DeclBase* decl) + { + Result result; + decl->accept(this, &result); + return result; + } + +#define ABSTRACT_SYNTAX_CLASS(NAME,BASE) /* empty */ +#define SYNTAX_CLASS(NAME, BASE) \ + virtual void dispatch_##NAME(NAME* obj, void* extra) override \ + { *(Result*)extra = ((Derived*) this)->visit(obj); } + +#include "object-meta-begin.h" +#include "decl-defs.h" +#include "object-meta-end.h" + +}; + +template<typename Derived> +struct DeclVisitor<Derived,void> : IDeclVisitor +{ + void dispatch(DeclBase* decl) + { + decl->accept(this, 0); + } + +#define ABSTRACT_SYNTAX_CLASS(NAME,BASE) /* empty */ +#define SYNTAX_CLASS(NAME, BASE) \ + virtual void dispatch_##NAME(NAME* obj, void*) override \ + { ((Derived*) this)->visit(obj); } + +#include "object-meta-begin.h" +#include "decl-defs.h" +#include "object-meta-end.h" + +}; + +// +// Modifier Visitors +// + +struct IModifierVisitor +{ +#define ABSTRACT_SYNTAX_CLASS(NAME,BASE) /* empty */ +#define SYNTAX_CLASS(NAME, BASE) \ + virtual void dispatch_##NAME(NAME* obj, void* extra) = 0; + +#include "object-meta-begin.h" +#include "modifier-defs.h" +#include "object-meta-end.h" +}; + +template<typename Derived, typename Result = void> +struct ModifierVisitor : IModifierVisitor +{ + Result dispatch(Modifier* modifier) + { + Result result; + modifier->accept(this, &result); + return result; + } + +#define ABSTRACT_SYNTAX_CLASS(NAME,BASE) /* empty */ +#define SYNTAX_CLASS(NAME, BASE) \ + virtual void dispatch_##NAME(NAME* obj, void* extra) override \ + { *(Result*)extra = ((Derived*) this)->visit(obj); } + +#include "object-meta-begin.h" +#include "modifier-defs.h" +#include "object-meta-end.h" + +}; + +template<typename Derived> +struct ModifierVisitor<Derived, void> : IModifierVisitor +{ + void dispatch(Modifier* modifier) + { + modifier->accept(this, 0); + } + +#define ABSTRACT_SYNTAX_CLASS(NAME,BASE) /* empty */ +#define SYNTAX_CLASS(NAME, BASE) \ + virtual void dispatch_##NAME(NAME* obj, void*) override \ + { ((Derived*) this)->visit(obj); } + +#include "object-meta-begin.h" +#include "modifier-defs.h" +#include "object-meta-end.h" + +}; + +// +// Val Visitors +// + +struct IValVisitor : ITypeVisitor +{ +#define ABSTRACT_SYNTAX_CLASS(NAME,BASE) /* empty */ +#define SYNTAX_CLASS(NAME, BASE) \ + virtual void dispatch_##NAME(NAME* obj, void* extra) = 0; + +#include "object-meta-begin.h" +#include "val-defs.h" +#include "object-meta-end.h" +}; + +template<typename Derived, typename Result = void> +struct ValVisitor : IValVisitor +{ + Result dispatch(Val* val) + { + Result result; + val->accept(this, &result); + return result; + } + +#define ABSTRACT_SYNTAX_CLASS(NAME,BASE) /* empty */ +#define SYNTAX_CLASS(NAME, BASE) \ + virtual void dispatch_##NAME(NAME* obj, void* extra) override \ + { *(Result*)extra = ((Derived*) this)->visit(obj); } + +#include "object-meta-begin.h" +#include "val-defs.h" +#include "type-defs.h" +#include "object-meta-end.h" + +}; + +template<typename Derived> +struct ValVisitor<Derived, void> : IValVisitor +{ + void dispatch(Val* val) + { + val->accept(this, 0); + } + +#define ABSTRACT_SYNTAX_CLASS(NAME,BASE) /* empty */ +#define SYNTAX_CLASS(NAME, BASE) \ + virtual void dispatch_##NAME(NAME* obj, void*) override \ + { ((Derived*) this)->visit(obj); } + +#include "object-meta-begin.h" +#include "val-defs.h" +#include "type-defs.h" +#include "object-meta-end.h" + +}; + +} + +#endif
\ No newline at end of file diff --git a/tests/diagnostics/while-predicate-type.slang.expected b/tests/diagnostics/while-predicate-type.slang.expected index d921c588e..c65cb6ef8 100644 --- a/tests/diagnostics/while-predicate-type.slang.expected +++ b/tests/diagnostics/while-predicate-type.slang.expected @@ -1,6 +1,6 @@ result code = -1 standard error = { -tests/diagnostics/while-predicate-type.slang(9): error 30010: 'while': expression must evaluate to int. +tests/diagnostics/while-predicate-type.slang(9): error 30019: expected an expression of type 'bool', got 'S' } standard output = { } |
