Skip to content

Language Grammar

Douglas Parker edited this page Nov 6, 2016 · 26 revisions

Grammar Tree

Grammar Tree

Lexical Components

  • <identifier>: myIdentifier
  • <tag>: valid | enabled | visible | result | selector
  • <number>: 1234
  • <string>: "testing"
  • <regex>: /"regex"/
  • <selector>: $("selector")
  • <type>: string | boolean | number

Uniform File

  • Consists of 1 or more Statement or Block
  • Can be completely empty

Grammar

<file> -> <blockOrStatementOrDecls>
<blockOrStatementOrDecls> -> ( <decl> | <blockOrStatement> ) <blockOrStatementOrDecls> | Ø
<blockOrStatement> -> <block> | <statement>

Declaration

  • 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.

Grammar

<decl> -> <type> : <identifier> ;

Example

<input type="text" name="email" />
string: email; // Declares the input named "email" as a string

Statement

  • 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.

Grammar

<statement> -> <variable> | <tag> : <expression>

Example

valid: true and true;

Variable

  • 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.

Grammar

<variable> -> @ <identifier> :

Example

@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" />

Block

  • 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.

Grammar

<block> -> <identifier> | <variable> { <blockOrStatements> }

Example

<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;

Tag

  • 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:

Grammar

<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.

Example

@block {
    result: "test"; //Any type
    visible: true;  //Boolean
    enabled: true;  //Boolean
    valid: false;   //Boolean
    selector: $("#myForm"); //jQuery selector that this block references
}

Identifier

  • 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:

1. As the header of a block

  • The statements within the block apply to the block header identifier.
  • The block header identifier stores the expression of all its tags.

2. As an operand in a statement

  • 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.

Example

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";

Expression

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.

Expression Priority Table

Grammar

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> ;