DLX-Microprocessor / scripts / utils / pupi_source_files / pupi.go
pupi.go
Raw
package main

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"slices"
	"strings"
)

// the basics is that every file that needs a component
// is put in a wating line until all it's requests are
// satisfied

type node struct {
	Name      string
	Got, Want map[string]struct{}
}

func main() {
	content, err := io.ReadAll(os.Stdin)
	if err != nil {
		panic(err)
	}
	files := strings.Split(string(content), "\n")
	nodes := make([]*node, 0, len(files))
	for _, name := range files {
		if strings.TrimSpace(name) == "" {
			continue
		}

		nn := &node{
			Name: name,
			Got:  map[string]struct{}{},
			Want: map[string]struct{}{},
		}

		f, err := os.Open(name)
		if err != err {
			panic(err)
		}

		s := bufio.NewScanner(f)

		// need to add priority to the packages
		// Types of files
		// Package only with constants => no entities found first to compile (No Got no Want => can bbe directly compiled)
		// Package with entities => need to sweep for entites and functions (Surely has Got and can have Want)
		// Entity => if no components needed has only Got but can request some packages for constants
		// Top Entity => can request other components "entities" has Want and less got

		// we can sweep if package or not, in general:
		// we see what entities declaration has and we put in the got
		// we see what components needs and put in the want
		// extra: we see what functions declares and put in the got
		// extra: we see what functions needs and put in the want
		// if no Want and no Got we output it (is a package with only constants)

		for s.Scan() {
			line := s.Text()
			line = strings.ToLower(line)

			// we need only the declatarions
			if strings.Contains(line, ";") {
				continue
			}

			ff := strings.Fields(line)

			if len(ff) == 0 {
				continue
			}

			// the component keyword means a request => thus a Want
			if idx := slices.Index(ff, "component"); idx != -1 {
				name := ff[idx+1]
				nn.Want[name] = struct{}{}
				continue
			}

			// the entity keyword means an entity declaration => thus a got
			if idx := slices.Index(ff, "entity"); idx != -1 {
				name := ff[idx+1]
				nn.Got[name] = struct{}{}
				continue
			}

			//If nothing found it will have Want and Got empty
		}
		nodes = append(nodes, nn)
	}

	//first we remove the ones without requests
	todel := []*node{}

	for _, nn := range nodes {
		// Simple package type
		if nn != nil {
			if len(nn.Want) == 0 && len(nn.Got) == 0 {
				// compile it
				fmt.Println(nn.Name)
				todel = append(todel, nn)
				// Delete the actual compiled node
				nodes = slices.DeleteFunc(nodes, func(n *node) bool { return slices.Contains(todel, n) })
			}
		}
	}

	// We iterate ass long as there is a file with a want
	// at each iteration we compile the nodes with only got
	// instances
	for {
		if len(nodes) == 0 {
			break
		}
		todel := []*node{}

		for _, nn := range nodes {
			// Exclude the top level entity
			if len(nn.Want) != 0 {
				continue
			}

			// We only give out things so we compile and erase from the
			// consumers
			if len(nn.Want) == 0 {
				fmt.Println(nn.Name)
			}

			todel = append(todel, nn)
			// delete from the other nodes what i just have compiled
			for _, consumer := range nodes {
				for what := range nn.Got {
					delete(consumer.Want, what)
				}
			}
		}
		// Delete the actual compiled node
		nodes = slices.DeleteFunc(nodes, func(n *node) bool { return slices.Contains(todel, n) })
	}

}