コード例 #1
0
ファイル: parser_test.go プロジェクト: Serulian/compiler
func TestParser(t *testing.T) {
	for _, test := range parserTests {
		if os.Getenv("FILTER") != "" {
			if !strings.Contains(test.name, os.Getenv("FILTER")) {
				continue
			} else {
				fmt.Printf("Matched Test: %v\n", test.name)
			}
		}

		moduleNode := createAstNode(compilercommon.InputSource(test.name), NodeTypeGlobalModule)

		Parse(moduleNode, createAstNode, compilercommon.InputSource(test.name), test.input())
		parseTree := getParseTree((moduleNode).(*testNode), 0)
		assert := assert.New(t)

		expected := strings.TrimSpace(test.tree())
		found := strings.TrimSpace(parseTree)

		if os.Getenv("REGEN") == "true" {
			test.writeTree(found)
		} else {
			if !assert.Equal(expected, found, test.name) {
				t.Log(parseTree)
			}
		}
	}
}
コード例 #2
0
ファイル: packageloader.go プロジェクト: Serulian/compiler
// conductParsing performs parsing of a source file found at the given path.
func (p *PackageLoader) conductParsing(sourceFile pathInformation) {
	inputSource := compilercommon.InputSource(sourceFile.path)

	// Add the file to the package map as a package of one file.
	p.packageMap.Add(sourceFile.sourceKind, sourceFile.referenceId, PackageInfo{
		kind:        sourceFile.sourceKind,
		referenceId: sourceFile.referenceId,
		modulePaths: []compilercommon.InputSource{inputSource},
	})

	// Ensure the file exists.
	if ok, _ := exists(sourceFile.path); !ok {
		p.errors <- compilercommon.SourceErrorf(sourceFile.sal, "Could not find source file '%s'", sourceFile.path)
		return
	}

	// Load the source file's contents.
	contents, err := ioutil.ReadFile(sourceFile.path)
	if err != nil {
		p.errors <- compilercommon.SourceErrorf(sourceFile.sal, "Could not load source file '%s'", sourceFile.path)
		return
	}

	// Parse the source file.
	handler, hasHandler := p.handlers[sourceFile.sourceKind]
	if !hasHandler {
		log.Fatalf("Missing handler for source file of kind: [%v]", sourceFile.sourceKind)
	}

	handler.Parse(inputSource, string(contents), p.handleImport)
}
コード例 #3
0
ファイル: scope_op_expr.go プロジェクト: Serulian/compiler
// scopeUnaryExpression scopes a unary expression in the SRG.
func (sb *scopeBuilder) scopeUnaryExpression(node compilergraph.GraphNode, opName string, predicate compilergraph.Predicate, context scopeContext) *scopeInfoBuilder {
	// Get the scope of the sub expression.
	childScope := sb.getScope(node.GetNode(predicate), context)

	// Ensure that the child scope is valid.
	if !childScope.GetIsValid() {
		return newScope().Invalid()
	}

	// Ensure that the operator exists under the resolved type.
	childType := childScope.ResolvedTypeRef(sb.sg.tdg)
	module := compilercommon.InputSource(node.Get(parser.NodePredicateSource))
	operator, rerr := childType.ResolveAccessibleMember(opName, module, typegraph.MemberResolutionOperator)
	if rerr != nil {
		sb.decorateWithError(node, "Operator '%v' is not defined on type '%v'", opName, childType)
		return newScope().Invalid()
	}

	returnType, _ := operator.ReturnType()

	// Check for nullable values.
	if childType.NullValueAllowed() {
		sb.decorateWithError(node, "Cannot invoke operator '%v' on nullable type '%v'", opName, childType)
		return newScope().Invalid().CallsOperator(operator).Resolving(returnType.TransformUnder(childType))
	}

	return newScope().Valid().CallsOperator(operator).Resolving(returnType.TransformUnder(childType))
}
コード例 #4
0
ファイル: scope_op_expr.go プロジェクト: Serulian/compiler
// scopeInCollectionExpression scopes an 'in' collection expression in the SRG.
func (sb *scopeBuilder) scopeInCollectionExpression(node compilergraph.GraphNode, context scopeContext) proto.ScopeInfo {
	// Get the scope of the left and right expressions.
	leftScope := sb.getScope(node.GetNode(parser.NodeBinaryExpressionLeftExpr), context)
	rightScope := sb.getScope(node.GetNode(parser.NodeBinaryExpressionRightExpr), context)

	// Ensure that both scopes are valid.
	if !leftScope.GetIsValid() || !rightScope.GetIsValid() {
		return newScope().Invalid().GetScope()
	}

	// Ensure that the right side has a 'contains' operator defined.
	rightType := rightScope.ResolvedTypeRef(sb.sg.tdg)
	module := compilercommon.InputSource(node.Get(parser.NodePredicateSource))
	operator, rerr := rightType.ResolveAccessibleMember("contains", module, typegraph.MemberResolutionOperator)
	if rerr != nil {
		sb.decorateWithError(node, "Operator 'contains' is not defined on type '%v'", rightType)
		return newScope().Invalid().GetScope()
	}

	// Ensure the right side is not nullable.
	if rightType.NullValueAllowed() {
		sb.decorateWithError(node, "Cannot invoke operator 'in' on nullable value of type '%v'", rightType)
		return newScope().Invalid().GetScope()
	}

	// Ensure that the left side can be used as the operator's parameter.
	parameterType := operator.ParameterTypes()[0].TransformUnder(rightType)
	leftType := leftScope.ResolvedTypeRef(sb.sg.tdg)
	if serr := leftType.CheckSubTypeOf(parameterType); serr != nil {
		sb.decorateWithError(node, "Cannot invoke operator 'in' with value of type '%v': %v", leftType, serr)
		return newScope().Invalid().GetScope()
	}

	return newScope().Valid().CallsOperator(operator).Resolving(sb.sg.tdg.BoolTypeReference()).GetScope()
}
コード例 #5
0
ファイル: webidl.go プロジェクト: Serulian/compiler
// salForValues returns a SourceAndLocation for the given string predicate values.
func salForValues(sourceStr string, bytePositionStr string) compilercommon.SourceAndLocation {
	source := compilercommon.InputSource(sourceStr)
	bytePosition, err := strconv.Atoi(bytePositionStr)
	if err != nil {
		panic(fmt.Sprintf("Expected int value for byte position, found: %v", bytePositionStr))
	}

	return compilercommon.NewSourceAndLocation(source, bytePosition)
}
コード例 #6
0
func conductParsing(t *testing.T, test goldenTest, source []byte) (*parseTree, formatterNode) {
	parseTree := newParseTree(source)
	inputSource := compilercommon.InputSource(test.filename)
	rootNode := parser.Parse(parseTree.createAstNode, nil, inputSource, string(source))
	if !assert.Empty(t, parseTree.errors, "Expected no parse errors for test %s", test.name) {
		return nil, formatterNode{}
	}

	return parseTree, rootNode.(formatterNode)
}
コード例 #7
0
ファイル: scopename_test.go プロジェクト: Serulian/compiler
func TestNameScoping(t *testing.T) {
	for _, test := range nameScopeTests {
		if os.Getenv("FILTER") != "" && !strings.Contains(test.name, os.Getenv("FILTER")) {
			continue
		}

		source := fmt.Sprintf("tests/namescope/%s.seru", test.source)
		testSRG := getSRG(t, source, "tests/testlib")

		_, found := testSRG.FindModuleBySource(compilercommon.InputSource(source))
		if !assert.True(t, found, "Test module not found") {
			continue
		}

		// Find the commented node.
		commentedNode, commentFound := testSRG.FindCommentedNode("/* " + test.comment + " */")
		if !assert.True(t, commentFound, "Comment %v for test %v not found", test.comment, test.name) {
			continue
		}

		// Resolve the name from the node.
		result, nameFound := testSRG.FindNameInScope(test.queryName, commentedNode)
		if !test.result.isValid {
			assert.False(t, nameFound, "Test %v expected name %v to not be found. Found: %v", test.name, test.queryName, result)
			continue
		}

		if !assert.Equal(t, result.IsNamedScope(), !test.result.isExternal, "External scope mismatch on test %s", test.name) {
			continue
		}

		if result.IsNamedScope() {
			resolved := result.AsNamedScope()
			if !assert.True(t, nameFound, "Test %v expected name %v to be found", test.name, test.queryName) {
				continue
			}

			if !assert.Equal(t, test.result.expectedNodeType, resolved.Kind(), "Test %v expected node of kind %v", test.name, test.result.expectedNodeType) {
				continue
			}

			if !assert.Equal(t, test.result.expectedName, resolved.Name(), "Test %v expected name %v", test.name, test.result.expectedName) {
				continue
			}

			if !assert.Equal(t, test.result.expectedKind, resolved.ScopeKind(), "Test %v expected kind %v", test.name, test.result.expectedKind) {
				continue
			}
		} else {
			if !assert.Equal(t, test.result.expectedName, result.AsPackageImport().name, "Mismatch name on imported package for test %s", test.name) {
				continue
			}
		}
	}
}
コード例 #8
0
ファイル: modules_test.go プロジェクト: Serulian/compiler
func TestComplexResolveTypePath(t *testing.T) {
	testSRG := getSRG(t, "tests/complexresolve/entrypoint.seru")

	// Lookup the entrypoint module.
	entrypointModule, ok := testSRG.FindModuleBySource(compilercommon.InputSource("tests/complexresolve/entrypoint.seru"))
	assert.True(t, ok, "Could not find entrypoint module")

	// Lookup all the expected types.

	// In module.
	assertResolveTypePath(t, entrypointModule, "SomeClass", "SomeClass")

	// from ... import ... on module
	assertResolveTypePath(t, entrypointModule, "AnotherClass", "AnotherClass")
	assertResolveTypePath(t, entrypointModule, "BestClass", "AThirdClass")

	// from ... import ... on package
	assertResolveTypePath(t, entrypointModule, "FirstClass", "FirstClass")
	assertResolveTypePath(t, entrypointModule, "SecondClass", "SecondClass")
	assertResolveTypePath(t, entrypointModule, "BusinessClass", "FirstClass")

	// Direct imports.
	assertResolveTypePath(t, entrypointModule, "anothermodule.AnotherClass", "AnotherClass")

	assertResolveTypePath(t, entrypointModule, "subpackage.FirstClass", "FirstClass")
	assertResolveTypePath(t, entrypointModule, "subpackage.SecondClass", "SecondClass")

	// Ensure that an non-exported type is still accessible inside the package..
	assertResolveTypePath(t, entrypointModule, "anothermodule.localClass", "localClass")

	// Other package.
	assertResolveTypePath(t, entrypointModule, "anotherpackage.ExportedPackageClass", "ExportedPackageClass")

	// Ensure that an non-exported type is not accessible from another package.
	_, found := entrypointModule.ResolveTypePath("anotherpackage.otherPackageClass")
	assert.False(t, found, "Expected otherPackageClass to not be exported")

	// Lookup another module.
	anotherModule, ok := testSRG.FindModuleBySource(compilercommon.InputSource("tests/complexresolve/anothermodule.seru"))
	assert.True(t, ok, "Could not find another module")
	assertResolveTypePath(t, anotherModule, "localClass", "localClass")
}
コード例 #9
0
ファイル: lex_test.go プロジェクト: Serulian/compiler
// collect gathers the emitted tokens into a slice.
func collect(t *lexerTest) (tokens []lexeme) {
	l := lex(compilercommon.InputSource(t.name), t.input)
	for {
		token := l.nextToken()
		tokens = append(tokens, token)
		if token.kind == tokenTypeEOF || token.kind == tokenTypeError {
			break
		}
	}
	return
}
コード例 #10
0
ファイル: modules_test.go プロジェクト: Serulian/compiler
func TestBasicResolveTypePath(t *testing.T) {
	testSRG := getSRG(t, "tests/basic/basic.seru")

	// Lookup the basic module.
	basicModule, ok := testSRG.FindModuleBySource(compilercommon.InputSource("tests/basic/basic.seru"))
	assert.True(t, ok, "Could not find basic module")

	// Lookup both expected types.
	assertResolveTypePath(t, basicModule, "SomeClass", "SomeClass")
	assertResolveTypePath(t, basicModule, "AnotherClass", "AnotherClass")
}
コード例 #11
0
// scopeMemberAccessExpression scopes a member access expression in the SRG.
func (sb *scopeBuilder) scopeMemberAccessExpression(node compilergraph.GraphNode, context scopeContext) proto.ScopeInfo {
	// Get the scope of the child expression.
	childScope := sb.getScope(node.GetNode(parser.NodeMemberAccessChildExpr), context)
	if !childScope.GetIsValid() {
		return newScope().Invalid().GetScope()
	}

	memberName := node.Get(parser.NodeMemberAccessIdentifier)
	module := compilercommon.InputSource(node.Get(parser.NodePredicateSource))

	switch childScope.GetKind() {

	case proto.ScopeKind_VALUE:
		childType := childScope.ResolvedTypeRef(sb.sg.tdg)
		if childType.IsNullable() {
			sb.decorateWithError(node, "Cannot access name '%v' under nullable type '%v'. Please use the ?. operator to ensure type safety.", memberName, childType)
			return newScope().Invalid().GetScope()
		}

		typeMember, rerr := childType.ResolveAccessibleMember(memberName, module, typegraph.MemberResolutionInstance)
		if rerr != nil {
			sb.decorateWithError(node, "%v", rerr)
			return newScope().Invalid().GetScope()
		}

		memberScope := sb.getNamedScopeForMember(typeMember)
		context.staticDependencyCollector.checkNamedScopeForDependency(memberScope)

		return newScope().ForNamedScopeUnderType(memberScope, childType, context).GetScope()

	case proto.ScopeKind_GENERIC:
		namedScope, _ := sb.getNamedScopeForScope(childScope)
		sb.decorateWithError(node, "Cannot attempt member access of '%v' under %v %v, as it is generic without specification", memberName, namedScope.Title(), namedScope.Name())
		return newScope().Invalid().GetScope()

	case proto.ScopeKind_STATIC:
		staticType := childScope.StaticTypeRef(sb.sg.tdg)
		namedScope, _ := sb.getNamedScopeForScope(childScope)
		memberScope, rerr := namedScope.ResolveStaticMember(memberName, module, staticType)
		if rerr != nil {
			sb.decorateWithError(node, "%v", rerr)
			return newScope().Invalid().GetScope()
		}
		return newScope().ForNamedScopeUnderType(memberScope, staticType, context).GetScope()

	default:
		panic("Unknown scope kind")
	}

	return newScope().Invalid().GetScope()
}
コード例 #12
0
ファイル: members_test.go プロジェクト: Serulian/compiler
func TestModuleMembers(t *testing.T) {
	testSRG := getSRG(t, "tests/members/module.seru")

	// Ensure both module-level members are found.
	module, _ := testSRG.FindModuleBySource(compilercommon.InputSource("tests/members/module.seru"))
	members := module.GetMembers()

	if !assert.Equal(t, 2, len(members), "Expected 2 members found") {
		return
	}

	assert.Equal(t, members[0].MemberKind(), VarMember)
	assert.Equal(t, members[1].MemberKind(), FunctionMember)
}
コード例 #13
0
// scopeStreamMemberAccessExpression scopes a stream member access expression in the SRG.
func (sb *scopeBuilder) scopeStreamMemberAccessExpression(node compilergraph.GraphNode, context scopeContext) proto.ScopeInfo {
	// Get the scope of the child expression.
	childScope := sb.getScope(node.GetNode(parser.NodeMemberAccessChildExpr), context)
	if !childScope.GetIsValid() {
		return newScope().Invalid().GetScope()
	}

	memberName := node.Get(parser.NodeMemberAccessIdentifier)
	module := compilercommon.InputSource(node.Get(parser.NodePredicateSource))

	switch childScope.GetKind() {
	case proto.ScopeKind_VALUE:
		childType := childScope.ResolvedTypeRef(sb.sg.tdg)

		// Ensure the child type is a stream.
		generics, serr := childType.CheckConcreteSubtypeOf(sb.sg.tdg.StreamType())
		if serr != nil {
			sb.decorateWithError(node, "Cannot attempt stream access of name '%v' under non-stream type '%v': %v", memberName, childType, serr)
			return newScope().Invalid().GetScope()
		}

		valueType := generics[0]
		typeMember, rerr := valueType.ResolveAccessibleMember(memberName, module, typegraph.MemberResolutionInstance)
		if rerr != nil {
			sb.decorateWithError(node, "%v", rerr)
			return newScope().Invalid().GetScope()
		}

		memberScope := sb.getNamedScopeForMember(typeMember)
		context.staticDependencyCollector.checkNamedScopeForDependency(memberScope)

		return newScope().ForNamedScopeUnderModifiedType(memberScope, valueType, makeStream, context).GetScope()

	case proto.ScopeKind_GENERIC:
		namedScope, _ := sb.getNamedScopeForScope(childScope)
		sb.decorateWithError(node, "Cannot attempt stream member access of '%v' under %v %v, as it is generic without specification", memberName, namedScope.Title(), namedScope.Name())
		return newScope().Invalid().GetScope()

	case proto.ScopeKind_STATIC:
		namedScope, _ := sb.getNamedScopeForScope(childScope)
		sb.decorateWithError(node, "Cannot attempt stream member access of '%v' under %v %v, as it is a static type", memberName, namedScope.Title(), namedScope.Name())
		return newScope().Invalid().GetScope()

	default:
		panic("Unknown scope kind")
	}

	return newScope().Invalid().GetScope()
}
コード例 #14
0
ファイル: modules.go プロジェクト: Serulian/compiler
// getModulesMap returns the modules map for the modules in the SRG.
func (g *SRG) getModulesMap() map[compilercommon.InputSource]SRGModule {
	if g.modulePathMap == nil {
		moduleMap := map[compilercommon.InputSource]SRGModule{}
		it := g.findAllNodes(parser.NodeTypeFile).BuildNodeIterator(parser.NodePredicateSource)
		for it.Next() {
			moduleMap[compilercommon.InputSource(it.GetPredicate(parser.NodePredicateSource).String())] = SRGModule{it.Node(), g}
		}

		// Cache the map.
		g.modulePathMap = moduleMap
		return moduleMap
	}

	return g.modulePathMap
}
コード例 #15
0
ファイル: typeref.go プロジェクト: Serulian/compiler
// ResolveType attempts to resolve the type path referenced by this type ref.
// Panics if this is not a RefKind of TypeRefPath.
func (t SRGTypeRef) ResolveType() (TypeResolutionResult, bool) {
	// Find the parent module.
	source := compilercommon.InputSource(t.GraphNode.Get(parser.NodePredicateSource))
	srgModule, found := t.srg.FindModuleBySource(source)
	if !found {
		panic(fmt.Sprintf("Unknown parent module: %s", source))
	}

	// Resolve the type path under the module.
	resolutionPath := t.ResolutionPath()
	resolvedType, typeFound := srgModule.ResolveTypePath(resolutionPath)
	if typeFound {
		return resolvedType, true
	}

	// If not found and the path is a single name, try to resolve as a generic
	// under a parent function or type.
	if strings.ContainsRune(resolutionPath, '.') {
		// Not a single name.
		return TypeResolutionResult{}, false
	}

	containingFilter := func(q compilergraph.GraphQuery) compilergraph.Query {
		// For this filter, we check if the defining type (or type member) if the
		// generic is the same type (or type member) containing the typeref. To do so,
		// we perform a check that the start rune and end rune of the definition
		// contains the range of the start and end rune, respectively, of the typeref. Since
		// we know both nodes are in the same module, and the SRG is a tree, this validates
		// that we are in the correct scope without having to walk the tree upward.
		startRune := t.GraphNode.GetValue(parser.NodePredicateStartRune).Int()
		endRune := t.GraphNode.GetValue(parser.NodePredicateEndRune).Int()

		return q.
			In(parser.NodeTypeDefinitionGeneric, parser.NodePredicateTypeMemberGeneric).
			HasWhere(parser.NodePredicateStartRune, compilergraph.WhereLTE, startRune).
			HasWhere(parser.NodePredicateEndRune, compilergraph.WhereGTE, endRune)
	}

	resolvedGenericNode, genericFound := t.srg.layer.
		StartQuery().                                         // Find a node...
		Has(parser.NodeGenericPredicateName, resolutionPath). // With the generic name..
		Has(parser.NodePredicateSource, string(source)).      // That is in this module...
		IsKind(parser.NodeTypeGeneric).                       // That is a generic...
		FilterBy(containingFilter).                           // Filter by whether its defining type or member contains this typeref.
		TryGetNode()

	return resultForTypeOrGeneric(SRGTypeOrGeneric{resolvedGenericNode, t.srg}), genericFound
}
コード例 #16
0
ファイル: scopename.go プロジェクト: Serulian/compiler
// FindNameInScope finds the given name accessible from the scope under which the given node exists, if any.
func (g *SRG) FindNameInScope(name string, node compilergraph.GraphNode) (SRGScopeOrImport, bool) {
	// Attempt to resolve the name as pointing to a parameter, var statement, loop var or with var.
	srgNode, srgNodeFound := g.findAddedNameInScope(name, node)
	if srgNodeFound {
		return SRGNamedScope{srgNode, g}, true
	}

	// If still not found, try to resolve as a type or import.
	nodeSource := node.Get(parser.NodePredicateSource)
	parentModule, parentModuleFound := g.FindModuleBySource(compilercommon.InputSource(nodeSource))
	if !parentModuleFound {
		panic(fmt.Sprintf("Missing module for source %v", nodeSource))
	}

	// Try to resolve as a local member.
	srgTypeOrMember, typeOrMemberFound := parentModule.FindTypeOrMemberByName(name, ModuleResolveAll)
	if typeOrMemberFound {
		return SRGNamedScope{srgTypeOrMember.GraphNode, g}, true
	}

	// Try to resolve as an imported member.
	localImportNode, localImportFound := parentModule.findImportWithLocalName(name)
	if localImportFound {
		// Retrieve the package for the imported member.
		packageInfo := g.getPackageForImport(localImportNode)
		resolutionName := localImportNode.Get(parser.NodeImportPredicateSubsource)

		// If an SRG package, then continue with the resolution. Otherwise,
		// we return a named scope that says that the name needs to be furthered
		// resolved in the package by the type graph.
		if packageInfo.IsSRGPackage() {
			packageTypeOrMember, packagetypeOrMemberFound := packageInfo.FindTypeOrMemberByName(resolutionName)
			if packagetypeOrMemberFound {
				return SRGNamedScope{packageTypeOrMember.GraphNode, g}, true
			}
		}

		return SRGExternalPackageImport{packageInfo.packageInfo, resolutionName, g}, true
	}

	// Try to resolve as an imported package.
	importNode, importFound := parentModule.findImportByPackageName(name)
	if importFound {
		return SRGNamedScope{importNode, g}, true
	}

	return SRGNamedScope{}, false
}
コード例 #17
0
ファイル: packageloader.go プロジェクト: Serulian/compiler
// loadLocalPackage loads the package found at the path relative to the package directory.
func (p *PackageLoader) loadLocalPackage(packagePath pathInformation) {
	// Ensure the directory exists.
	if ok, _ := exists(packagePath.path); !ok {
		p.errors <- compilercommon.SourceErrorf(packagePath.sal, "Could not find directory '%s'", packagePath.path)
		return
	}

	// Read the contents of the directory.
	directoryContents, err := ioutil.ReadDir(packagePath.path)
	if err != nil {
		p.errors <- compilercommon.SourceErrorf(packagePath.sal, "Could not load directory '%s'", packagePath.path)
		return
	}

	// Add the package information to the map.
	packageInfo := &PackageInfo{
		kind:        packagePath.sourceKind,
		referenceId: packagePath.referenceId,
		modulePaths: make([]compilercommon.InputSource, 0),
	}

	// Load the handler for the package.
	handler, hasHandler := p.handlers[packagePath.sourceKind]
	if !hasHandler {
		log.Fatalf("Missing handler for source file of kind: [%v]", packagePath.sourceKind)
	}

	// Find all source files in the directory and add them to the paths list.
	var fileFound bool
	for _, fileInfo := range directoryContents {
		if path.Ext(fileInfo.Name()) == handler.PackageFileExtension() {
			fileFound = true
			filePath := path.Join(packagePath.path, fileInfo.Name())
			p.pushPath(pathSourceFile, packagePath.sourceKind, filePath, packagePath.sal)

			// Add the source file to the package information.
			packageInfo.modulePaths = append(packageInfo.modulePaths, compilercommon.InputSource(filePath))
		}
	}

	p.packageMap.Add(packagePath.sourceKind, packagePath.referenceId, *packageInfo)
	if !fileFound {
		p.warnings <- compilercommon.SourceWarningf(packagePath.sal, "Package '%s' has no source files", packagePath.path)
		return
	}
}
コード例 #18
0
ファイル: lex_test.go プロジェクト: Serulian/compiler
func TestLexerPositioning(t *testing.T) {
	text := `this.foo // some comment
class SomeClass`

	l := lex(compilercommon.InputSource("position test"), text)
	checkNext(t, l, text, lexeme{tokenTypeKeyword, 0, "this"}, 0, 0)
	checkNext(t, l, text, lexeme{tokenTypeDotAccessOperator, 4, "."}, 0, 4)
	checkNext(t, l, text, lexeme{tokenTypeIdentifer, 5, "foo"}, 0, 5)
	checkNext(t, l, text, lexeme{tokenTypeWhitespace, 8, " "}, 0, 8)
	checkNext(t, l, text, lexeme{tokenTypeSinglelineComment, 9, "// some comment"}, 0, 9)

	checkNext(t, l, text, lexeme{tokenTypeSyntheticSemicolon, 24, "\n"}, 0, 24)

	checkNext(t, l, text, lexeme{tokenTypeKeyword, 25, "class"}, 1, 0)
	checkNext(t, l, text, lexeme{tokenTypeWhitespace, 30, " "}, 1, 5)
	checkNext(t, l, text, lexeme{tokenTypeIdentifer, 31, "SomeClass"}, 1, 6)
	checkNext(t, l, text, lexeme{tokenTypeEOF, 40, ""}, 1, 15)
}
コード例 #19
0
// scopeStructuralNewExpressionEntry scopes a single entry in a structural new expression.
func (sb *scopeBuilder) scopeStructuralNewExpressionEntry(node compilergraph.GraphNode, context scopeContext) proto.ScopeInfo {
	parentNode := node.GetIncomingNode(parser.NodeStructuralNewExpressionChildEntry)
	parentExprScope := sb.getScope(parentNode.GetNode(parser.NodeStructuralNewTypeExpression), context)

	parentType := parentExprScope.StaticTypeRef(sb.sg.tdg)
	if parentExprScope.GetKind() == proto.ScopeKind_VALUE {
		parentType = parentExprScope.ResolvedTypeRef(sb.sg.tdg)
	}

	entryName := node.Get(parser.NodeStructuralNewEntryKey)

	// Get the scope for the value.
	valueScope := sb.getScope(node.GetNode(parser.NodeStructuralNewEntryValue), context)
	if !valueScope.GetIsValid() {
		return newScope().Invalid().GetScope()
	}

	// Lookup the member associated with the entry name.
	module := compilercommon.InputSource(node.Get(parser.NodePredicateSource))
	member, rerr := parentType.ResolveAccessibleMember(entryName, module, typegraph.MemberResolutionInstance)
	if rerr != nil {
		sb.decorateWithError(node, "%v", rerr)
		return newScope().Invalid().GetScope()
	}

	// Ensure the member is assignable.
	if member.IsReadOnly() {
		sb.decorateWithError(node, "%v %v under type %v is read-only", member.Title(), member.Name(), parentType)
		return newScope().Invalid().GetScope()
	}

	// Get the member's assignable type, transformed under the parent type, and ensure it is assignable
	// from the type of the value.
	assignableType := member.AssignableType().TransformUnder(parentType)
	valueType := valueScope.ResolvedTypeRef(sb.sg.tdg)

	if aerr := valueType.CheckSubTypeOf(assignableType); aerr != nil {
		sb.decorateWithError(node, "Cannot assign value of type %v to %v %v: %v", valueType, member.Title(), member.Name(), aerr)
		return newScope().Invalid().GetScope()
	}

	return newScope().ForNamedScope(sb.getNamedScopeForMember(member), context).Valid().GetScope()
}
コード例 #20
0
ファイル: scope_op_expr.go プロジェクト: Serulian/compiler
// scopeBinaryExpression scopes a binary expression in the SRG.
func (sb *scopeBuilder) scopeBinaryExpression(node compilergraph.GraphNode, opName string, context scopeContext) *scopeInfoBuilder {
	// Get the scope of the left and right expressions.
	leftScope := sb.getScope(node.GetNode(parser.NodeBinaryExpressionLeftExpr), context)
	rightScope := sb.getScope(node.GetNode(parser.NodeBinaryExpressionRightExpr), context)

	// Ensure that both scopes are valid.
	if !leftScope.GetIsValid() || !rightScope.GetIsValid() {
		return newScope().Invalid()
	}

	// Ensure that both scopes have the same type.
	leftType := leftScope.ResolvedTypeRef(sb.sg.tdg)
	rightType := rightScope.ResolvedTypeRef(sb.sg.tdg)

	if leftType != rightType {
		sb.decorateWithError(node, "Operator '%v' requires operands of the same type. Found: '%v' and '%v'", opName, leftType, rightType)
		return newScope().Invalid()
	}

	// Ensure that the operator exists under the resolved type.
	module := compilercommon.InputSource(node.Get(parser.NodePredicateSource))
	operator, rerr := leftType.ResolveAccessibleMember(opName, module, typegraph.MemberResolutionOperator)
	if rerr != nil {
		sb.decorateWithError(node, "Operator '%v' is not defined on type '%v'", opName, leftType)
		return newScope().Invalid()
	}

	returnType, _ := operator.ReturnType()

	// Check for nullable values.
	if leftType.NullValueAllowed() {
		sb.decorateWithError(node, "Cannot invoke operator '%v' on nullable type '%v'", opName, leftType)
		return newScope().Invalid().CallsOperator(operator).Resolving(returnType.TransformUnder(leftType))
	}

	if rightType.NullValueAllowed() {
		sb.decorateWithError(node, "Cannot invoke operator '%v' on nullable type '%v'", opName, rightType)
		return newScope().Invalid().CallsOperator(operator).Resolving(returnType.TransformUnder(leftType))
	}

	return newScope().Valid().CallsOperator(operator).Resolving(returnType.TransformUnder(leftType))
}
コード例 #21
0
// scopeStructuralNewTypeExpression scopes a structural new expression for constructing a new instance
// of a structural or class type.
func (sb *scopeBuilder) scopeStructuralNewTypeExpression(node compilergraph.GraphNode, childScope *proto.ScopeInfo, context scopeContext) proto.ScopeInfo {
	// Retrieve the static type.
	staticTypeRef := childScope.StaticTypeRef(sb.sg.tdg)

	// Ensure that the static type is a struct OR it is a class with an accessible 'new'.
	staticType := staticTypeRef.ReferredType()
	switch staticType.TypeKind() {
	case typegraph.ClassType:
		// Classes can only be constructed structurally if they are in the same module as this call.
		// Otherwise, an exported constructor must be used.
		module := compilercommon.InputSource(node.Get(parser.NodePredicateSource))
		_, rerr := staticTypeRef.ResolveAccessibleMember("new", module, typegraph.MemberResolutionStatic)
		if rerr != nil {
			sb.decorateWithError(node, "Cannot structurally construct type %v, as it is imported from another module", staticTypeRef)
			return newScope().Invalid().Resolving(staticTypeRef).GetScope()
		}

	case typegraph.StructType:
		// Structs can be constructed by anyone, assuming that their members are all exported.
		// That check occurs below.
		break

	default:
		sb.decorateWithError(node, "Cannot structurally construct type %v", staticTypeRef)
		return newScope().Invalid().Resolving(staticTypeRef).GetScope()
	}

	encountered, isValid := sb.scopeStructuralNewEntries(node, context)
	if !isValid {
		return newScope().Invalid().Resolving(staticTypeRef).GetScope()
	}

	// Ensure that all required entries are present.
	for _, field := range staticType.RequiredFields() {
		if _, ok := encountered[field.Name()]; !ok {
			isValid = false
			sb.decorateWithError(node, "Non-nullable %v '%v' is required to construct type %v", field.Title(), field.Name(), staticTypeRef)
		}
	}

	return newScope().IsValid(isValid).Resolving(staticTypeRef).GetScope()
}
コード例 #22
0
ファイル: sourcemap.go プロジェクト: Serulian/compiler
func getMapping(dom codedom.StatementOrExpression, positionMapper *compilercommon.PositionMapper) (sourcemap.SourceMapping, bool) {
	basisNode := dom.BasisNode()
	inputSource, hasInputSource := basisNode.TryGet(parser.NodePredicateSource)
	if !hasInputSource {
		return sourcemap.SourceMapping{}, false
	}

	startRune := basisNode.GetValue(parser.NodePredicateStartRune).Int()
	originalLine, originalCol, err := positionMapper.Map(compilercommon.InputSource(inputSource), startRune)
	if err != nil {
		panic(err)
	}

	var name = ""
	if named, ok := dom.(codedom.Named); ok {
		name = named.ExprName()
	}

	return sourcemap.SourceMapping{inputSource, originalLine, originalCol, name}, true
}
コード例 #23
0
ファイル: scope_sml_expr.go プロジェクト: Serulian/compiler
// scopeSmlNormalAttribute scopes an SML expression attribute under a declaration.
func (sb *scopeBuilder) scopeSmlAttribute(node compilergraph.GraphNode, propsType typegraph.TypeReference, context scopeContext) (string, bool) {
	attributeName := node.Get(parser.NodeSmlAttributeName)

	// If the props type is a struct or class, ensure that the attribute name exists.
	var allowedValueType = sb.sg.tdg.AnyTypeReference()
	if propsType.IsRefToStruct() || propsType.IsRefToClass() {
		module := compilercommon.InputSource(node.Get(parser.NodePredicateSource))
		resolvedMember, rerr := propsType.ResolveAccessibleMember(attributeName, module, typegraph.MemberResolutionInstance)
		if rerr != nil {
			sb.decorateWithError(node, "%v", rerr)
			return attributeName, false
		}

		allowedValueType = resolvedMember.AssignableType()
	} else {
		// The props type must be a mapping, so the value must match it value type.
		allowedValueType = propsType.Generics()[0]
	}

	// Scope the attribute value (if any). If none, then we default to a boolean value.
	var attributeValueType = sb.sg.tdg.BoolTypeReference()

	valueNode, hasValueNode := node.TryGetNode(parser.NodeSmlAttributeValue)
	if hasValueNode {
		attributeValueScope := sb.getScope(valueNode, context)
		if !attributeValueScope.GetIsValid() {
			return attributeName, false
		}

		attributeValueType = attributeValueScope.ResolvedTypeRef(sb.sg.tdg)
	}

	// Ensure it matches the assignable value type.
	if serr := attributeValueType.CheckSubTypeOf(allowedValueType); serr != nil {
		sb.decorateWithError(node, "Cannot assign value of type %v for attribute %v: %v", attributeValueType, attributeName, serr)
		return attributeName, false
	}

	return attributeName, true
}
コード例 #24
0
ファイル: formatter.go プロジェクト: Serulian/compiler
// parseAndFormatSourceFile parses the source file at the given path (with associated file info),
// formats it and, if changed, writes it back to that path.
func parseAndFormatSourceFile(sourceFilePath string, info os.FileInfo, importHandling importHandlingInfo) error {
	// Load the source from the file.
	source, err := ioutil.ReadFile(sourceFilePath)
	if err != nil {
		return err
	}

	// Conduct the parsing.
	parseTree := newParseTree(source)
	inputSource := compilercommon.InputSource(sourceFilePath)
	rootNode := parser.Parse(parseTree.createAstNode, nil, inputSource, string(source))

	// Report any errors found.
	if len(parseTree.errors) > 0 {
		for _, err := range parseTree.errors {
			startRune, _ := strconv.Atoi(err.properties[parser.NodePredicateStartRune])
			sal := compilercommon.NewSourceAndLocation(inputSource, startRune)
			location := sal.Location()

			fmt.Printf("%v: line %v, column %v: %s\n",
				sourceFilePath,
				location.LineNumber()+1,
				location.ColumnPosition()+1,
				err.properties[parser.NodePredicateErrorMessage])
		}

		return fmt.Errorf("Parsing errors found in file %s", sourceFilePath)
	}

	// Create the formatted source.
	formattedSource := buildFormattedSource(parseTree, rootNode.(formatterNode), importHandling)
	if string(formattedSource) == string(source) {
		// Nothing changed.
		return nil
	}

	// Overwrite the file with the formatted source.
	return ioutil.WriteFile(sourceFilePath, formattedSource, info.Mode())
}
コード例 #25
0
ファイル: packages.go プロジェクト: Serulian/compiler
// getPackageForImport returns the package information for the package imported by the given import
// package node.
func (g *SRG) getPackageForImport(importPackageNode compilergraph.GraphNode) importedPackage {
	importNode := importPackageNode.GetIncomingNode(parser.NodeImportPredicatePackageRef)

	// Note: There may not be a kind, in which case this will return empty string, which is the
	// default kind.
	packageKind, _ := importNode.TryGet(parser.NodeImportPredicateKind)
	packageLocation := importNode.Get(parser.NodeImportPredicateLocation)

	packageInfo, ok := g.packageMap.Get(packageKind, packageLocation)
	if !ok {
		source := importNode.Get(parser.NodeImportPredicateSource)
		subsource, _ := importPackageNode.TryGet(parser.NodeImportPredicateSubsource)
		panic(fmt.Sprintf("Missing package info for import %s %s (reference %v) (node %v)\nPackage Map: %v",
			source, subsource, packageLocation, importNode, g.packageMap))
	}

	return importedPackage{
		srg:          g,
		packageInfo:  packageInfo,
		importSource: compilercommon.InputSource(importPackageNode.Get(parser.NodePredicateSource)),
	}
}
コード例 #26
0
ファイル: typereference.go プロジェクト: Serulian/compiler
// ResolveAccessibleMember looks for an member with the given name under the referred type and returns it (if any).
func (tr TypeReference) ResolveAccessibleMember(memberName string, modulePath compilercommon.InputSource, kind MemberResolutionKind) (TGMember, error) {
	member, found := tr.ResolveMember(memberName, kind)
	if !found {
		adjusted := tr.tdg.adjustedName(memberName)
		_, otherSpellingFound := tr.ResolveMember(adjusted, kind)
		if otherSpellingFound {
			return TGMember{}, fmt.Errorf("Could not find %v name '%v' under %v; Did you mean '%v'?", kind.Title(), memberName, tr.TitledString(), adjusted)
		}

		return TGMember{}, fmt.Errorf("Could not find %v name '%v' under %v", kind.Title(), memberName, tr.TitledString())
	}

	// If the member is exported, then always return it. Otherwise, only return it if the asking module's package
	// is the same as the declaring module's package.
	if !member.IsExported() {
		memberModulePath := compilercommon.InputSource(member.Node().Get(NodePredicateModulePath))
		if !srg.InSamePackage(memberModulePath, modulePath) {
			return TGMember{}, fmt.Errorf("%v %v is not exported under %v", member.Title(), member.Name(), tr.TitledString())
		}
	}

	return member, nil
}
コード例 #27
0
ファイル: scope_op_expr.go プロジェクト: Serulian/compiler
// scopeSliceChildExpression scopes the child expression of a slice expression, returning whether it
// is valid and the associated operator found, if any.
func (sb *scopeBuilder) scopeSliceChildExpression(node compilergraph.GraphNode, opName string, context scopeContext) (typegraph.TGMember, typegraph.TypeReference, bool) {
	// Scope the child expression of the slice.
	childScope := sb.getScope(node.GetNode(parser.NodeSliceExpressionChildExpr), context)
	if !childScope.GetIsValid() {
		return typegraph.TGMember{}, sb.sg.tdg.AnyTypeReference(), false
	}

	childType := childScope.ResolvedTypeRef(sb.sg.tdg)
	module := compilercommon.InputSource(node.Get(parser.NodePredicateSource))
	operator, rerr := childType.ResolveAccessibleMember(opName, module, typegraph.MemberResolutionOperator)
	if rerr != nil {
		sb.decorateWithError(node, "Operator '%v' is not defined on type '%v'", opName, childType)
		return typegraph.TGMember{}, childType, false
	}

	// Ensure that the child expression is not nullable.
	if childType.NullValueAllowed() {
		sb.decorateWithError(node, "Operator '%v' cannot be called on nullable type '%v'", opName, childType)
		return typegraph.TGMember{}, childType, false
	}

	return operator, childType, true
}
コード例 #28
0
// scopeDynamicMemberAccessExpression scopes a dynamic member access expression in the SRG.
func (sb *scopeBuilder) scopeDynamicMemberAccessExpression(node compilergraph.GraphNode, context scopeContext) proto.ScopeInfo {
	// Get the scope of the child expression.
	childScope := sb.getScope(node.GetNode(parser.NodeMemberAccessChildExpr), context)
	if !childScope.GetIsValid() {
		return newScope().Invalid().GetScope()
	}

	memberName := node.Get(parser.NodeMemberAccessIdentifier)
	module := compilercommon.InputSource(node.Get(parser.NodePredicateSource))

	scopeMemberAccess := func(childType typegraph.TypeReference, expectStatic bool) proto.ScopeInfo {
		// If the child type is any, then this operator returns another value of any, regardless of name.
		if childType.IsAny() {
			return newScope().Valid().Resolving(sb.sg.tdg.AnyTypeReference()).GetScope()
		}

		var lookupType = childType
		if childType.IsNullable() {
			lookupType = childType.AsNonNullable()
		}

		// Look for the matching type member, either instance or static. If not found, then the access
		// returns an "any" type.
		typeMember, rerr := lookupType.ResolveAccessibleMember(memberName, module, typegraph.MemberResolutionInstanceOrStatic)
		if rerr != nil {
			return newScope().Valid().Resolving(sb.sg.tdg.AnyTypeReference()).GetScope()
		}

		// Ensure static isn't accessed under instance and vice versa.
		if typeMember.IsStatic() != expectStatic {
			if typeMember.IsStatic() {
				sb.decorateWithError(node, "Member '%v' is static but accessed under an instance value", typeMember.Name())
			} else {
				sb.decorateWithError(node, "Member '%v' is non-static but accessed under a static value", typeMember.Name())
			}
			return newScope().Invalid().GetScope()
		}

		// The resulting type (if matching a named scope) is the named scope, but also nullable (since the operator)
		// allows for nullable types.
		memberScope := sb.getNamedScopeForMember(typeMember)
		context.staticDependencyCollector.checkNamedScopeForDependency(memberScope)

		if childType.IsNullable() {
			sb.decorateWithWarning(node, "Dynamic access of known member '%v' under type %v. The ?. operator is suggested.", typeMember.Name(), childType)
			return newScope().ForNamedScopeUnderModifiedType(memberScope, lookupType, makeNullable, context).GetScope()
		} else {
			sb.decorateWithWarning(node, "Dynamic access of known member '%v' under type %v. The . operator is suggested.", typeMember.Name(), childType)
			return newScope().ForNamedScopeUnderType(memberScope, lookupType, context).GetScope()
		}
	}

	switch childScope.GetKind() {
	case proto.ScopeKind_VALUE:
		childType := childScope.ResolvedTypeRef(sb.sg.tdg)
		return scopeMemberAccess(childType, false)

	case proto.ScopeKind_STATIC:
		namedScope, _ := sb.getNamedScopeForScope(childScope)
		if !namedScope.IsType() {
			sb.decorateWithError(node, "Cannot attempt dynamic member access of '%v' under %v %v, as it is not a type", memberName, namedScope.Title(), namedScope.Name())
			return newScope().Invalid().GetScope()
		}

		childType := namedScope.StaticType(context)
		return scopeMemberAccess(childType, true)

	case proto.ScopeKind_GENERIC:
		namedScope, _ := sb.getNamedScopeForScope(childScope)
		sb.decorateWithError(node, "Cannot attempt dynamic member access of '%v' under %v %v, as it is generic without specification", memberName, namedScope.Title(), namedScope.Name())
		return newScope().Invalid().GetScope()

	default:
		panic("Unknown scope kind")
	}

	return newScope().Invalid().GetScope()
}
コード例 #29
0
func TestLookupReturnType(t *testing.T) {
	graph, err := compilergraph.NewGraph("tests/returntype/returntype.seru")
	if !assert.Nil(t, err, "Got graph creation error: %v", err) {
		return
	}

	testSRG := srg.NewSRG(graph)
	testIDL := webidl.NewIRG(graph)

	loader := packageloader.NewPackageLoader(graph.RootSourceFilePath, []string{}, testSRG.PackageLoaderHandler(), testIDL.PackageLoaderHandler())

	srgResult := loader.Load(packageloader.Library{TESTLIB_PATH, false, ""})
	if !assert.True(t, srgResult.Status, "Got error for SRG construction: %v", srgResult.Errors) {
		return
	}

	// Construct the type graph.
	result := typegraph.BuildTypeGraph(testSRG.Graph, GetConstructor(testSRG), webidltc.GetConstructor(testIDL))
	if !assert.True(t, result.Status, "Got error for TypeGraph construction: %v", result.Errors) {
		return
	}

	// Ensure that the function and the property getter have return types.
	module, found := testSRG.FindModuleBySource(compilercommon.InputSource("tests/returntype/returntype.seru"))
	if !assert.True(t, found, "Could not find source module") {
		return
	}

	resolvedclass, foundClass := module.ResolveTypePath("SomeClass")
	if !assert.True(t, foundClass, "Could not find SomeClass") {
		return
	}

	someclass := resolvedclass.ResolvedType.AsType()

	// Check the function.
	dosomethingFunc, foundFunc := someclass.FindMember("DoSomething")
	if !assert.True(t, foundFunc, "Could not find DoSomething") {
		return
	}

	dosomethingFuncReturnType, hasReturnType := result.Graph.LookupReturnType(dosomethingFunc.Node())
	if !assert.True(t, hasReturnType, "Could not find return type for DoSomething") {
		return
	}

	assert.Equal(t, "Integer", dosomethingFuncReturnType.String(), "Expected int for DoSomething return type, found: %v", dosomethingFuncReturnType)

	// Check the property getter.
	someProp, foundProp := someclass.FindMember("SomeProp")
	if !assert.True(t, foundProp, "Could not find SomeProp") {
		return
	}

	getter, _ := someProp.Getter()
	somePropReturnType, hasPropReturnType := result.Graph.LookupReturnType(getter.GraphNode)
	if !assert.True(t, hasPropReturnType, "Could not find return type for SomeProp getter") {
		return
	}

	assert.Equal(t, "SomeClass", somePropReturnType.String(), "Expected SomeClass for SomeProp return type, found: %v", somePropReturnType)
}
コード例 #30
0
ファイル: util.go プロジェクト: Serulian/compiler
// salForNode returns a SourceAndLocation for the given graph node.
func salForNode(node compilergraph.GraphNode) compilercommon.SourceAndLocation {
	return compilercommon.NewSourceAndLocation(
		compilercommon.InputSource(node.Get(parser.NodePredicateSource)),
		node.GetValue(parser.NodePredicateStartRune).Int())
}