1.8. 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/embedding/bind-1.07-0.flx[1 /1 ]
     1: #line 520 "./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;
End felix section to tut/embedding/bind-1.07-0.flx[1]
Start data section to tut/embedding/bind-1.07-0.expect[1 /1 ]
     1: Hello
End data section to tut/embedding/bind-1.07-0.expect[1]
Header and body statements can also have requirements. We can reorganise the previous example using this fact.
Start felix section to tut/embedding/bind-1.07-1.flx[1 /1 ]
     1: #line 536 "./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;
End felix section to tut/embedding/bind-1.07-1.flx[1]
Start data section to tut/embedding/bind-1.07-1.expect[1 /1 ]
     1: Hello
End data section to tut/embedding/bind-1.07-1.expect[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/embedding/bind-1.07-2.flx[1 /1 ]
     1: #line 554 "./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;
End felix section to tut/embedding/bind-1.07-2.flx[1]
Start data section to tut/embedding/bind-1.07-2.expect[1 /1 ]
     1: Hello
End data section to tut/embedding/bind-1.07-2.expect[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/embedding/bind-1.07-3.flx[1 /1 ]
     1: #line 572 "./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;
End felix section to tut/embedding/bind-1.07-3.flx[1]
Start data section to tut/embedding/bind-1.07-3.expect[1 /1 ]
     1: Hello
End data section to tut/embedding/bind-1.07-3.expect[1]
The next example demonstrates untagged bodies at work.
Start felix section to tut/embedding/bind-1.07-4.flx[1 /1 ]
     1: #line 590 "./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)
End felix section to tut/embedding/bind-1.07-4.flx[1]
Start data section to tut/embedding/bind-1.07-4.expect[1 /1 ]
     1: TOP
     2: A will be used
     3: A is used
     4: Done
End data section to tut/embedding/bind-1.07-4.expect[1]
Here you can see that insertions can be given literally too:
Start felix section to tut/embedding/bind-1.07-5.flx[1 /1 ]
     1: #line 629 "./lpsrc/flx_tut_bind.pak"
     2: proc f: 1 = 'printf("A is used\\n");'
     3:   requires header '#include <stdio.h>';
     4: 
     5: f();
End felix section to tut/embedding/bind-1.07-5.flx[1]
Start data section to tut/embedding/bind-1.07-5.expect[1 /1 ]
     1: A is used
End data section to tut/embedding/bind-1.07-5.expect[1]
Here's an example demonstrating polymorphic insertions.
Start felix section to tut/embedding/bind-1.07-6.flx[1 /1 ]
     1: #line 642 "./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;
End felix section to tut/embedding/bind-1.07-6.flx[1]
Start data section to tut/embedding/bind-1.07-6.expect[1 /1 ]
     1: 1
     2: 1.1
End data section to tut/embedding/bind-1.07-6.expect[1]