F.E.L.T.

Functionally Equivalent Language Translation

#F:WHEN

(#f:when coder-class expressions)
(#f:when PHPCoder ...body...)
(#f:when JSCoder ...body...)
(#f:when CSSCoder ...body...)
(#f:when NodejsCoder ...body...)

See also #F:FN #F:SYM #F:VAR

This pre-processor instruction checks to see if the current back-end output coder is FOOCoder and if so it will add the contents of the body expression to the output source text, translated of course into language FOO. Coder names are case sensitive.


Choose Portability!

If you have a small script that you'd like to keep all in one file but there are small differences that you need to take into account, for example, functions in language A not being present in language B then this instruction is what you will need to use to manage those differences. For larger projects or for cleaner FELT code, it is easier just to put all language specifics into a single file and then ensure that whatever tool-chain you use is able to pull in what it needs when it needs it.

For example, we've already seen during many of the instruction reference pages places where the PHP implode function was used to concatenate an array of strings and produce a final string... javaScript of course does not have that instruction in its natural set of reserved words. So how do we do it? Simple, by adding this to your FELT source. In the examples, for simplicity and clarity, we added the extra function explicitly in the example but here can will use the "clever" way to do it:

(#f:when JSCoder
  (defun implode (x)
    (return (x.join))))

Now when we run the FELT source it will generate a function called implode that works on the javaScript language target and produce no output at all for any other target language.

Here is the current (case-sensitive) list of coder names as a short example.

(#f:when PHPCoder
  (emit "PHP"))

(#f:when JSCoder
  (emit "javaScript"))

(#f:when NodejsCoder
  (emit "Node.js"))

(#f:when CSSCoder
  (emit "CSS, commented out!"))

One of the places were this is used on the actual FELT site is in the tag library, it will help if we display and explain the code and how and why it works. That should be explanation enough on how to use the TYPEOF instruction.

The TAGLIB.FELT source file.

One of the coolest files in the entire project! This file contains a really simple HTML generation library that is used by both the PHP server side and the javaScript client side code because simple rules were followed and allowed FELT to generate functionally equivalent code for both. Every page from the server uses it and the client-side code using it is the automatic table-of-contents generation.

One of the core functions in the tag library is called (->string x), what this does is take any argument and attempt to return a st

(->STRING)

Essentially it looks at the type of its argument and then, after determing the type, will return a string representation of that argument by following these rules:

So, how can it know what to do for PHP and Javscript? Answer: It can't! That's where the #F:WHEN instruction comes to the rescue by allowing us to provide two different implementations of the same function at render time.

PHP version of (->STRING)

Here is the actual code that powers this site in PHP mode:

(#f:when PHPCoder
  (defun ->string (thing (glue ""))
    (if (is-string thing)
    (return thing))
    (if (is-array thing)
    (return (implode glue thing)))
    (if (is-object thing)
    (return (-> thing (__toString))))
    (return thing)))

JavaScript version of (->STRING)

(#f:when JSCoder
  (defun ->string (thing)
    (defvar glue "")
    (if (== 2 arguments.length)
    (= glue (@ arguments 1)))
    (defvar isa Object.prototype.toString)
    (defvar type (-> isa (call thing)))
    (switch type
            "[object Array]" (return (thing.join glue))
            "[object String]" (return thing))
    (return (concat "" thing)))
  ;;
  ;; Simulates PHP func_get_args() but requires that the locally
  ;; scoped "arguments" value is passed in to be able to work. We use
  ;; (@<) to ensure the reutrned array is in the same order.
  ;;
  (defun func-get-args (the-args)
    (defvar args [])
    (foreach (the-args a-key a-val)
         (@< args a-val))
    (return args)))