Differences of HFL from javascript, CSS and HFL
- In addition to extending the syntax of javascript, CSS and HTML, HFL has some slight behavioral differences in some cases.
- Most of these differences are necessary in order to be able to merge the syntax of the three languages without syntactic conflict.
- Some of the others were added to enhance certain features of the languages.
- These differences are presented here as an aid to understanding the language for those who are already familiar with javascript, CSS and HFL.
Differences from javascript
-
Variables in HFL have some slight behavioral differences from javascript:
-
Unlike javascript, in HFL global var, let and const identifiers must be declared lexically above any code or function declaration that references them.
HFL does support javascript-stype 'hoisting' of local identifier declarations within code blocks (e.g. code inside braces '{' '}'). For example, an identifier can be referenced near the top of a code block, and then be declared later as a var in the same code block.
But in HFL this cannot be done for global identifier declarations.
The reason is that unlike javascript, HFL also supports cell properties (CSS properties and HTML attributes). And to support CSS-style cell property references, and keep user code uncluttered, HFL does not require that cell properties be pre-declared.
Unless variables, consts and cell properties are pre-declared, it is not possible to distinguish a variable reference from a cell property.
As an example, without some kind of disambiguation rule, it is not possible to distinguish whether identifiers border and width are variables or cell properties without declaring them.
It becomes even more ambiguous when the two identifiers are separated by a hyphen, as in border-width. It could be either a reference to the CSS border-width property, or it could be a subtraction of width from border. Javascript does not have this issue, because variable identifiers cannot have hyphens in them as can CSS identifiers.
To resolve the ambiguities, HFL applies the following rules:
- Undeclared identifiers are interpreted as cell property references, not global variables.
- An undeclared identifier followed by a hyphen and another identifier without spaces between them is interpreted as a single CSS-style identifier.
This requires that global declarations must be made ahead of any references in the code, as it affects the how the code is parsed.
NOTE: It is not possible to declare variable or function names that contain hyphens. Only cell properties and scope references are affected by this rule.
In the following two examples, cell properties width, border and border-width initially have the following values:
-
// Set the width, border and border-width cell properties
border = 50;
width = 200;
border-width = 5;
In the first example, identifiers width, border and border-width are otherwise undeclared, so they will be treated as cell properties:
-
print("width prop is $width"); // Prints: "width prop is 200"
// Subtract border-width property from border property
width -= border-width; // border-width is a property
print("width prop is now $width"); // Prints: "border prop is now 195"
In the second example, if identifier border is first declared as a variable, then border-width becomes a subtraction of the width cell property from the border variable value:
-
// Declare border as a var
var border = 20;
print("border var = %d", border); // Prints: "border var = 20"
print("border prop $border"); // Prints: "border prop is 50"
print("width prop is $width"); // Prints: "width prop is 200"
// Now border-width is not a prop, but var border less prop width!
width -= border-width; // Now border-width is a subtraction
print("width prop is now $width!"); // Prints: "width prop is now 350!"
-
Undeclared identifiers used in the left-hand-side of assignment statements are treated as HTML attribute assignments, unless the identifier names begin with a '$'.
- Undeclared identifiers followed by a colon (:) are treated as CSS property expressions, when used outside of an anonymous object reference.
-
Variables whose names do not begin with a '$' must be declared. In effect, HFL enforces the ES5 strict mode mode of javascript unless the names begin with a '$'.
Thus $foo would not have to be declared, but bar would.
-
Variables whose names begin with a '$' followed by one or more alphanumeric characters can be used within double-quoted strings and will be replaced with their value.
- Undeclared identifiers begining with a '$' that have the same name (minus the '$') as cell properties are treated as pseudo-variables . Pseudo-variables are syntactic sugar to make it easy to reference cell properties, allowing them to be used in expressions and expanded in double-quoted strings (see above).
-
Statement labels must be followed by a newline after the colon.
CSS-style cell property assignments must not be followed by a newline after the colon.
This distinction is necessary in order to disambiguate statement labels from CSS property assignments, as either can be followed by an expression. The distinction is critical, as the right-side expression of CSS property assignments is parsed differently than are normal HFL statements.
-
// Statement labels must have a newline after the colon:
top:
for (i = 1; i < 10; i++)
if (foo[i] == 2)
break top;
// CSS property assigns must not have a newline after the colon:
color:red;
-
-
-
EXAMPLES:
-
// Assignments using undeclared identifiers are HTML attribute assignments
color = red // Undeclared: attribute assign
foo++; // Undeclared: SYNTAX ERROR
// Variables without leading '$' must be declared
var count = 1; // Declared variable
count++; // Variable increment
// Variables with leading '$' will expand in double-quoted strings
$wld = 'World'; // Undeclared global var
print("Hello $wld!"); // Prints "Hello World!"
// Undeclared identifiers followed by a colon are CSS property expressions
mycolor:red; // Undeclared: CSS property
// Cell properties can be referenced as pseudo-variables
var new_height = $height + 50; // References cell prop "height"
print("The color is $color"); // Print the color prop value
-
Differences from CSS
- CSS property expressions can accept any valid javascript right-hand-side expression as the assigned value.
-
EXAMPLES:
-
// CSS expression's right-hand-side can be a javascript expression
width:$width + 1; // Increments width property value
-
Differences from HTML attributes
- HTML attribute assignments can accept any valid javascript right-hand-side expression as the assigned value.
- If the right-hand-side expression contains more than a single identifier or value, the assignment requires a terminating semi-colon.
-
EXAMPLES:
-
// Single-term values do not require a terminating semi0colon
color = "red"
// An attribute assignment's right-hand-side can be a javascript expression
width = $width + 1; // Increments width property value
-
Differences from PHP
- Like PHP, in HFL double-quoted strings are treated differently than single-quoted strings. In both languages, substrings within the double-quoted strings that begin with a '$' and followed by valid identifer characters are treated as identifier references. And in both languages the references are expanded with the identifer's value.
- The difference is that in HFL the referenced identifier itself must begin with a '$', and PHP identifiers cannot begin with a $.
- Further, HFL supports pseudo-variables which also begin with $ characters.
- Thus a reference of $foo in HFL would match variable $foo, the same reference in PHP would match variable foo.
-
EXAMPLES:
-
var $foo = "red";
print("foo = $foo"); // Prints: "foo = red"
-