-
Notifications
You must be signed in to change notification settings - Fork 87
Modules Notes
-
We conflate modules and compilation units. That is, each file
f.p4
is module. -
Files are searched in a standard order -- e.g., according to an environment variable like
$P4PATH
and/or command-line arguments to thep4c
compiler.-
It would be simplest to restrict that for every name
foo
, importing modulefoo
will always correspond to the filefoo.p4
in the first directory of$P4PATH
that contains such a file, ignoring any identically named files in later directories of$P4PATH
. Also, for a single execution of the compiler, there is only one value for$P4PATH
, i.e. no way to temporarily modify$P4PATH
for part of the compilation run, or when compiling some modules vs. other modules. -
Should
import foo.bar
be allowed, and become searching for a filefoo/bar.p4
inside of a directory in$P4PATH
? -
A question was raised about dealing with multiple versions of the same module, with different versions imported from different other modules, e.g. top level program A imports modules B and C. B imports module D version 28, but C imports module D version 31. Proposal: If someone has specific ideas on how to address this, please describe them. It is far simpler to just require that for every module name, there is a single version of it that is first in
$P4PATH
, no matter where it is imported from, and the P4 developer is responsible for arranging that it is the version they want to use everywhere in their program. I am not aware of any language with modules that has a good answer to using multiple versions of the same library/module from different parts of a program, other than explicitly giving them different names from each other, e.g. D_version_28 and D_version_31.
-
-
We still run
cpp
over each file before loading. However, this will be discouraged, and we hope soon become unnecessary. -
We import modules by name in a P4 Program.
import f; // can now reference f.x and f.y
import f as g; // can now reference g.x and g.y, especially handy if instead of 'f' it is 'some_very_long_module_name'
from f import x,y; // can now reference x and y
from f import x as a, y as b; // can now reference f.x using name a, and f.b using name b
from f import *; // @jafingerhut argues against this. // However, this would let us say that the compiler automagically does `from core import *` // We could consider making core, and perhaps also one architecture per program, as a special // case that behaves like `from core import *`, but still not let the P4 developer write // `from foo import *` for any other modules.
-
A few issues to think about:
-
Do we write
import core
? Or do we just automatically import and open that module? -
Do we write
import v1model
?- Could specify architecture on the command-line and automagically import, like
core
?
... counter(1024) c; ... switch( ... ) main;
- Could specify the architecture on the command-line but manually import architecture
import psa ... psa.counter(1024) c; ... psa.switch( ... ) main;
- Could specify the architecture on the command-line but automagically import with a wildcard
from psa import * ... counter(1024) c; ... switch( ... ) main;
- Could include using
cpp
directives
#include<psa.p4> ... counter(1024) c; ... switch( ... ) main;
- Could specify architecture on the command-line and automagically import, like
-
-
Circular dependencies between compilation units not allowed
-
import statements are definitely supported at the top level of the code. Proposal: It seems reasonable to disallow them anywhere except at the top level of a program, e.g. they are not permitted inside the body of a parser or control.
-
Proposal: Explicitly support an arbitrary directed acyclic graph structure of imports between modules in a single compilation run, i.e. compiling A, which imports B, C, and D, and all of B, C, and D import E (perhaps with different aliases for each) should be allowed.
- Does it ever make sense for the instantiation of
main
to be anywhere other than A, the file name / module that one directly invokes the compiler on? Anything after that instantiation seems like it cannot affect the behavior of earlier code, so seems like it must be dead code to me. P4 has no forward declarations. - Should a module that is imported be allowed to have top level instantiations of extern objects, parsers, controls, or packages? Proposal: Yes. If yes, and if a module like E in the example above is imported from multiple other places has such instantiations, should that imply exactly one instantiation of each of those objects, or once for each time that E is imported (3 in the example above)? Proposal: Exactly one instantiation seems simpler to implement and reason about, and still useful.
- Does it ever make sense for the instantiation of
-
Should A be allowed to have multiple import statements for the same module B? If so, what does that mean? Proposal: It is allowed, and simply creates more aliases for the same objects of B inside of A. In the directed acyclic graph described in the issue above, it is simply multiple edges from A to B.