Example #1
0
// 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()
}
Example #2
0
// 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
}