Skip to content

Modules Notes

Andy Fingerhut edited this page May 8, 2019 · 16 revisions

Design

  • 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 the p4c compiler.

    • It would be simplest to restrict that for every name foo, importing module foo will always correspond to the file foo.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.
  • 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
    
    from f import x,y;
    // can now reference x and y
    
    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 ?

      1. Could specify architecture on the command-line and automagically import, like core?
      ...
      counter(1024) c;
      ...
      switch( ... ) main;
      
      1. Could specify the architecture on the command-line but manually import architecture
      import psa
      ...
      psa.counter(1024) c;
      ...
      psa.switch( ... ) main;
      
      1. Could specify the architecture on the command-line but automagically import with a wildcard
      from psa import *
      ...
      counter(1024) c;
      ...
      switch( ... ) main;
      
      1. Could include using cpp directives
      #include<psa.p4>
      ...
      counter(1024) c;
      ...
      switch( ... ) main;
      
  • 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.
  • 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.

Clone this wiki locally