// scopeReturnStatement scopes a return statement in the SRG. func (sb *scopeBuilder) scopeReturnStatement(node compilergraph.GraphNode, context scopeContext) proto.ScopeInfo { var actualReturnType typegraph.TypeReference = sb.sg.tdg.VoidTypeReference() exprNode, found := node.TryGetNode(parser.NodeReturnStatementValue) if found { exprScope := sb.getScope(exprNode, context) if !exprScope.GetIsValid() { return newScope(). Invalid(). GetScope() } actualReturnType = exprScope.ResolvedTypeRef(sb.sg.tdg) } // Ensure the return types match. expectedReturnType, _ := sb.sg.tdg.LookupReturnType(context.parentImplemented) if expectedReturnType.IsVoid() { if !actualReturnType.IsVoid() { sb.decorateWithError(node, "No return value expected here, found value of type '%v'", actualReturnType) return newScope(). Invalid(). Returning(actualReturnType, true). GetScope() } } else if actualReturnType.IsVoid() { sb.decorateWithError(node, "Expected non-void resolved value") return newScope(). Invalid(). Returning(actualReturnType, true). GetScope() } else { if serr := actualReturnType.CheckSubTypeOf(expectedReturnType); serr != nil { sb.decorateWithError(node, "Expected return value of type '%v': %v", expectedReturnType, serr) return newScope(). Invalid(). Returning(actualReturnType, true). GetScope() } } return newScope(). IsTerminatingStatement(). Valid(). Returning(actualReturnType, true). GetScope() }
// scopeSmlDecoratorAttribute scopes a decorator SML expression attribute under a declaration. func (sb *scopeBuilder) scopeSmlDecorator(node compilergraph.GraphNode, declaredType typegraph.TypeReference, context scopeContext) (typegraph.TypeReference, bool) { // Resolve the scope of the decorator. decoratorScope := sb.getScope(node.GetNode(parser.NodeSmlDecoratorPath), context) if !decoratorScope.GetIsValid() { return declaredType, false } namedScope, _ := sb.getNamedScopeForScope(decoratorScope) decoratorName := namedScope.Name() // Register that we make use of the decorator function. context.staticDependencyCollector.registerNamedDependency(namedScope) // Ensure the decorator refers to a function. decoratorType := decoratorScope.ResolvedTypeRef(sb.sg.tdg) if !decoratorType.IsDirectReferenceTo(sb.sg.tdg.FunctionType()) { sb.decorateWithError(node, "SML declaration decorator '%v' must refer to a function. Found: %v", decoratorName, decoratorType) return declaredType, false } // Ensure that the decorator doesn't return void. returnType := decoratorType.Generics()[0] if returnType.IsVoid() { sb.decorateWithError(node, "SML declaration decorator '%v' cannot return void", decoratorName) return declaredType, false } // Scope the attribute value (if any). var attributeValueType = sb.sg.tdg.BoolTypeReference() valueNode, hasValueNode := node.TryGetNode(parser.NodeSmlDecoratorValue) if hasValueNode { attributeValueScope := sb.getScope(valueNode, context) if !attributeValueScope.GetIsValid() { return returnType, false } attributeValueType = attributeValueScope.ResolvedTypeRef(sb.sg.tdg) } // Ensure the decorator takes the decorated type and a value as parameters. if decoratorType.ParameterCount() != 2 { sb.decorateWithError(node, "SML declaration decorator '%v' must refer to a function with two parameters. Found: %v", decoratorName, decoratorType) return returnType, false } // Ensure the first parameter is the declared type. allowedDecoratedType := decoratorType.Parameters()[0] allowedValueType := decoratorType.Parameters()[1] if serr := declaredType.CheckSubTypeOf(allowedDecoratedType); serr != nil { sb.decorateWithError(node, "SML declaration decorator '%v' expects to decorate an instance of type %v: %v", decoratorName, allowedDecoratedType, serr) return declaredType, false } // Ensure that the second parameter is the value type. if serr := attributeValueType.CheckSubTypeOf(allowedValueType); serr != nil { sb.decorateWithError(node, "Cannot assign value of type %v for decorator '%v': %v", attributeValueType, decoratorName, serr) return returnType, false } // The returned type is that of the decorator. return returnType, true }