Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modules #36

Open
dvanhorn opened this issue Feb 16, 2021 · 2 comments
Open

Modules #36

dvanhorn opened this issue Feb 16, 2021 · 2 comments
Assignees
Labels
enhancement New feature or request

Comments

@dvanhorn
Copy link
Member

It should be possible to write modular programs rather than just single monolithic programs. A module is a program that imports some identifiers via require and possibly exports some identifiers with provide. The compiler ought to support separate compilation, meaning we might have one module in "f.rkt":

#lang racket
(provide f)
(define (f x)
  (+ x x))

which can be compiled (to say "f.o").

And another module which uses it:

#lang racket
(require "f.rkt")
(f 5)

which can be compiled without needing to recompile "f.rkt".

It should be possible to follow the design of the standard library feature to implement this, although there will be several added wrinkles in the front end (the client of a module will need to fetch a list of provided identifiers etc.). I'm also not exactly sure how to handle building and linking dependencies when compiling a module.

@dvanhorn dvanhorn added the enhancement New feature or request label Feb 16, 2021
@dandorat dandorat self-assigned this Feb 16, 2021
@dandorat
Copy link
Contributor

Can the rules for making the .o files for all the modules be added to the Makefile and the object files all be loaded at run-time similar to the libraries? Or should the object files be created and put in a list by some additional code in compile-file.rkt by going through all the imports in the program and then the object files in this list be combined into a library which then is linked by the Makefile?

@dandorat
Copy link
Contributor

dandorat commented Feb 21, 2021

Implemented modules by adding the following:

  1. a modules.rkt file
  2. a C file (formdps.c)
  3. changes in Makefile to call formdps.c which then via a system call invokes make again (to allow the module dependencies to be calculated in modules.rkt to produce a list of .o files of the needed modules and also to compile the .s files of the modules in this step before the rest of the recipe in the Makefile is carried out)
  4. changes in ast.rkt, parse.rkt, compile-file.rkt, externs.rkt, and compile.rkt.

modules.rkt calculates and stores the directed graph of module dependencies. If there is a cycle in this graph, modules.rkt detects this and produces an error.

Currently, the following formats for the modules are supported:

  1. (begin (provide "filename.rkt" ...) (require "filename.rkt" ...) defines)
  2. (begin (require "filename.rkt" ...) defines)
  3. (begin (provide "filename.rkt" ...) (require "filename.rkt" ...) defines e)
  4. (begin (require "filename.rkt" ...) defines e)

Example modules exmod0.rkt, exmod1.rkt, exmod2.rkt, exmod3.rkt, and exmod4.rkt added.

Exmod0.rkt has the format (begin (require "filename.rkt" ...) defines e) and in this example it is used as the root file to be compiled and for the expression e to be evaluated.

If a module is the root file, the expression e is included in the compilation. But if a module is not the root file and it has formats 3 and 4, during the compilation the information on imports and exports is included in the compilation, and the defines are compiled, but the expression e is not compiled.

Example Run

Executing make exmod0.run will first run the command racket -t compile-file.rkt -m exmod0.rkt > exmod0.s. During this, compile-file.rkt calls modules.rkt, which calculates module dependencies, does the compilation of the .s files for the other modules so that compile-file.rkt is not called for them later by the Makefile, and writes the names of the .o files for the modules that need to be created in a file called modulefiles.

Then, the following are done:

  1. nasm -f $(format) -o exmod0.o exmod0.s to form exmod0.o
  2. ./formdps.c make exmod0.run to make a system call: make exmod0.run2
  3. Then by the recipe for %.run2 in the Makefile, the following files are created: the .o files for the rest of the modules (based on the list in modulefiles), runtime.o, and the executable exmod0.run2
  4. ./formdps.c mv exmod0.run2 to rename exmod0.run2 to exmod0.run.

Then, running the executable ./exmod0.run will produce the correct result 10.

A file called modulesgraph is also created by modules.rkt recording the directed graph of module dependencies in adjacency list format.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants