civboot / fngi

a readable language that grows from the silicon
The Unlicense
59 stars 3 forks source link

build system #14

Open vitiral opened 1 year ago

vitiral commented 1 year ago

This is to try and outline some of my ideas of how mod (modules) and pkg (packages) work together and are integrated into the build system.

A mod is a sub-class of TyDict which can have constants, functions, etc. It can also act as a "syn type" in that it can be used to dynamically create types depending on some arguments Arr[20, MyType]. Basically it is something the compiler itself understands and uses directly in the syntax of fngi.

Source files can add modules, modify modules, etc by using with syn function to affect "one token", or filewith:mod syn function at the top will make the whole file that module.

pkg is a different concept -- fundamentally it is just a config file which directs the compiler on how to compile a set of files. It is technically a fngi file, but anything defined in it does not affect anything outside the following global variables:

A typical .fnc (fngi config) for a pkg might look like (recall that fngi string syntax is |hello world|):

\ deps { ... } must be the first token.
\ It has it's own syntax that constructs Pkg objects
deps {
  |regex| \ same as: Pkg { name = |regex| }
  |zoa|
  Pkg { path = |subPkg/pkg.fsc| } \ local package

  \ pkgs accessible at build-time can be specified by
  \   setting build=true or buildOnly=true
  Pkg { name = |fsutil|,          buildOnly=true }
  Pkg { path = |buildHelper.fsc|, buildOnly=true }

  \ '+' can be used to access values or even call functions defined
  \ within build-time dependencies. The output must be
  \ an &Slc[Pkg].
  \ The + will not be accessed until all previous deps steps are complete
  + buildHelper.extraDeps
}

var _srcs: Arr[CStr] = {
  |types.fn|,
  |firstThing.fn|,
  |secondThing.fn|,
};

_srcs.extend(buildHelper.otherSrcs);

\ export srcs by making all src paths start with "src/"
var srcs: Arr(Slc) = fsutil.joinall(|src|, &_srcs);

\ Regular expressions of raw data files to include
var data: Arr(Slc) = fs.list(|data/.*|)

The compiler will construct the dependency tree and compile each package according to the DAG it creates. Once all the deps (and their deps, recursively) have been compiled it compiles the srcs in order.

Needless to say, this is a radical departure from how many programming languages handle their imports. Most have elaborate processes for how to discover dependencies. C gives an extraordinarily brute-force solution and simply expands all macros and imports for every source file. Like many other features of compiler design, fngi eschews these common practices in favor of the simplest possible approach -- simply compile the files in the order the programmer specifies. No magic. Fngi has to do this since all things in fngi are compiled immediately as they are discovered -- but regardless, it also makes things much simpler.

Because of this:


limitations

pkg's cannot create files -- they only read files and define state for building the pkg. Generating files / etc is the job of some other build system (i.e. make, bazel, scripts, etc) which civboot will define independent of fngi pkgs.