-
Notifications
You must be signed in to change notification settings - Fork 0
Language Grammar
Douglas Parker edited this page Nov 6, 2016
·
26 revisions
-
<identifier>
: myIdentifier -
<tag>
: valid | enabled | visible | result | selector -
<number>
: 1234 -
<string>
: "testing" -
<regex>
: /"regex"/ -
<selector>
: $("selector") -
<type>
: string | boolean | number
- Consists of 1 or more Statement or Block
- Can be completely empty
<file> -> <blockOrStatementOrDecls>
<blockOrStatementOrDecls> -> ( <decl> | <blockOrStatement> ) <blockOrStatementOrDecls> | Ø
<blockOrStatement> -> <block> | <statement>
- An identifier must be declared before it can be used.
- The name should match with the name attribute of an
<input />
tag on the HTML page.
<decl> -> <type> : <identifier> ;
<input type="text" name="email" />
string: email; // Declares the input named "email" as a string
- A statement defines a variable or tag with an expression.
- A tag statement within the outer most scope of the program is attached to the root element.
<statement> -> <variable> | <tag> : <expression>
valid: true and true;
- A variable name begins with the '@'
- The only naming restriction is that the variable name cannot contain ':'
- Variables are bound to the expression they are given. Their current value will automatically update as their expression changes.
- Variable names can be reused within the same file provided they are within different scopes.
- If a variable name is reused in the same scope, a warning will be triggered and the original expression will be overwritten with the new expression.
<variable> -> @ <identifier> :
@var2: 10 * 5; //Declaration for var2
valid: @var2 equals 50; //evaluates to 10 * 5 equals 50 -> true
string: myIdentifier;
@var1: myIdentifier; //Declaration for var1
valid: @var1 equals "test"; //true or false depending on the value of <input name="myIdentifier" />
- A block comprises of two elements, a header and a body.
- The header is a variable or an identifier.
- The body contains information that can be recalled by the header with dot notation.
- The block's body consists of statements or nested blocks
- Nested variables are contained within a local scope.
<block> -> <identifier> | <variable> { <blockOrStatements> }
<form>
<input type="text" name="outer" />
<div> <!-- @form -->
<input type="text" name="inner" />
<div> <!-- @subform -->
<input type="text" name="inner2" />
</div>
</div>
</form>
// Block variable
@form {
// Tag statement
valid: inner matches /"."/ and @subForm.valid;
// Nested block variable
@subForm {
// Tag statement
valid: inner equals inner2;
}
}
// Block identifier
outer {
// Tag statement
valid: outer matches /"."/;
}
// Root-level tag statement
valid: outer.valid and @form.valid;
- There are currently five different tag that are supported: valid, enabled, visible, selector, and result
- The value of a tag is bound to that of its expression
Descriptions of each tag can be found here:
<tag> -> valid | enabled | visible | result | selector
- valid - Boolean representing whether or not the containing block is considered "valid"
- enabled - Boolean representing whether or not the containing block is enabled for user input
- visible - Boolean representing whether or not the containing block is visible to the user
- result - Any data type which represents the "result" of the containing block. This should hold any information other forms may need from it while internal information can be kept hidden.
- selector - jQuery selector to apply the enabled and visible tags to. For an identifier block this will default to the element with the name of the containing block.
@block {
result: "test"; //Any type
visible: true; //Boolean
enabled: true; //Boolean
valid: false; //Boolean
selector: $("#myForm"); //jQuery selector that this block references
}
- An identifier refers to the name of an HTML
<input />
element to be validated. - The only restriction to an identifier is that it must not be a key word in Uniform.
An identifier can be used in two places:
- The statements within the block apply to the block header identifier.
- The block header identifier stores the expression of all its tags.
- The value of the identifier is extracted and used in the expression.
- The dot operation can be used to refer to tags underneath the identifier.
myElement {
valid: true;
}
//myElement.valid reads `true` from myElement's valid tag
//otherElement's value is used directly and compared with "test"
valid: myElement.valid and otherElement equals "test";
The expression grammar looks complicated, but is this way to enforce order of operations, prefix, postfix, or infix, and unary or binary. The order of operations is represented more clearly by this table.
The actual grammar is as follows:
<expression> -> <andOr>
<andOr> -> <not> <andOr_>
<andOr_> -> and <not> <andOr_>
| or <not> <andOr_>
| Ø
<not> -> not <not>
| <comparator>
<comparator> -> <addSub> <comparator_>
<comparator_> -> equals <addSub> <comparator_>
| matches <addSub> <comparator_>
| < <addSub> <comparator_>
| > <addSub> <comparator_>
| <= <addSub> <comparator_>
| >= <addSub> <comparator_>
| Ø
<addSub> -> <mulDivMod> <addSub_>
<addSub_> -> + <mulDivMod> <addSub_>
| - <mulDivMod> <addSub_>
| Ø
<mulDivMod> -> <neg> <mulDivMod_>
<mulDivMod_> -> * <neg> <mulDivMod_>
| / <neg> <mulDivMod_>
| % <neg> <mulDivMod_>
| Ø
<neg> -> - <neg>
| <anyAll>
<anyAll> -> any <ifBlock>
| all <ifBlock>
| <ifBlock>
<ifBlock> -> if <expression> then <expression> <elseIf> else <expression> end
| <dot>
<elseIf> -> elif <expression> then <expression> <elseIf>
| ø
<dot> -> <paren> <dot_>
<dot_> -> . <identifier> ( <args> ) <dot_>
| Ø
<args> -> <expression> <args_>
<args_> -> , <expression> <args_>
| Ø
<paren> -> ( <expression> ) | <operand>
<operand> -> <number> | <string> | <variable> | <selector> | true | false | this | <object>
<object> -> { <keyValuePairs> }
<keyValuePairs> -> <keyValuePair> <keyValuePairs>
| Ø
<keyValuePair> -> <identifier> : <expression> ;