1.7. Header and body tags

Header and body statements may include tag names which can be refered to in requires clauses of binding definitions.

Tagged bodies and headers are only emitted if a used primitive type, constant, function or procedure requires them.

Untagged headers and bodies are tagged with the synthesised name _root. Every primitive function, procedure, type, or constant requires all visible untagged headers and bodies, that is, they all implicitly require _root.

Root requirements are inherited: each untagged header or body requires its parents _root (if it has one).

The effect is that if no primitives are used, no header or body code will be generated. If you really need to unconditionally force execution of some C code, you should be using the 'code' primitive. Header and body statements are intended for declarations and definitions.

The same tag can be used on more than one code insertion statements: this is typically useful on a header-body pair.

Start felix section to tut/examples/tut_bind135.flx[1 /1 ]
     1: #line 471 "./lpsrc/flx_tut_bind.pak"
     2: body "#include <stdio.h>";
     3: body xprint = "void printx(char *fmt, char *s) { printf(fmt,s);}";
     4: body printu = 'void print(char *s) { printx("%s\\n",s); }';
     5: 
     6: proc hello:1='print("Hello");' requires xprint, printu;
     7: hello;
     8: 
End felix section to tut/examples/tut_bind135.flx[1]
Header and body statements can also have requirements. We can reorganise the previous example using this fact.
Start felix section to tut/examples/tut_bind136.flx[1 /1 ]
     1: #line 483 "./lpsrc/flx_tut_bind.pak"
     2: body "#include <stdio.h>";
     3: body xprint = "void printx(char *fmt, char *s) { printf(fmt,s);}";
     4: body printu = 'void print(char *s) { printx("%s\\n",s); }'
     5:   requires xprint;
     6: 
     7: proc hello:1='print("Hello");' requires printu;
     8: hello;
     9: 
End felix section to tut/examples/tut_bind136.flx[1]
Naked requires clauses can also be used. They can define dependencies, or simply specify existing tagged requirements are roots.
Start felix section to tut/examples/tut_bind137.flx[1 /1 ]
     1: #line 497 "./lpsrc/flx_tut_bind.pak"
     2: body "#include <stdio.h>";
     3: body xprint = "void printx(char *fmt, char *s) { printf(fmt,s);}";
     4: body printu = 'void print(char *s) { printx("%s\\n",s); }';
     5: requires xprint;
     6: xxxx requires printu;
     7: 
     8: proc hello:1='print("Hello");' requires xxxx;
     9: hello;
    10: 
End felix section to tut/examples/tut_bind137.flx[1]
You can also use qualified names to refer to tags defined inside modules, unless they're marked private of course.
Start felix section to tut/examples/tut_bind138.flx[1 /1 ]
     1: #line 511 "./lpsrc/flx_tut_bind.pak"
     2: body "#include <stdio.h>";
     3: body xprint = "void printx(char *fmt, char *s) { printf(fmt,s);}";
     4: module fred {
     5:   body printu = 'void print(char *s) { printx("%s\\n",s); }';
     6: }
     7: requires xprint;
     8: 
     9: proc hello:1='print("Hello");' requires fred::printu;
    10: hello;
    11: 
End felix section to tut/examples/tut_bind138.flx[1]
The next example demonstrates untagged bodies at work.
Start felix section to tut/examples/tut_bind138a.flx[1 /1 ]
     1: #line 524 "./lpsrc/flx_tut_bind.pak"
     2: #import <flx.flxh>
     3: 
     4: body top = 'int ptop() { printf("TOP\\n"); return 1; }';
     5: body 'int top = ptop();' requires top;
     6: 
     7: proc f() {
     8:   body pf = 'int pf(){ printf("f used\\n"); return 1;}';
     9:   body 'int x = pf();' requires pf;
    10:   print "Using f"; endl;
    11: }
    12: 
    13: module A {
    14:   body p = 'int p() { printf("A will be used\\n"); return 1;}';
    15:   body 'int y = p();' requires p;
    16:   proc f: unit = 'printf("A is used\\n");';
    17: }
    18: 
    19: module B {
    20:   body p = 'int p() { printf("B will be used\\n"); return 1;}';
    21:   body 'int y = p();' requires p;
    22:   proc f: unit = 'printf("B is used\\n");';
    23: }
    24: 
    25: A::f();
    26: print "Done"; endl;
    27: // B is not used .. (would cause y,p to be defined twice)
    28: 
End felix section to tut/examples/tut_bind138a.flx[1]
Here you can see that insertions can be given literally too:
Start felix section to tut/examples/tut_bind138b.flx[1 /1 ]
     1: #line 555 "./lpsrc/flx_tut_bind.pak"
     2: 
     3: proc f: 1 = 'printf("A is used\\n");'
     4:   requires header '#include <stdio.h>';
     5: 
     6: f();
     7: 
End felix section to tut/examples/tut_bind138b.flx[1]
Here's an example demonstrating polymorphic insertions.
Start felix section to tut/examples/tut_bind138c.flx[1 /1 ]
     1: #line 564 "./lpsrc/flx_tut_bind.pak"
     2: pod type int="int";
     3: pod type double="double";
     4: 
     5: body prb[t] = "void pr(?1 x) { std::cout << x << std::endl; }"
     6:   requires header "#include <iostream>";
     7: 
     8: proc pr[t]:t = "pr($1);" requires prb[t];
     9: pr 1; pr 1.1;
    10: 
End felix section to tut/examples/tut_bind138c.flx[1]