Exemplo n.º 1
0
Arquivo: main.go Projeto: vnev/ark
func parseFiles(inputs []string) ([]*parser.Module, *parser.ModuleLookup) {
	if len(inputs) != 1 {
		setupErr("Please specify only one file or module to build")
	}

	var modulesToRead []*parser.ModuleName
	var modules []*parser.Module
	moduleLookup := parser.NewModuleLookup("")
	depGraph := parser.NewDependencyGraph()

	input := inputs[0]
	if strings.HasSuffix(input, ".ark") {
		// Handle the special case of a single .ark file
		modname := &parser.ModuleName{Parts: []string{"__main"}}
		module := &parser.Module{
			Name:    modname,
			Dirpath: "",
		}
		moduleLookup.Create(modname).Module = module

		// Read
		sourcefile, err := lexer.NewSourcefile(input)
		if err != nil {
			setupErr("%s", err.Error())
		}

		// Lex
		sourcefile.Tokens = lexer.Lex(sourcefile)

		// Parse
		parsedFile, deps := parser.Parse(sourcefile)
		module.Trees = append(module.Trees, parsedFile)

		// Add dependencies to parse array
		for _, dep := range deps {
			depname := parser.NewModuleName(dep)
			modulesToRead = append(modulesToRead, depname)
			depGraph.AddDependency(modname, depname)
		}

		modules = append(modules, module)
	} else {
		if strings.ContainsAny(input, `\/. `) {
			setupErr("Invalid module name: %s", input)
		}

		modname := &parser.ModuleName{Parts: strings.Split(input, "::")}
		modulesToRead = append(modulesToRead, modname)
	}

	log.Timed("read/lex/parse phase", "", func() {
		for i := 0; i < len(modulesToRead); i++ {
			modname := modulesToRead[i]

			// Skip already loaded modules
			if _, err := moduleLookup.Get(modname); err == nil {
				continue
			}

			fi, dirpath := findModuleDir(*buildSearchpaths, modname.ToPath())
			if fi == nil {
				setupErr("Couldn't find module `%s`", modname)
			}

			if !fi.IsDir() {
				setupErr("Expected path `%s` to be directory, was file.", dirpath)
			}

			module := &parser.Module{
				Name:    modname,
				Dirpath: dirpath,
			}
			moduleLookup.Create(modname).Module = module

			// Check module children
			childFiles, err := ioutil.ReadDir(dirpath)
			if err != nil {
				setupErr("%s", err.Error())
			}

			for _, childFile := range childFiles {
				if strings.HasPrefix(childFile.Name(), ".") || !strings.HasSuffix(childFile.Name(), ".ark") {
					continue
				}

				actualFile := filepath.Join(dirpath, childFile.Name())

				// Read
				sourcefile, err := lexer.NewSourcefile(actualFile)
				if err != nil {
					setupErr("%s", err.Error())
				}

				// Lex
				sourcefile.Tokens = lexer.Lex(sourcefile)

				// Parse
				parsedFile, deps := parser.Parse(sourcefile)
				module.Trees = append(module.Trees, parsedFile)

				// Add dependencies to parse array
				for _, dep := range deps {
					depname := parser.NewModuleName(dep)
					modulesToRead = append(modulesToRead, depname)
					depGraph.AddDependency(modname, depname)
				}
			}

			modules = append(modules, module)
		}
	})

	// Check for cyclic dependencies (in modules)
	log.Timed("cyclic dependency check", "", func() {
		errs := depGraph.DetectCycles()
		if len(errs) > 0 {
			log.Errorln("main", "error: Encountered cyclic dependecies:")
			for _, cycle := range errs {
				log.Errorln("main", "%s", cycle)
			}
			os.Exit(util.EXIT_FAILURE_SETUP)
		}
	})

	// construction
	log.Timed("construction phase", "", func() {
		for _, module := range modules {
			parser.Construct(module, moduleLookup)

		}
	})

	return modules, moduleLookup
}
Exemplo n.º 2
0
func parseFiles(inputs []string) ([]*parser.Module, *parser.ModuleLookup) {
	var modulesToRead []*parser.ModuleName
	for _, input := range inputs {
		if strings.ContainsAny(input, `\/. `) {
			setupErr("Invalid module name: %s", input)
		}

		modname := &parser.ModuleName{Parts: strings.Split(input, "::")}
		modulesToRead = append(modulesToRead, modname)
	}

	var parsedFiles []*parser.ParseTree
	moduleLookup := parser.NewModuleLookup("")
	depGraph := parser.NewDependencyGraph()

	log.Timed("read/lex/parse phase", "", func() {
		for i := 0; i < len(modulesToRead); i++ {
			modname := modulesToRead[i]
			actualFile := filepath.Join(*buildBasedir, modname.ToPath())

			fi, err := os.Stat(actualFile + ".ark")
			shouldBeDir := false
			if os.IsNotExist(err) {
				fi, err = os.Stat(actualFile)
				shouldBeDir = true
			}

			if err != nil {
				setupErr("%s", err.Error())
			}

			if !fi.IsDir() && shouldBeDir {
				setupErr("Expected file `%s` to be directory, was file.", actualFile)
			}

			// Check lookup
			ll := moduleLookup.Create(modname)
			if ll.Tree == nil {
				if shouldBeDir {
					// Setup dummy parse tree
					ll.Tree = &parser.ParseTree{}
					ll.Tree.Name = modname

					// Setup dummy module
					ll.Module = &parser.Module{}
					ll.Module.Path = actualFile
					ll.Module.Name = modname
					ll.Module.GlobalScope = parser.NewGlobalScope()

					// Check module children
					childFiles, err := ioutil.ReadDir(actualFile)
					if err != nil {
						setupErr("%s", err.Error())
					}

					for _, childFile := range childFiles {
						if strings.HasPrefix(childFile.Name(), ".") {
							continue
						}

						if childFile.IsDir() || strings.HasSuffix(childFile.Name(), ".ark") {
							childmodname := parser.JoinModuleName(modname, strings.TrimSuffix(childFile.Name(), ".ark"))
							modulesToRead = append(modulesToRead, childmodname)

							ll.Module.GlobalScope.UsedModules[childmodname.Last()] = moduleLookup.Create(childmodname)
						}
					}
				} else {
					// Read
					sourcefile, err := lexer.NewSourcefile(actualFile + ".ark")
					if err != nil {
						setupErr("%s", err.Error())
					}

					// Lex
					sourcefile.Tokens = lexer.Lex(sourcefile)

					// Parse
					parsedFile, deps := parser.Parse(sourcefile)
					parsedFile.Name = modname

					parsedFiles = append(parsedFiles, parsedFile)
					ll.Tree = parsedFile

					// Add dependencies to parse array
					for _, dep := range deps {
						depname := parser.NewModuleName(dep)
						modulesToRead = append(modulesToRead, depname)
						depGraph.AddDependency(modname, depname)
					}
				}
			}
		}
	})

	// Check for cyclic dependencies (in modules)
	log.Timed("cyclic dependency check", "", func() {
		errs := depGraph.DetectCycles()
		if len(errs) > 0 {
			log.Errorln("main", "error: Encountered cyclic dependecies:")
			for _, cycle := range errs {
				log.Errorln("main", "%s", cycle)
			}
			os.Exit(util.EXIT_FAILURE_SETUP)
		}
	})

	hasMainFunc := false
	// construction
	var constructedModules []*parser.Module
	log.Timed("construction phase", "", func() {
		for _, file := range parsedFiles {
			mod := parser.Construct(file, moduleLookup)
			constructedModules = append(constructedModules, mod)

			// not terribly efficient, but it's best
			// to catch out earlier on if we have
			// a main function or not rather than
			// figuring out at the codegen phase??
			// maybe??
			// TODO FIXME MAKEPRETTY
			for _, node := range mod.Nodes {
				switch node := node.(type) {
				case *parser.FunctionDecl:
					if node.Function.Name == "main" {
						hasMainFunc = true
						break
					}
				default:
				}
			}
		}
	})

	// and here we check if we should
	// bother continuing any further...
	if !hasMainFunc {
		log.Error("main", util.Red("error: ")+"main function not found\n")
		os.Exit(1)
	}

	return constructedModules, moduleLookup
}