Example #1
0
// buildBinaryOperatorExpression builds the CodeDOM for a binary operator.
func (db *domBuilder) buildBinaryOperatorExpression(node compilergraph.GraphNode, modifier exprModifier) codedom.Expression {
	scope, _ := db.scopegraph.GetScope(node)
	operator, _ := scope.CalledOperator(db.scopegraph.TypeGraph())

	if operator.IsNative() {
		return db.buildNativeBinaryExpression(node, operatorMap[node.Kind()])
	}

	leftExpr := db.getExpression(node, parser.NodeBinaryExpressionLeftExpr)
	rightExpr := db.getExpression(node, parser.NodeBinaryExpressionRightExpr)

	leftScope, _ := db.scopegraph.GetScope(node.GetNode(parser.NodeBinaryExpressionLeftExpr))
	parentType := leftScope.ResolvedTypeRef(db.scopegraph.TypeGraph())

	optimized, wasOptimized := db.buildOptimizedBinaryOperatorExpression(node, parentType, leftExpr, rightExpr)
	if wasOptimized {
		return optimized
	}

	callExpr := codedom.MemberCall(codedom.StaticMemberReference(operator, parentType, node), operator, []codedom.Expression{leftExpr, rightExpr}, node)
	if modifier != nil {
		return modifier(callExpr)
	}

	return callExpr
}
Example #2
0
// AsImplementable returns the given node as an SRGImplementable (if applicable).
func (g *SRG) AsImplementable(node compilergraph.GraphNode) (SRGImplementable, bool) {
	switch node.Kind() {
	case parser.NodeTypeConstructor:
		fallthrough

	case parser.NodeTypeFunction:
		fallthrough

	case parser.NodeTypeProperty:
		fallthrough

	case parser.NodeTypeOperator:
		fallthrough

	case parser.NodeTypeField:
		fallthrough

	case parser.NodeTypeVariable:
		fallthrough

	case parser.NodeTypePropertyBlock:
		return SRGImplementable{node, g}, true

	default:
		return SRGImplementable{}, false
	}
}
Example #3
0
// buildUnaryOperatorExpression builds the CodeDOM for a unary operator.
func (db *domBuilder) buildUnaryOperatorExpression(node compilergraph.GraphNode, modifier exprModifier) codedom.Expression {
	scope, _ := db.scopegraph.GetScope(node)
	operator, _ := scope.CalledOperator(db.scopegraph.TypeGraph())

	if operator.IsNative() {
		return db.buildNativeUnaryExpression(node, operatorMap[node.Kind()])
	}

	childScope, _ := db.scopegraph.GetScope(node.GetNode(parser.NodeUnaryExpressionChildExpr))
	parentType := childScope.ResolvedTypeRef(db.scopegraph.TypeGraph())

	childExpr := db.getExpression(node, parser.NodeUnaryExpressionChildExpr)
	callExpr := codedom.MemberCall(codedom.StaticMemberReference(operator, parentType, node), operator, []codedom.Expression{childExpr}, node)
	if modifier != nil {
		return modifier(callExpr)
	}

	return callExpr
}
Example #4
0
// buildNamedAccess builds the CodeDOM for a member access expression.
func (db *domBuilder) buildNamedAccess(node compilergraph.GraphNode, name string, childExprNode *compilergraph.GraphNode) codedom.Expression {
	scope, _ := db.scopegraph.GetScope(node)
	namedReference, hasNamedReference := db.scopegraph.GetReferencedName(scope)

	// Reference to an unknown name or a nullable member access must be a dynamic access.
	if !hasNamedReference || node.Kind() == parser.NodeNullableMemberAccessExpression {
		return codedom.DynamicAccess(db.buildExpression(*childExprNode), name, node)
	}

	// Reference to a local name is a var or parameter.
	if namedReference.IsLocal() {
		return codedom.LocalReference(namedReference.Name(), node)
	}

	// Check for a reference to a type.
	if typeRef, isType := namedReference.Type(); isType {
		return codedom.StaticTypeReference(typeRef, node)
	}

	// Check for a reference to a member.
	if memberRef, isMember := namedReference.Member(); isMember {
		// If the member is under a child expression, build as an access expression.
		if childExprNode != nil {
			childExpr := db.buildExpression(*childExprNode)

			_, underFuncCall := node.TryGetIncomingNode(parser.NodeFunctionCallExpressionChildExpr)
			isAliasedFunctionReference := scope.ResolvedTypeRef(db.scopegraph.TypeGraph()).HasReferredType(db.scopegraph.TypeGraph().FunctionType())

			if isAliasedFunctionReference && !underFuncCall {
				return codedom.DynamicAccess(childExpr, memberRef.Name(), node)
			} else {
				return codedom.MemberReference(childExpr, memberRef, node)
			}
		} else {
			// This is a direct access of a static member. Generate an access under the module.
			return codedom.StaticMemberReference(memberRef, db.scopegraph.TypeGraph().AnyTypeReference(), node)
		}
	}

	panic("Unknown kind of named access")
	return nil
}
Example #5
0
// buildStatements builds the CodeDOM for the given SRG node and returns it as start and end statements.
func (db *domBuilder) buildStatements(node compilergraph.GraphNode) (codedom.Statement, codedom.Statement) {
	switch node.Kind() {
	case parser.NodeTypeStatementBlock:
		return db.buildStatementBlock(node)

	case parser.NodeTypeReturnStatement:
		stm := db.buildReturnStatement(node)
		return stm, stm

	case parser.NodeTypeRejectStatement:
		stm := db.buildRejectStatement(node)
		return stm, stm

	case parser.NodeTypeYieldStatement:
		stm := db.buildYieldStatement(node)
		return stm, stm

	case parser.NodeTypeConditionalStatement:
		return db.buildConditionalStatement(node)

	case parser.NodeTypeLoopStatement:
		return db.buildLoopStatement(node)

	case parser.NodeTypeExpressionStatement:
		stm := db.buildExpressionStatement(node)
		return stm, stm

	case parser.NodeTypeContinueStatement:
		stm := db.buildContinueStatement(node)
		return stm, stm

	case parser.NodeTypeBreakStatement:
		stm := db.buildBreakStatement(node)
		return stm, stm

	case parser.NodeTypeAssignStatement:
		stm := db.buildAssignStatement(node)
		return stm, stm

	case parser.NodeTypeVariableStatement:
		stm := db.buildVarStatement(node)
		return stm, stm

	case parser.NodeTypeWithStatement:
		stm := db.buildWithStatement(node)
		return stm, stm

	case parser.NodeTypeSwitchStatement:
		return db.buildSwitchStatement(node)

	case parser.NodeTypeMatchStatement:
		return db.buildMatchStatement(node)

	case parser.NodeTypeArrowStatement:
		return db.buildArrowStatement(node)

	case parser.NodeTypeResolveStatement:
		return db.buildResolveStatement(node)

	default:
		panic(fmt.Sprintf("Unknown SRG statement node: %s", node.Kind()))
		return nil, nil
	}
}
Example #6
0
// buildExpression builds the CodeDOM for the given SRG node and returns it as an expression. Will
// panic if the returned DOM type is not an expression.
func (db *domBuilder) buildExpression(node compilergraph.GraphNode) codedom.Expression {
	switch node.Kind() {

	// Access Expressions.
	case parser.NodeMemberAccessExpression:
		fallthrough

	case parser.NodeNullableMemberAccessExpression:
		fallthrough

	case parser.NodeDynamicMemberAccessExpression:
		return db.buildMemberAccessExpression(node)

	case parser.NodeTypeIdentifierExpression:
		return db.buildIdentifierExpression(node)

	case parser.NodeGenericSpecifierExpression:
		return db.buildGenericSpecifierExpression(node)

	case parser.NodeCastExpression:
		return db.buildCastExpression(node)

	case parser.NodeStreamMemberAccessExpression:
		return db.buildStreamMemberAccessExpression(node)

	// Await Expression.
	case parser.NodeTypeAwaitExpression:
		return db.buildAwaitExpression(node)

	// Lambda Expressions.
	case parser.NodeTypeLambdaExpression:
		return db.buildLambdaExpression(node)

	// SML Expressions.
	case parser.NodeTypeSmlExpression:
		return db.buildSmlExpression(node)

	case parser.NodeTypeSmlText:
		return db.buildSmlText(node)

	// Flow Expressions.
	case parser.NodeTypeConditionalExpression:
		return db.buildConditionalExpression(node)

	case parser.NodeTypeLoopExpression:
		return db.buildLoopExpression(node)

	// Op Expressions.
	case parser.NodeRootTypeExpression:
		return db.buildRootTypeExpression(node)

	case parser.NodeFunctionCallExpression:
		return db.buildFunctionCall(node)

	case parser.NodeSliceExpression:
		return db.buildSliceExpression(node)

	case parser.NodeNullComparisonExpression:
		return db.buildNullComparisonExpression(node)

	case parser.NodeAssertNotNullExpression:
		return db.buildAssertNotNullExpression(node)

	case parser.NodeIsComparisonExpression:
		return db.buildIsComparisonExpression(node)

	case parser.NodeInCollectionExpression:
		return db.buildInCollectionExpression(node)

	case parser.NodeBitwiseNotExpression:
		return db.buildUnaryOperatorExpression(node, nil)

	case parser.NodeKeywordNotExpression:
		return db.buildUnaryOperatorExpression(node, func(expr codedom.Expression) codedom.Expression {
			boolType := db.scopegraph.TypeGraph().BoolTypeReference()
			childExpr := codedom.UnaryOperation("!", codedom.NominalUnwrapping(expr, boolType, node), node)
			return codedom.NominalWrapping(
				childExpr,
				db.scopegraph.TypeGraph().BoolType(),
				node)
		})

	case parser.NodeDefineRangeExpression:
		fallthrough

	case parser.NodeBitwiseXorExpression:
		fallthrough

	case parser.NodeBitwiseOrExpression:
		fallthrough

	case parser.NodeBitwiseAndExpression:
		fallthrough

	case parser.NodeBitwiseShiftLeftExpression:
		fallthrough

	case parser.NodeBitwiseShiftRightExpression:
		fallthrough

	case parser.NodeBinaryAddExpression:
		fallthrough

	case parser.NodeBinarySubtractExpression:
		fallthrough

	case parser.NodeBinaryMultiplyExpression:
		fallthrough

	case parser.NodeBinaryDivideExpression:
		fallthrough

	case parser.NodeBinaryModuloExpression:
		return db.buildBinaryOperatorExpression(node, nil)

	case parser.NodeComparisonEqualsExpression:
		return db.buildBinaryOperatorExpression(node, nil)

	case parser.NodeComparisonNotEqualsExpression:
		return db.buildBinaryOperatorExpression(node, func(expr codedom.Expression) codedom.Expression {
			boolType := db.scopegraph.TypeGraph().BoolTypeReference()
			childExpr := codedom.UnaryOperation("!", codedom.NominalUnwrapping(expr, boolType, node), node)
			return codedom.NominalRefWrapping(
				childExpr,
				boolType.NominalDataType(),
				boolType,
				node)
		})

	case parser.NodeComparisonLTEExpression:
		return db.buildBinaryOperatorExpression(node, func(expr codedom.Expression) codedom.Expression {
			intType := db.scopegraph.TypeGraph().IntTypeReference()
			boolType := db.scopegraph.TypeGraph().BoolTypeReference()
			childExpr := codedom.BinaryOperation(codedom.NominalUnwrapping(expr, intType, node), "<=", codedom.LiteralValue("0", node), node)
			return codedom.NominalRefWrapping(
				childExpr,
				boolType.NominalDataType(),
				boolType,
				node)
		})

	case parser.NodeComparisonLTExpression:
		return db.buildBinaryOperatorExpression(node, func(expr codedom.Expression) codedom.Expression {
			intType := db.scopegraph.TypeGraph().IntTypeReference()
			boolType := db.scopegraph.TypeGraph().BoolTypeReference()
			childExpr := codedom.BinaryOperation(codedom.NominalUnwrapping(expr, intType, node), "<", codedom.LiteralValue("0", node), node)
			return codedom.NominalRefWrapping(
				childExpr,
				boolType.NominalDataType(),
				boolType,
				node)
		})

	case parser.NodeComparisonGTEExpression:
		return db.buildBinaryOperatorExpression(node, func(expr codedom.Expression) codedom.Expression {
			intType := db.scopegraph.TypeGraph().IntTypeReference()
			boolType := db.scopegraph.TypeGraph().BoolTypeReference()
			childExpr := codedom.BinaryOperation(codedom.NominalUnwrapping(expr, intType, node), ">=", codedom.LiteralValue("0", node), node)
			return codedom.NominalRefWrapping(
				childExpr,
				boolType.NominalDataType(),
				boolType,
				node)
		})

	case parser.NodeComparisonGTExpression:
		return db.buildBinaryOperatorExpression(node, func(expr codedom.Expression) codedom.Expression {
			intType := db.scopegraph.TypeGraph().IntTypeReference()
			boolType := db.scopegraph.TypeGraph().BoolTypeReference()
			childExpr := codedom.BinaryOperation(codedom.NominalUnwrapping(expr, intType, node), ">", codedom.LiteralValue("0", node), node)
			return codedom.NominalRefWrapping(
				childExpr,
				boolType.NominalDataType(),
				boolType,
				node)
		})

	// Boolean operators.
	case parser.NodeBooleanAndExpression:
		return db.buildBooleanBinaryExpression(node, "&&")

	case parser.NodeBooleanOrExpression:
		return db.buildBooleanBinaryExpression(node, "||")

	case parser.NodeBooleanNotExpression:
		return db.buildBooleanUnaryExpression(node, "!")

	// Literals.
	case parser.NodeStructuralNewExpression:
		return db.buildStructuralNewExpression(node)

	case parser.NodeNumericLiteralExpression:
		return db.buildNumericLiteral(node)

	case parser.NodeBooleanLiteralExpression:
		return db.buildBooleanLiteral(node)

	case parser.NodeStringLiteralExpression:
		return db.buildStringLiteral(node)

	case parser.NodeNullLiteralExpression:
		return db.buildNullLiteral(node)

	case parser.NodeThisLiteralExpression:
		return db.buildThisLiteral(node)

	case parser.NodeValLiteralExpression:
		return db.buildValLiteral(node)

	case parser.NodeListExpression:
		return db.buildListExpression(node)

	case parser.NodeSliceLiteralExpression:
		return db.buildSliceLiteralExpression(node)

	case parser.NodeMappingLiteralExpression:
		return db.buildMappingLiteralExpression(node)

	case parser.NodeMapExpression:
		return db.buildMapExpression(node)

	case parser.NodeTypeTemplateString:
		return db.buildTemplateStringExpression(node)

	case parser.NodeTaggedTemplateLiteralString:
		return db.buildTaggedTemplateString(node)

	default:
		panic(fmt.Sprintf("Unknown SRG expression node: %s", node.Kind()))
		return nil
	}
}
Example #7
0
// findAddedNameInScope finds the {parameter, with, loop, var} node exposing the given name, if any.
func (g *SRG) findAddedNameInScope(name string, node compilergraph.GraphNode) (compilergraph.GraphNode, bool) {
	nodeSource := node.Get(parser.NodePredicateSource)
	nodeStartIndex := node.GetValue(parser.NodePredicateStartRune).Int()

	// Note: This filter ensures that the name is accessible in the scope of the given node by checking that
	// the node adding the name contains the given node.
	containingFilter := func(q compilergraph.GraphQuery) compilergraph.Query {
		startRune := node.GetValue(parser.NodePredicateStartRune).Int()
		endRune := node.GetValue(parser.NodePredicateEndRune).Int()

		return q.
			In(parser.NodePredicateTypeMemberParameter,
				parser.NodeLambdaExpressionInferredParameter,
				parser.NodeLambdaExpressionParameter,
				parser.NodePredicateTypeMemberGeneric,
				parser.NodeStatementNamedValue,
				parser.NodeAssignedDestination,
				parser.NodeAssignedRejection,
				parser.NodePredicateChild,
				parser.NodeStatementBlockStatement).
			InIfKind(parser.NodeStatementBlockStatement, parser.NodeTypeResolveStatement).
			HasWhere(parser.NodePredicateStartRune, compilergraph.WhereLTE, startRune).
			HasWhere(parser.NodePredicateEndRune, compilergraph.WhereGTE, endRune)
	}

	nit := g.layer.StartQuery(name).
		In("named").
		Has(parser.NodePredicateSource, nodeSource).
		IsKind(parser.NodeTypeParameter, parser.NodeTypeNamedValue, parser.NodeTypeAssignedValue,
			parser.NodeTypeVariableStatement, parser.NodeTypeLambdaParameter, parser.NodeTypeGeneric).
		FilterBy(containingFilter).
		BuildNodeIterator(parser.NodePredicateStartRune, parser.NodePredicateEndRune)

	// Sort the nodes found by location and choose the closest node.
	var results = make(scopeResultNodes, 0)
	for nit.Next() {
		node := nit.Node()
		startIndex := nit.GetPredicate(parser.NodePredicateStartRune).Int()

		// If the node is a variable statement or assigned value, we have do to additional checks
		// (since they are not block scoped but rather statement scoped).
		if node.Kind() == parser.NodeTypeVariableStatement || node.Kind() == parser.NodeTypeAssignedValue {
			endIndex := nit.GetPredicate(parser.NodePredicateEndRune).Int()
			if node.Kind() == parser.NodeTypeAssignedValue {
				if parentNode, ok := node.TryGetIncomingNode(parser.NodeAssignedDestination); ok {
					endIndex = parentNode.GetValue(parser.NodePredicateEndRune).Int()
				} else if parentNode, ok := node.TryGetIncomingNode(parser.NodeAssignedRejection); ok {
					endIndex = parentNode.GetValue(parser.NodePredicateEndRune).Int()
				} else {
					panic("Missing assigned parent")
				}
			}

			// Check that the startIndex of the variable statement is <= the startIndex of the parent node
			if startIndex > nodeStartIndex {
				continue
			}

			// Ensure that the scope starts after the end index of the variable. Otherwise, the variable
			// name could be used in its initializer expression (which is expressly disallowed).
			if nodeStartIndex <= endIndex {
				continue
			}
		}

		results = append(results, scopeResultNode{node, startIndex})
	}

	if len(results) == 1 {
		// If there is a single result, return it.
		return results[0].node, true
	} else if len(results) > 1 {
		// Otherwise, sort the list by startIndex and choose the one closest to the scope node.
		sort.Sort(results)
		return results[0].node, true
	}

	return compilergraph.GraphNode{}, false
}
Example #8
0
func (db *domBuilder) buildOptimizedBinaryOperatorExpression(node compilergraph.GraphNode, parentType typegraph.TypeReference, leftExpr codedom.Expression, rightExpr codedom.Expression) (codedom.Expression, bool) {
	// Verify this is a supported native operator.
	opString, hasOp := operatorMap[node.Kind()]
	if !hasOp {
		return nil, false
	}

	// Verify we have a native binary operator we can optimize.
	if !parentType.IsNominal() {
		return nil, false
	}

	isNumeric := false

	switch {
	case parentType.IsDirectReferenceTo(db.scopegraph.TypeGraph().IntType()):
		isNumeric = true

	case parentType.IsDirectReferenceTo(db.scopegraph.TypeGraph().BoolType()):
		fallthrough

	case parentType.IsDirectReferenceTo(db.scopegraph.TypeGraph().StringType()):
		fallthrough

	default:
		return nil, false
	}

	// Handle the various kinds of operators.
	switch node.Kind() {
	case parser.NodeComparisonEqualsExpression:
		fallthrough

	case parser.NodeComparisonNotEqualsExpression:
		// Always allowed.
		break

	case parser.NodeComparisonLTEExpression:
		fallthrough
	case parser.NodeComparisonLTExpression:
		fallthrough
	case parser.NodeComparisonGTEExpression:
		fallthrough
	case parser.NodeComparisonGTExpression:
		// Only allowed for number.
		if !isNumeric {
			return nil, false
		}
	}

	boolType := db.scopegraph.TypeGraph().BoolTypeReference()

	unwrappedLeftExpr := codedom.NominalUnwrapping(leftExpr, parentType, node)
	unwrappedRightExpr := codedom.NominalUnwrapping(rightExpr, parentType, node)

	compareExpr := codedom.BinaryOperation(unwrappedLeftExpr, opString, unwrappedRightExpr, node)
	return codedom.NominalRefWrapping(compareExpr,
		boolType.NominalDataType(),
		boolType,
		node), true
}
Example #9
0
// inferTypesForConditionalExpressionContext returns a modified context for the then or else branches of
// a conditional statement that contains a type override of a named identifer if the comparison has clarified
// its type. For example a conditional expression of `a is null` will make the type of `a` be null under
// the then branch while being non-null under the `else` branch.
func (sb *scopeBuilder) inferTypesForConditionalExpressionContext(baseContext scopeContext,
	conditionalExprNode compilergraph.GraphNode,
	option inferrenceOption) scopeContext {

	// Make sure the conditional expression is valid.
	conditionalExprScope := sb.getScope(conditionalExprNode, baseContext)
	if !conditionalExprScope.GetIsValid() {
		return baseContext
	}

	checkIsExpression := func(isExpressionNode compilergraph.GraphNode, setToNull bool) scopeContext {
		// Invert the null-set if requested.
		if option == inferredInverted {
			setToNull = !setToNull
		}

		// Ensure the left expression of the `is` has valid scope.
		leftScope := sb.getScope(isExpressionNode.GetNode(parser.NodeBinaryExpressionLeftExpr), baseContext)
		if !leftScope.GetIsValid() {
			return baseContext
		}

		// Ensure that the left expression refers to a named scope.
		leftNamed, isNamed := sb.getNamedScopeForScope(leftScope)
		if !isNamed {
			return baseContext
		}

		// Ensure that the left expression does not have a void type. We know it is valid
		// due to the check above.
		valueType, _ := leftNamed.ValueType(baseContext)
		if valueType.IsVoid() {
			return baseContext
		}

		// Lookup the right expression. If it is itself a `not`, then we invert the set to null.
		rightExpr := isExpressionNode.GetNode(parser.NodeBinaryExpressionRightExpr)
		if rightExpr.Kind() == parser.NodeKeywordNotExpression {
			setToNull = !setToNull
		}

		// Add an override for the named node.
		leftNamedNode, _ := leftScope.NamedReferenceNode(sb.sg.srg, sb.sg.tdg)
		if setToNull {
			return baseContext.withTypeOverride(leftNamedNode, sb.sg.tdg.NullTypeReference())
		} else {
			return baseContext.withTypeOverride(leftNamedNode, leftScope.ResolvedTypeRef(sb.sg.tdg).AsNonNullable())
		}
	}

	// TODO: If we add more comparisons or forms here, change this into a more formal comparison
	// system rather than hand-written checks.
	exprKind := conditionalExprNode.Kind()
	switch exprKind {
	case parser.NodeIsComparisonExpression:
		// Check the `is` expression itself to see if we can add the inferred type.
		return checkIsExpression(conditionalExprNode, true)

	case parser.NodeBooleanNotExpression:
		// If the ! is in front of an `is` expression, then invert it.
		childExpr := conditionalExprNode.GetNode(parser.NodeUnaryExpressionChildExpr)
		if childExpr.Kind() == parser.NodeIsComparisonExpression {
			return checkIsExpression(childExpr, false)
		}
	}

	return baseContext
}
Example #10
0
// getScopeHandler returns the scope building handler for nodes of the given type.
func (sb *scopeBuilder) getScopeHandler(node compilergraph.GraphNode) scopeHandler {
	switch node.Kind() {
	// Members.
	case parser.NodeTypeProperty:
		fallthrough

	case parser.NodeTypePropertyBlock:
		fallthrough

	case parser.NodeTypeFunction:
		fallthrough

	case parser.NodeTypeConstructor:
		fallthrough

	case parser.NodeTypeOperator:
		return sb.scopeImplementedMember

	case parser.NodeTypeVariable:
		return sb.scopeVariable

	case parser.NodeTypeField:
		return sb.scopeField

	// Statements.
	case parser.NodeTypeStatementBlock:
		return sb.scopeStatementBlock

	case parser.NodeTypeBreakStatement:
		return sb.scopeBreakStatement

	case parser.NodeTypeContinueStatement:
		return sb.scopeContinueStatement

	case parser.NodeTypeYieldStatement:
		return sb.scopeYieldStatement

	case parser.NodeTypeReturnStatement:
		return sb.scopeReturnStatement

	case parser.NodeTypeRejectStatement:
		return sb.scopeRejectStatement

	case parser.NodeTypeConditionalStatement:
		return sb.scopeConditionalStatement

	case parser.NodeTypeLoopStatement:
		return sb.scopeLoopStatement

	case parser.NodeTypeWithStatement:
		return sb.scopeWithStatement

	case parser.NodeTypeVariableStatement:
		return sb.scopeVariableStatement

	case parser.NodeTypeSwitchStatement:
		return sb.scopeSwitchStatement

	case parser.NodeTypeMatchStatement:
		return sb.scopeMatchStatement

	case parser.NodeTypeAssignStatement:
		return sb.scopeAssignStatement

	case parser.NodeTypeExpressionStatement:
		return sb.scopeExpressionStatement

	case parser.NodeTypeNamedValue:
		return sb.scopeNamedValue

	case parser.NodeTypeAssignedValue:
		return sb.scopeAssignedValue

	case parser.NodeTypeArrowStatement:
		return sb.scopeArrowStatement

	case parser.NodeTypeResolveStatement:
		return sb.scopeResolveStatement

	// Await expression.
	case parser.NodeTypeAwaitExpression:
		return sb.scopeAwaitExpression

	// SML expression.
	case parser.NodeTypeSmlExpression:
		return sb.scopeSmlExpression

	case parser.NodeTypeSmlText:
		return sb.scopeSmlText

	// Flow expressions.
	case parser.NodeTypeConditionalExpression:
		return sb.scopeConditionalExpression

	case parser.NodeTypeLoopExpression:
		return sb.scopeLoopExpression

	// Access expressions.
	case parser.NodeCastExpression:
		return sb.scopeCastExpression

	case parser.NodeMemberAccessExpression:
		return sb.scopeMemberAccessExpression

	case parser.NodeNullableMemberAccessExpression:
		return sb.scopeNullableMemberAccessExpression

	case parser.NodeDynamicMemberAccessExpression:
		return sb.scopeDynamicMemberAccessExpression

	case parser.NodeStreamMemberAccessExpression:
		return sb.scopeStreamMemberAccessExpression

	// Operator expressions.
	case parser.NodeDefineRangeExpression:
		return sb.scopeDefineRangeExpression

	case parser.NodeSliceExpression:
		return sb.scopeSliceExpression

	case parser.NodeBitwiseXorExpression:
		return sb.scopeBitwiseXorExpression

	case parser.NodeBitwiseOrExpression:
		return sb.scopeBitwiseOrExpression

	case parser.NodeBitwiseAndExpression:
		return sb.scopeBitwiseAndExpression

	case parser.NodeBitwiseShiftLeftExpression:
		return sb.scopeBitwiseShiftLeftExpression

	case parser.NodeBitwiseShiftRightExpression:
		return sb.scopeBitwiseShiftRightExpression

	case parser.NodeBitwiseNotExpression:
		return sb.scopeBitwiseNotExpression

	case parser.NodeBinaryAddExpression:
		return sb.scopeBinaryAddExpression

	case parser.NodeBinarySubtractExpression:
		return sb.scopeBinarySubtractExpression

	case parser.NodeBinaryMultiplyExpression:
		return sb.scopeBinaryMultiplyExpression

	case parser.NodeBinaryDivideExpression:
		return sb.scopeBinaryDivideExpression

	case parser.NodeBinaryModuloExpression:
		return sb.scopeBinaryModuloExpression

	case parser.NodeBooleanAndExpression:
		return sb.scopeBooleanBinaryExpression

	case parser.NodeBooleanOrExpression:
		return sb.scopeBooleanBinaryExpression

	case parser.NodeBooleanNotExpression:
		return sb.scopeBooleanUnaryExpression

	case parser.NodeKeywordNotExpression:
		return sb.scopeKeywordNotExpression

	case parser.NodeComparisonEqualsExpression:
		return sb.scopeEqualsExpression

	case parser.NodeComparisonNotEqualsExpression:
		return sb.scopeEqualsExpression

	case parser.NodeComparisonLTEExpression:
		return sb.scopeComparisonExpression

	case parser.NodeComparisonLTExpression:
		return sb.scopeComparisonExpression

	case parser.NodeComparisonGTEExpression:
		return sb.scopeComparisonExpression

	case parser.NodeComparisonGTExpression:
		return sb.scopeComparisonExpression

	case parser.NodeNullComparisonExpression:
		return sb.scopeNullComparisonExpression

	case parser.NodeAssertNotNullExpression:
		return sb.scopeAssertNotNullExpression

	case parser.NodeIsComparisonExpression:
		return sb.scopeIsComparisonExpression

	case parser.NodeInCollectionExpression:
		return sb.scopeInCollectionExpression

	case parser.NodeFunctionCallExpression:
		return sb.scopeFunctionCallExpression

	case parser.NodeGenericSpecifierExpression:
		return sb.scopeGenericSpecifierExpression

	case parser.NodeRootTypeExpression:
		return sb.scopeRootTypeExpression

	// Literal expressions.
	case parser.NodeBooleanLiteralExpression:
		return sb.scopeBooleanLiteralExpression

	case parser.NodeNumericLiteralExpression:
		return sb.scopeNumericLiteralExpression

	case parser.NodeStringLiteralExpression:
		return sb.scopeStringLiteralExpression

	case parser.NodeListExpression:
		return sb.scopeListLiteralExpression

	case parser.NodeSliceLiteralExpression:
		return sb.scopeSliceLiteralExpression

	case parser.NodeMappingLiteralExpression:
		return sb.scopeMappingLiteralExpression

	case parser.NodeMapExpression:
		return sb.scopeMapLiteralExpression

	case parser.NodeNullLiteralExpression:
		return sb.scopeNullLiteralExpression

	case parser.NodeThisLiteralExpression:
		return sb.scopeThisLiteralExpression

	case parser.NodeTypeLambdaExpression:
		return sb.scopeLambdaExpression

	case parser.NodeValLiteralExpression:
		return sb.scopeValLiteralExpression

	case parser.NodeStructuralNewExpression:
		return sb.scopeStructuralNewExpression

	case parser.NodeStructuralNewExpressionEntry:
		return sb.scopeStructuralNewExpressionEntry

	// Template string.
	case parser.NodeTaggedTemplateLiteralString:
		return sb.scopeTaggedTemplateString

	case parser.NodeTypeTemplateString:
		return sb.scopeTemplateStringExpression

	// Named expressions.
	case parser.NodeTypeIdentifierExpression:
		return sb.scopeIdentifierExpression

	default:
		panic(fmt.Sprintf("Unknown SRG node in scoping: %v", node.Kind()))
	}
}