Lexical Issues

ACOR

Pattern:acor

The acor keyword introduces an object accessor function.

AGENT

Pattern:agent

The agent keyword introduces an agent declaration.

AJAX

Pattern:ajax

The ajax keyword creates or access an AJAX server in a system test.

APPLICATION

Pattern:application

The application keyword introduces an application in an assembly file.

APPLY

Pattern:\.

The apply operator.

ARROW

Pattern:->

ARROW is used to describe function types.

ASSERT

Pattern:assert

The assert keyword introduces an assert step in a unit test.

AT

Pattern:at

The at keyword is used in assembly files to indicate actions carried out at a particular route.

BASEURI

Pattern:baseuri

The baseuri keyword is used in an assembly file to identify the base URI of the application.

BINOP

Pattern:[-+*/%<>]|==|<=|>=|\+\+|&&|\|\|

One of the standard binary operators. They have precedence, but this is not apparent from the grammar.

We should specify the precedence here.

CANCEL

Pattern:<~

The CANCEL operator is used to specify expectations that a subscription will be cancelled.

CARD

Pattern:card

The card keyword introduces a card definition.

CAST

Pattern:cast

The cast function states that the expression should be given a specific compile-time type which will be checked at runtime.

CCB

Pattern:\}

A closing curly bracket delimits the end of a constructor pattern or object creation.

CLOSE

Pattern:close

The CLOSE command is used in unit tests to close a card.

COLON

Pattern::

Can be an operator or can be used to define object literals.

COMMA

Pattern:,

Separates similar items in a list.

CONFIGURE

Pattern:configure

The system test keyword configure.

CONTRACT

Pattern:contract

The contract keyword introduces a contract declaration.

It is also used in unit tests to invoke a contract method on a card or service.

CRB

Pattern:\)

A closing round bracket delimits the end of an expression or pattern.

CREATE

Pattern:create

The ajax system test keyword create.

CSB

Pattern:\]

A closing square bracket delimits the end of a list operation or polymorphic variable list.

CTOR

Pattern:ctor

The ctor keyword introduces an object constructor declaration.

DATA

Pattern:data

The data keyword introduces a data declaration in a unit test.

ENTER

Pattern:enter

The enter keyword is used in assembly files to indicate actions carried out when first entering particular route.

ENTITY

Pattern:entity

The entity keyword introduces an entity definition.

EQ

Pattern:=

Defines the variable/function definition operator.

EVENT

Pattern:event

The event keyword introduces an event handler.

EXIT

Pattern:exit

The exit keyword is used in assembly files to indicate actions carried out when leaving a particular route.

EXPECT

Pattern:expect

The expect keyword introduces a mock expectation.

FALSE

Pattern:False

The boolean literal False.

FINALLY

Pattern:finally

The system test keyword finally.

FREETEXT

Pattern:.*

Free text spread across multiple lines which can be used to match HTML output from a template.

GUARD

Pattern:\|

Defines the variable/function definition operator.

HANDLE

Pattern:->

The HANDLE operator is used to assign subscription handles to handle variables.

HANDLER

Pattern:handler

The handler keyword introduces a callback handler.

HREF

Pattern:href

href is a keyword used with the match unit test command to match hyperlink text.

IDENTICAL

Pattern:identical

The identical keyword introduces an assertion that two expressions refer to the same node.

IGNORE

Pattern:ignore

The ignore keyword causes a unit test to be ignored.

IMAGE

Pattern:image

image is a keyword used with the match unit test command to match image URIs.

IMPLEMENTS

Pattern:implements

The implements keyword introduces a contract implementation in a card.

INPUT

Pattern:input

The input keyword allows tests to enter data into boxes.

INVOKE

Pattern:invoke

The invoke keyword is used in unit tests to invoke a method on an object.

ISTYPE

Pattern:istype

istype is a special function for testing the runtime type of an expression.

MATCH

Pattern:match

The match keyword introduces a template matching step in a unit test.

METHOD

Pattern:method

The method keyword introduces a standalone method definition.

NEWDIV

Pattern:newdiv

The newdiv keyword is used in internal testing.

NUMBER

Pattern:[0-9.e+-]+

A numeric literal.

OBJECT

Pattern:object

The object keyword introduces an object declaration.

OCB

Pattern:\{

An opening curly bracket introduces a constructor pattern match or object creation.

OPTIONAL

Pattern:optional

The optional keyword indicates that a contract method does not need to be implemented.

ORB

Pattern:\(

An opening square bracket introduces a sub-element of an expression or pattern.

ORELSE

Pattern:\|\|

The ORELSE token allows simple alternative styling patterns.

OSB

Pattern:\[

An opening square bracket introduces various list operations as well as polymorphic variables.

PROVIDES

Pattern:provides

The provides keyword introduces a block indicating that the service portion of a contract will be provided.

PUMP

Pattern:pump

The ajax system test keyword pump.

RENDER

Pattern:render

The render keyword is used to force cards to render in tests.

REQUIRES

Pattern:requires

The requires keyword identifies a variable which is bound to a service of the specified contract.

RESPONSES

Pattern:responses

The ajax system test keyword create.

ROUTE

Pattern:route

The route keyword introduces a nested route in a routing table in an assembly file.

ROUTES

Pattern:routes

The routes keyword introduces a routing table in an assembly file.

SCROLL

Pattern:scroll

scroll is a keyword used with the match unit test command to check on where the window has scrolled to.

SECURE

Pattern:secure

scroll is a keyword used with the match unit test command to check on where the window has scrolled to.

SEND

Pattern:<-

Method actions, variable assignments and template definitions are defined using the SEND operator.

SENDTO

Pattern:=>

The SENDTO operator is used to pass things around in templates.

SERVICE

Pattern:service

The service keyword introduces a service declaration.

SHOVE

Pattern:shove

The shove keyword is used in unit tests to directly affect object or card state.

STATE

Pattern:state

The state keyword introduces a card or object state.

STRING

Pattern:"[^"]*"|'[^']*'

A string literal.

STRUCT

Pattern:struct

The struct keyword introduces a struct declaration.

STYLE

Pattern:style

The style keyword is used to match card styles.

SUBSCRIBE

Pattern:subscribe

The system test keyword subscribe.

TEMPLATE

Pattern:template

The template keyword introduces a template definition.

TEST

Pattern:test

The test keyword introduces a unit test case.

TESTDESCRIPTION

Pattern:.+

The test keyword introduces a unit test case.

TEXT

Pattern:text

The text keyword is used to match text on a card.

TITLE

Pattern:title

title is a keyword used with the match unit test command to test the current window title.

It is also used in the assembly file to provide the title for an application.

TRUE

Pattern:True

The boolean literal True.

TYPE

Pattern:type

The type keyword is used to turn a type name literal into a type object.

UNION

Pattern:union

The union keyword introduces a union declaration.

UNOP

Pattern:[!]

One of the standard unary operators. They have precedence, but this is not apparent from the grammar.

We should specify the precedence here.

introduce-var

Pattern:_[a-z][A-Za-z0-9_]*

Function and variable names are one or more characters, where the first character must be a lower case alphabetic character.

poly-var

Pattern:[A-Z][A-Z]?

Polymorphic variable names must be one or two capital letters.

template-name

Pattern:[a-z][a-z0-9-]*

The name of a template or template item, which must match the name of a provided webzip element.

type-name

Pattern:[A-Z][a-z0-9_][A-Za-z0-9_]*

Concrete type names must start with a capital letter and have at least two characters in the name.

var-name

Pattern:[a-z][A-Za-z0-9_]*

Function and variable names are one or more characters, where the first character must be a lower case alphabetic character.

zone-name

Pattern:[a-z][A-Za-z0-9_-x]*

Function and variable names are one or more characters, where the first character must be a lower case alphabetic character.

Summary

(1)
file
::=
<source-file>
|
<assembly-file>
|
<unit-test-file>
|
<protocol-test-file>
|
<system-test-file>
(2)
source-file
::=
<top-level-unit>*
(3)
assembly-file
::=
<assembly-unit>*
(4)
unit-test-file
::=
 <unit-test-unit>*
(5)
protocol-test-file
::=
<protocol-test-unit>*
(6)
system-test-file
::=
 <system-test-configure>? <system-test-unit>* <system-test-finally>?
(7)
top-level-unit
::=
<top-level-definition>
|
<function-scope-unit>
(8)
top-level-definition
::=
<struct-declaration>
|
<union-declaration>
|
<entity-declaration>
|
<contract-declaration>
|
<object-declaration>
|
<service-declaration>
|
<agent-declaration>
|
<card-declaration>
(9)
function-scope
::=
<function-scope-unit>*
(10)
function-scope-unit
::=
<function-case-definition>
|
<tuple-definition>
|
<standalone-method-definition>
|
<handler-definition>
(11)
struct-declaration
::=
STRUCT type-name poly-var* 
>><struct-field-decl>
(12)
entity-declaration
::=
ENTITY type-name poly-var* 
>><struct-field-decl>
(13)
struct-field-decl
::=
<type-reference> var-name <struct-initializer>?
(14)
struct-initializer
::=
SEND <expression>
(15)
union-declaration
::=
UNION type-name 
>>><type-reference>
(16)
contract-declaration
::=
<contract-intro> type-name 
>><contract-method-decl>
(17)
contract-intro
::=
CONTRACT
|
CONTRACT SERVICE
|
CONTRACT HANDLER
(18)
contract-method-decl
::=
OPTIONAL? var-name  <argument-pattern-typed>* <handled-by>? 
(19)
handled-by
::=
HANDLE <argument-pattern-typed>
(20)
function-case-definition
::=
<simple-function-case-definition>
|
<degenerate-guarded-function-case-definition>
|
<guarded-function-case-definition>
(21)
simple-function-case-definition
::=
 var-name   <argument-pattern>*  EQ <expression> 
>><function-scope>
(22)
degenerate-guarded-function-case-definition
::=
var-name   <argument-pattern>*  
>>!<guarded-default-expression>
(23)
guarded-function-case-definition
::=
var-name   <argument-pattern>*  
>>!<guarded-equations>
(24)
guarded-equations
::=
<guarded-expression>+ <guarded-default-expression>? 
>><function-scope>
(25)
guarded-expression
::=
GUARD <expression> EQ <expression> 
(26)
guarded-default-expression
::=
GUARD EQ <expression> 
(27)
tuple-definition
::=
ORB var-name <comma-var-name>+ CRB EQ <expression> 
>><function-scope>
(28)
comma-var-name
::=
COMMA var-name
(29)
argument-pattern
::=
<argument-pattern-type-name>
|
<argument-pattern-variable>
|
<argument-pattern-literal>
|
<argument-pattern-list>
|
<argument-pattern-typed>
|
<argument-pattern-ctor>
(30)
argument-pattern-type-name
::=
type-name
(31)
argument-pattern-maybe-typed
::=
<argument-pattern-variable>
|
<argument-pattern-typed>
(32)
argument-pattern-variable
::=
var-name
(33)
argument-pattern-literal
::=
NUMBER
|
STRING
(34)
argument-pattern-list
::=
OSB CSB
|
OSB <argument-pattern> <comma-argument-pattern>* CSB
(35)
comma-argument-pattern
::=
COMMA <argument-pattern>
(36)
argument-pattern-typed
::=
ORB <type-reference> var-name CRB
(37)
argument-pattern-ctor
::=
ORB <type-reference> OCB CCB CRB
|
ORB <type-reference> OCB <field-argument-pattern> <comma-field-argument-pattern>* CCB CRB
(38)
field-argument-pattern
::=
var-name COLON <argument-pattern>
(39)
comma-field-argument-pattern
::=
COMMA <field-argument-pattern>
(40)
type-reference
::=
type-name <poly-type-list>?
|
poly-var
|
<type-reference> ARROW <type-reference>
|
ORB <type-reference> <comma-type-reference>+ CRB
|
ORB <type-reference> CRB
|
<type-member>
(41)
poly-type-list
::=
OSB <type-reference> <comma-type-reference>* CSB
(42)
comma-type-reference
::=
COMMA <type-reference>
(43)
expression
::=
<literal>
|
<paren-expression>
|
<tuple-expression>
|
<function-call>
|
<get-type-expr>
|
<check-type-expr>
|
<member-expr>
|
UNOP <expression>
|
<expression> BINOP <expression>
|
<expression> COLON <expression>
|
CAST <type-reference> <expression>
(44)
member-expr
::=
<value-expression> APPLY var-name
|
<type-member>
(45)
type-member
::=
<value-expression> APPLY type-name
(46)
function-call
::=
<value-expression> <expression-term>*
(47)
check-type-expr
::=
ISTYPE type-name <expression-term>
(48)
get-type-expr
::=
TYPE type-name
|
TYPE <expression>
(49)
value-expression
::=
var-name
|
type-name
|
<member-expr>
|
ORB <expression> CRB
(50)
paren-expression
::=
ORB <expression> CRB
(51)
expression-term
::=
<literal>
|
var-name
|
type-name
|
<tuple-expression>
|
<member-expr>
|
<paren-expression>
(52)
literal
::=
NUMBER
|
STRING
|
TRUE
|
FALSE
|
<list-literal>
|
<object-literal>
(53)
list-literal
::=
OSB CSB
|
OSB <expression> <comma-expression>* CSB
(54)
tuple-expression
::=
ORB <expression> <comma-expression>+ CRB
(55)
comma-expression
::=
COMMA <expression>
(56)
object-literal
::=
OCB CCB
|
OCB <object-member> <comma-object-member>* CCB
(57)
object-member
::=
<object-key> COLON <expression>
(58)
object-key
::=
var-name
|
STRING
(59)
comma-object-member
::=
COMMA <object-member>
(60)
handler-definition
::=
HANDLER type-name type-name  <argument-pattern-maybe-typed>*  
>><implementation-method>
(61)
standalone-method-definition
::=
METHOD  <method-definition>
(62)
object-method-definition
::=
METHOD  <method-definition>
(63)
method-definition
::=
var-name  <argument-pattern>*  
>>!<method-guards-or-actions>
(64)
method-guards-or-actions
::=
<method-guards>
|
<method-actions>
(65)
method-guards
::=
<method-guard>* <method-guard-default>? 
>><function-scope-unit>
(66)
method-guard
::=
GUARD <expression> 
>><method-action>
(67)
method-guard-default
::=
GUARD 
>><method-action>
(68)
method-actions
::=
<method-action>* 
>><function-scope-unit>
(69)
method-action
::=
<message-method-action>
|
<assign-method-action>
(70)
message-method-action
::=
SEND <expression> <maybe-handled>? <maybe-subscribed>? 
(71)
maybe-handled
::=
HANDLE <expression>
(72)
maybe-subscribed
::=
SENDTO <expression>
(73)
assign-method-action
::=
<member-path> SEND <expression> 
(74)
member-path
::=
var-name <member-path-apply>*
(75)
member-path-apply
::=
APPLY var-name
(76)
object-declaration
::=
OBJECT type-name  poly-var* 
>><object-scope-unit>
(77)
object-scope-unit
::=
<state-declaration>
|
<requires-contract>
|
<object-ctor-definition>
|
<named-template-definition>
|
<object-acor-definition>
|
<object-method-definition>
|
<function-case-definition>
|
<handler-definition>
|
<event-handler>
(78)
state-declaration
::=
STATE 
>><struct-field-decl>
(79)
object-ctor-definition
::=
CTOR  <method-definition>
(80)
object-acor-definition
::=
ACOR  <function-case-definition>
(81)
service-declaration
::=
SERVICE type-name 
>><service-scope-unit>
(82)
service-scope-unit
::=
<requires-contract>
|
<provides-contract>
|
<function-scope-unit>
(83)
provides-contract
::=
PROVIDES type-name  
>><implementation-method>
(84)
agent-declaration
::=
AGENT type-name 
>><agent-scope-unit>
(85)
agent-scope-unit
::=
<state-declaration>
|
<requires-contract>
|
<implements-contract>
|
<service-scope-unit>
(86)
card-declaration
::=
CARD type-name  
>><card-scope-unit>
(87)
card-scope-unit
::=
<named-template-definition>
|
<event-handler>
|
<agent-scope-unit>
(88)
requires-contract
::=
REQUIRES type-name  var-name
(89)
implements-contract
::=
IMPLEMENTS type-name  
>><implementation-method>
(90)
implementation-method
::=
var-name  <argument-pattern-variable>* <implementation-result>?  
>><method-actions>
(91)
implementation-result
::=
HANDLE var-name
(92)
event-handler
::=
EVENT var-name  <argument-pattern-typed>  
>>!<method-guards-or-actions>
(93)
named-template-definition
::=
TEMPLATE template-name <define-template-chain>?  
>><template-bind>
(94)
define-template-chain
::=
SEND <template-chain-var>+
(95)
template-chain-var
::=
ORB <type-reference> var-name CRB
(96)
template-bind
::=
template-name SEND <expression> <pass-to-template>? 
>><template-customization>
|
template-name 
>>!<option-template-binds>
|
<template-customization>
(97)
option-template-binds
::=
<option-template-bind>+ <default-option-template-bind>? 
>><template-customization>
|
<default-option-template-bind> 
>><template-customization>
|
<template-customization>
(98)
option-template-bind
::=
GUARD <expression> SEND <expression> <pass-to-template>? 
>>!<option-template-binds>
(99)
default-option-template-bind
::=
SEND <expression> <pass-to-template>? 
(100)
pass-to-template
::=
SENDTO template-name
(101)
template-customization
::=
<template-style-cond>
|
<template-style-format>
|
<template-style-format-or-else>
|
<template-event>
(102)
template-style-cond
::=
GUARD <expression> 
>><template-customization>
(103)
template-style-format
::=
GUARD <expression>? SENDTO <expression>+ 
>><template-customization>
(104)
template-style-format-or-else
::=
GUARD <expression> SENDTO <expression>+ ORELSE <expression>+
(105)
template-event
::=
SENDTO var-name
(106)
assembly-unit
::=
<assembly-application>
|
<assembly-application>
(107)
assembly-application
::=
APPLICATION 
>><assembly-application-scope>
(108)
assembly-application-scope
::=
<assembly-title>
|
<assembly-baseuri>
|
<assembly-routes>
(109)
assembly-title
::=
TITLE STRING
(110)
assembly-baseuri
::=
BASEURI STRING
(111)
assembly-routes
::=
ROUTES 
>><assembly-routing-table>
(112)
assembly-routing-table
::=
<assembly-title>
|
var-name SEND type-name
|
SECURE
|
<assembly-route-enter>
|
<assembly-route-at>
|
<assembly-route-exit>
|
<assembly-route-nested>
(113)
assembly-route-enter
::=
ENTER 
>><assembly-route-actions>
(114)
assembly-route-at
::=
AT 
>><assembly-route-actions>
(115)
assembly-route-exit
::=
EXIT 
>><assembly-route-actions>
(116)
assembly-route-actions
::=
var-name <assembly-route-with-contract>? APPLY <function-call>
(117)
assembly-route-with-contract
::=
APPLY type-name
(118)
assembly-route-nested
::=
ROUTE STRING 
>><assembly-routing-table>
(119)
unit-test-unit
::=
<unit-test-declaration>
|
<unit-test-ignore>
|
<unit-data-declaration>
(120)
unit-test-declaration
::=
TEST TESTDESCRIPTION  
>><unit-test-step>
(121)
unit-test-ignore
::=
IGNORE TESTDESCRIPTION  
>><unit-test-step>
(122)
unit-test-step
::=
<unit-data-declaration>
|
<unit-event-action>
|
<unit-invoke-action>
|
<unit-contract-action>
|
<unit-test-assert>
|
<unit-test-identical>
|
<unit-test-shove>
|
<unit-test-input>
|
<unit-test-expect>
|
<unit-test-cancel>
|
<unit-test-close-card>
|
<unit-test-match>
|
<internal-test-newdiv>
|
<internal-test-render>
(123)
unit-event-action
::=
EVENT var-name <unit-test-target-zone> <expression>
(124)
unit-invoke-action
::=
INVOKE <expression>
(125)
unit-contract-action
::=
CONTRACT var-name type-name <function-call> <unit-contract-handle-expr>?
(126)
unit-contract-handle-expr
::=
HANDLE var-name
(127)
unit-test-assert
::=
ASSERT <expression> 
>>!<expression>
(128)
unit-test-identical
::=
IDENTICAL <expression> 
>>!<expression>
(129)
unit-test-shove
::=
SHOVE var-name APPLY <member-path> 
>>!<expression>
(130)
unit-test-input
::=
INPUT var-name <unit-test-target-zone> 
>>!<expression>
(131)
unit-test-expect
::=
EXPECT var-name var-name <expression>* <unit-expect-introduce-handler>?
(132)
unit-test-cancel
::=
EXPECT CANCEL var-name
(133)
unit-test-close-card
::=
CLOSE var-name
(134)
unit-expect-introduce-handler
::=
HANDLE introduce-var
(135)
unit-test-match
::=
MATCH var-name <unit-test-match-category> <unit-test-target-zone>? 
>>!<unit-match-free-text>
(136)
unit-test-match-category
::=
HREF
|
IMAGE
|
SCROLL
|
STYLE
|
TEXT
|
TITLE
(137)
unit-test-target-zone
::=
zone-name <unit-test-target-zone-suffix>*
(138)
unit-test-target-zone-suffix
::=
APPLY zone-name <unit-test-target-zone-qualifier>?
|
APPLY NUMBER <unit-test-target-zone-qualifier>?
(139)
unit-test-target-zone-qualifier
::=
COLON zone-name
(140)
unit-match-free-text
::=
FREETEXT
(141)
internal-test-newdiv
::=
NEWDIV NUMBER?
(142)
internal-test-render
::=
RENDER var-name SENDTO template-name
(143)
unit-data-declaration
::=
<unit-expr-data-declaration>
|
<unit-fields-data-declaration>
(144)
unit-expr-data-declaration
::=
DATA <type-reference> var-name SEND <expression> 
(145)
unit-fields-data-declaration
::=
DATA <type-reference> var-name 
>>><unit-fields-data-initializer>
(146)
unit-fields-data-initializer
::=
var-name SEND <expression>
(147)
protocol-test-unit
::=
GUARD
(148)
system-test-configure
::=
CONFIGURE 
>><system-configure-step>
(149)
system-configure-step
::=
<unit-data-declaration>
|
<ajax-configure-step>
(150)
ajax-configure-step
::=
AJAX CREATE var-name STRING 
>><ajax-create-handler>
(151)
system-test-unit
::=
TEST TESTDESCRIPTION  
>><system-test-step>
(152)
system-test-step
::=
<unit-test-assert>
|
<ajax-test-step>
(153)
ajax-test-step
::=
AJAX PUMP var-name
(154)
ajax-create-handler
::=
SUBSCRIBE STRING 
>><ajax-http-options>
(155)
ajax-http-options
::=
<ajax-http-response-list>
(156)
ajax-http-response-list
::=
RESPONSES 
>><object-literal>
(157)
system-test-finally
::=
FINALLY 
>><system-finally-step>
(158)
system-finally-step
::=
FINALLY

Files

FLAS code is organized by files, where each file may hold multiple units for compilation purposes.

(1)
file
::=
<source-file>
|
<assembly-file>
|
<unit-test-file>
|
<protocol-test-file>
|
<system-test-file>

Each type of file can be used to provide specific groups of definitions; other than where expressly allowed, definitions associated with one type of file may not be used in other files.

(2)
source-file
::=
<top-level-unit>*

Source files are used to define all of the production code. Apart from the contents of source code files, only the assembler file is distributed to clients.

Multiple source files may be specified for a single project, but this only provides a convenience to the author(s) and maintainer(s). The compiler treats all top-level definitions is source files as being part of the same scope.

(3)
assembly-file
::=
<assembly-unit>*

Each library or application contains one assembly file which contains meta-information about the project which cannot be gleaned simply from the classes. This being the case, the assembly file does not include such things as lists of dependencies. It does, however, include a routing table which maps URI paths to nests of cards, and actions as the various routes are entered and exited.

(4)
unit-test-file
::=
 <unit-test-unit>*

Unit test files contain multiple test fixtures. These are mainly independent from each other (although the executable tests may depend on the data declarations).

Unit tests are intended to test individual cards, services and agents (as well as other code such as algotithmic functions) in isolation.

All current unit tests must pass before a project can be distributed.

(5)
protocol-test-file
::=
<protocol-test-unit>*

Protocol test files are a work in progress, but the idea is that it should be possible to define, along with a contract, a set of behaviours that it would be reasonable to expect from any implementor of that contract. Thus such a set of tests should be able to take an arbitrary instance of that contract and test that it does indeed pass all the tests.

Each protocol file is given the name of the contract it is intended to test.

While protocol tests are not distributed with the application, they are uploaded to Ziniki servers and used to run tests against cards, services and agents that choose to implement the contract.

(6)
system-test-file
::=
 <system-test-configure>? <system-test-unit>* <system-test-finally>?

System tests complement unit tests by offering insight into the behaviour of a system through one or more storyboards. Each system test has three steps: the configure step ensures that everything is set up correctly (for example services and data stores). The test steps carry out the individual steps of the story and make sure that the correct things happen. The finally step is capable of asserting that the system ends in a desired state.

Note that no cleanup is required at the end of the test, since no actual physical servers or services are created or invoked; everything is run in a local sandbox, just simulating the effects of a multi-node system. For the same reason, these tests are not subject to the vaguaries of system configuration or failure.

On the other hand, that does mean that they do not truly reflect real life, but an idealized version of it.

Scoping

This set of units can be defined at the top level in files or within the scope of a function.

(7)
top-level-unit
::=
<top-level-definition>
|
<function-scope-unit>
(8)
top-level-definition
::=
<struct-declaration>
|
<union-declaration>
|
<entity-declaration>
|
<contract-declaration>
|
<object-declaration>
|
<service-declaration>
|
<agent-declaration>
|
<card-declaration>
(9)
function-scope
::=
<function-scope-unit>*
(10)
function-scope-unit
::=
<function-case-definition>
|
<tuple-definition>
|
<standalone-method-definition>
|
<handler-definition>

Data Declarations

(11)
struct-declaration
::=
STRUCT type-name poly-var* 
>><struct-field-decl>
(12)
entity-declaration
::=
ENTITY type-name poly-var* 
>><struct-field-decl>
(13)
struct-field-decl
::=
<type-reference> var-name <struct-initializer>?
(14)
struct-initializer
::=
SEND <expression>
(15)
union-declaration
::=
UNION type-name 
>>><type-reference>

Contracts

Contracts are core to FLAS.

A contract defines an abstraction of what a card, agent or service does in a way that should be independently testable with tests written against the abstraction.

There are three types of contracts:

  • those that are implemented by cards and agents and can be called by the container;
  • those provided by a service or a providing agent and can be required by cards and then called;
  • those defining how handlers will operate.

In each case, the contract specifies a set of methods which must all be implemented together by the implementing card, agent, service or handler.

Each method must have a method name. It may optionally be marked as optional, meaning that implementers do not need to provide a definition for it. It specifies zero or more arguments; these must be typed, and there are restrictions on the types that may be passed. It may optionally specify a subscription handler. This must be a typed variable where the type is a hander contract.

(16)
contract-declaration
::=
<contract-intro> type-name 
>><contract-method-decl>
(17)
contract-intro
::=
CONTRACT
|
CONTRACT SERVICE
|
CONTRACT HANDLER
(18)
contract-method-decl
::=
OPTIONAL? var-name  <argument-pattern-typed>* <handled-by>? 
(19)
handled-by
::=
HANDLE <argument-pattern-typed>

Functions

Constants and functions can be declared either at the top level or within nested scopes. When declared within a nested scope, all the surrounding variables and definitions are available for reference by name.

Note that a complete function declaration is made up of multiple cases applying to specific patterns. All of the cases must be declared ``together'' without any intervening blocks, but this is not included in this grammar specification.

There are two ways to declare a function case.

It is possible to declare a single expression on the same line as the function declaration.

Or the function name and argument patterns can appear on one line, and one or more guarded equations can appear on subsequent lines.

(20)
function-case-definition
::=
<simple-function-case-definition>
|
<degenerate-guarded-function-case-definition>
|
<guarded-function-case-definition>
(21)
simple-function-case-definition
::=
 var-name   <argument-pattern>*  EQ <expression> 
>><function-scope>
(22)
degenerate-guarded-function-case-definition
::=
var-name   <argument-pattern>*  
>>!<guarded-default-expression>
(23)
guarded-function-case-definition
::=
var-name   <argument-pattern>*  
>>!<guarded-equations>
(24)
guarded-equations
::=
<guarded-expression>+ <guarded-default-expression>? 
>><function-scope>
(25)
guarded-expression
::=
GUARD <expression> EQ <expression> 
(26)
guarded-default-expression
::=
GUARD EQ <expression> 
(27)
tuple-definition
::=
ORB var-name <comma-var-name>+ CRB EQ <expression> 
>><function-scope>
(28)
comma-var-name
::=
COMMA var-name

Patterns

(29)
argument-pattern
::=
<argument-pattern-type-name>
|
<argument-pattern-variable>
|
<argument-pattern-literal>
|
<argument-pattern-list>
|
<argument-pattern-typed>
|
<argument-pattern-ctor>
(30)
argument-pattern-type-name
::=
type-name
(31)
argument-pattern-maybe-typed
::=
<argument-pattern-variable>
|
<argument-pattern-typed>
(32)
argument-pattern-variable
::=
var-name
(33)
argument-pattern-literal
::=
NUMBER
|
STRING
(34)
argument-pattern-list
::=
OSB CSB
|
OSB <argument-pattern> <comma-argument-pattern>* CSB
(35)
comma-argument-pattern
::=
COMMA <argument-pattern>
(36)
argument-pattern-typed
::=
ORB <type-reference> var-name CRB
(37)
argument-pattern-ctor
::=
ORB <type-reference> OCB CCB CRB
|
ORB <type-reference> OCB <field-argument-pattern> <comma-field-argument-pattern>* CCB CRB
(38)
field-argument-pattern
::=
var-name COLON <argument-pattern>
(39)
comma-field-argument-pattern
::=
COMMA <field-argument-pattern>

Types

(40)
type-reference
::=
type-name <poly-type-list>?
|
poly-var
|
<type-reference> ARROW <type-reference>
|
ORB <type-reference> <comma-type-reference>+ CRB
|
ORB <type-reference> CRB
|
<type-member>
(41)
poly-type-list
::=
OSB <type-reference> <comma-type-reference>* CSB
(42)
comma-type-reference
::=
COMMA <type-reference>

Expressions

TODO: We need to include . notation for fields, along with the fact that it has very high priority, so should probably be somewhere around the literal stage. But we don't particularly focus on operator precedence, so including it as a BINOP and noting that is probably fine.

(43)
expression
::=
<literal>
|
<paren-expression>
|
<tuple-expression>
|
<function-call>
|
<get-type-expr>
|
<check-type-expr>
|
<member-expr>
|
UNOP <expression>
|
<expression> BINOP <expression>
|
<expression> COLON <expression>
|
CAST <type-reference> <expression>
(44)
member-expr
::=
<value-expression> APPLY var-name
|
<type-member>
(45)
type-member
::=
<value-expression> APPLY type-name
(46)
function-call
::=
<value-expression> <expression-term>*
(47)
check-type-expr
::=
ISTYPE type-name <expression-term>
(48)
get-type-expr
::=
TYPE type-name
|
TYPE <expression>
(49)
value-expression
::=
var-name
|
type-name
|
<member-expr>
|
ORB <expression> CRB
(50)
paren-expression
::=
ORB <expression> CRB
(51)
expression-term
::=
<literal>
|
var-name
|
type-name
|
<tuple-expression>
|
<member-expr>
|
<paren-expression>
(52)
literal
::=
NUMBER
|
STRING
|
TRUE
|
FALSE
|
<list-literal>
|
<object-literal>
(53)
list-literal
::=
OSB CSB
|
OSB <expression> <comma-expression>* CSB
(54)
tuple-expression
::=
ORB <expression> <comma-expression>+ CRB
(55)
comma-expression
::=
COMMA <expression>
(56)
object-literal
::=
OCB CCB
|
OCB <object-member> <comma-object-member>* CCB
(57)
object-member
::=
<object-key> COLON <expression>
(58)
object-key
::=
var-name
|
STRING
(59)
comma-object-member
::=
COMMA <object-member>

Handler

(60)
handler-definition
::=
HANDLER type-name type-name  <argument-pattern-maybe-typed>*  
>><implementation-method>

Method

Note that standalone and object methods have the same syntax, but they are sufficiently different to make it worth making it clear In rule (70), the second case is supposed to represent the user creating either a single Action object or a list of them. Any other expression will end up being rejected at typecheck. Note that the first case of the rule is not, per se, a valid expression since the service object is not in scope, but actually it will parse as one.
(61)
standalone-method-definition
::=
METHOD  <method-definition>
(62)
object-method-definition
::=
METHOD  <method-definition>
(63)
method-definition
::=
var-name  <argument-pattern>*  
>>!<method-guards-or-actions>
(64)
method-guards-or-actions
::=
<method-guards>
|
<method-actions>
(65)
method-guards
::=
<method-guard>* <method-guard-default>? 
>><function-scope-unit>
(66)
method-guard
::=
GUARD <expression> 
>><method-action>
(67)
method-guard-default
::=
GUARD 
>><method-action>
(68)
method-actions
::=
<method-action>* 
>><function-scope-unit>
(69)
method-action
::=
<message-method-action>
|
<assign-method-action>
(70)
message-method-action
::=
SEND <expression> <maybe-handled>? <maybe-subscribed>? 
(71)
maybe-handled
::=
HANDLE <expression>
(72)
maybe-subscribed
::=
SENDTO <expression>
(73)
assign-method-action
::=
<member-path> SEND <expression> 
(74)
member-path
::=
var-name <member-path-apply>*
(75)
member-path-apply
::=
APPLY var-name

Object

(76)
object-declaration
::=
OBJECT type-name  poly-var* 
>><object-scope-unit>
(77)
object-scope-unit
::=
<state-declaration>
|
<requires-contract>
|
<object-ctor-definition>
|
<named-template-definition>
|
<object-acor-definition>
|
<object-method-definition>
|
<function-case-definition>
|
<handler-definition>
|
<event-handler>
(78)
state-declaration
::=
STATE 
>><struct-field-decl>
(79)
object-ctor-definition
::=
CTOR  <method-definition>
(80)
object-acor-definition
::=
ACOR  <function-case-definition>

Service

(81)
service-declaration
::=
SERVICE type-name 
>><service-scope-unit>
(82)
service-scope-unit
::=
<requires-contract>
|
<provides-contract>
|
<function-scope-unit>
(83)
provides-contract
::=
PROVIDES type-name  
>><implementation-method>

Agent

(84)
agent-declaration
::=
AGENT type-name 
>><agent-scope-unit>
(85)
agent-scope-unit
::=
<state-declaration>
|
<requires-contract>
|
<implements-contract>
|
<service-scope-unit>

Card

(86)
card-declaration
::=
CARD type-name  
>><card-scope-unit>
(87)
card-scope-unit
::=
<named-template-definition>
|
<event-handler>
|
<agent-scope-unit>

Requires Contract

The requires block identifies a contract that this card needs to do its job. It requires a contract name and a variable. The variable can be used in the card to call the service bound to the contract.
(88)
requires-contract
::=
REQUIRES type-name  var-name

Implements Contract

/
(89)
implements-contract
::=
IMPLEMENTS type-name  
>><implementation-method>
(90)
implementation-method
::=
var-name  <argument-pattern-variable>* <implementation-result>?  
>><method-actions>
(91)
implementation-result
::=
HANDLE var-name

Events

An event handler is a special type of method on a card, which can respond to UI events.

Although not part of the grammar, each event will receive an appropriate event object as its final argument.

Event handlers are not called directly by the system but through the template mechanism (see some rule) and are generally curried, in that some arguments are presented as part of the configuration, and the event itself is provided by the system when called.

Although it is not captured in this grammar, event handlers must have exactly one argument, which must be a TypedPattern and the type must be a member of the Event class hierarchy.

(92)
event-handler
::=
EVENT var-name  <argument-pattern-typed>  
>>!<method-guards-or-actions>

Templates

Each card can have zero or more templates. If it has no templates, it cannot have any visual representation.

If it has at least one template, the first template name must be defined as a card in an associated webzip file. Other templates must be associated with items in a webzip file.

Each template consists of a set of binding of values to portions of the template.

Nested templates may have issues accessing their various state members. Ideally, the nested chain of scoped variables should be inferred. However, in certain circumstances, this may not be possible; and in other circumstances shadowing or anonymity of variables may come into play. To solve these problmes, a template may specify variables that are in its enclosing chain. In all circumstances, the validity of the claims made here will be checked by the typechecker. The card's own template will not have any of these problems, and so cannot have this syntax. Item templates may have nesting chains but (top-level) card templates may not

(93)
named-template-definition
::=
TEMPLATE template-name <define-template-chain>?  
>><template-bind>
(94)
define-template-chain
::=
SEND <template-chain-var>+
(95)
template-chain-var
::=
ORB <type-reference> var-name CRB

Template Bindings

Each binding is responsible for filling one slot in the template, which can be of type punnet, container or content.

The first case of rule (96) enables a value to be "assigned" to a slot in the template. The exact semantics of this depend on the slot type; see connecting elements to cards for details.

The second case allows the assignment to be conditional on another expression. In this case, the conditional (first) expression of each case of rule (98), which must be of type boolean, is considered and the first one to evaluate to true is selected. The value (second) expression is then used as the value. The rule (99) may be used to specify a default assignment if none of the previous cases match.

The degenerate (third) case for rule (96) can only be used to customize style elements. In this case the template name is provided and the styles and events are immediate descendants of this.

For container slots only, it is possible to specify an item template that the value should be passed to using rule (100).

Styling and event handling may be added to all elements except punnets, which hand off styling and event handling to their contained cards. In general, this will also not be used with container slots.

(96)
template-bind
::=
template-name SEND <expression> <pass-to-template>? 
>><template-customization>
|
template-name 
>>!<option-template-binds>
|
<template-customization>
(97)
option-template-binds
::=
<option-template-bind>+ <default-option-template-bind>? 
>><template-customization>
|
<default-option-template-bind> 
>><template-customization>
|
<template-customization>
(98)
option-template-bind
::=
GUARD <expression> SEND <expression> <pass-to-template>? 
>>!<option-template-binds>
(99)
default-option-template-bind
::=
SEND <expression> <pass-to-template>? 
(100)
pass-to-template
::=
SENDTO template-name

Template Customization

For content and style elements, it is possible to customize the element by applying styling and adding event handlers.

The various template-style rules define the behaviour for styling. Any number of styling rules may be applied; each will match the expr if supplied and, if not supplied or true, will add the classes identified by the strings to the element's class list.

Styles may then be furhter customized.

Rule (105) defines event handlers. Each of the predefined events can be mapped exactly once per element. The outcome will be the invocation of an event handler defined on the card as var-name. It will receive a set of arguments along with an event object of a type appropriate for the named event.

(101)
template-customization
::=
<template-style-cond>
|
<template-style-format>
|
<template-style-format-or-else>
|
<template-event>
(102)
template-style-cond
::=
GUARD <expression> 
>><template-customization>
(103)
template-style-format
::=
GUARD <expression>? SENDTO <expression>+ 
>><template-customization>
(104)
template-style-format-or-else
::=
GUARD <expression> SENDTO <expression>+ ORELSE <expression>+
(105)
template-event
::=
SENDTO var-name

Assembly Files

Applications and libraries in FLAS are assembled into components using an assembly file.

(106)
assembly-unit
::=
<assembly-application>
|
<assembly-application>
(107)
assembly-application
::=
APPLICATION 
>><assembly-application-scope>
(108)
assembly-application-scope
::=
<assembly-title>
|
<assembly-baseuri>
|
<assembly-routes>
(109)
assembly-title
::=
TITLE STRING
(110)
assembly-baseuri
::=
BASEURI STRING
(111)
assembly-routes
::=
ROUTES 
>><assembly-routing-table>
(112)
assembly-routing-table
::=
<assembly-title>
|
var-name SEND type-name
|
SECURE
|
<assembly-route-enter>
|
<assembly-route-at>
|
<assembly-route-exit>
|
<assembly-route-nested>
(113)
assembly-route-enter
::=
ENTER 
>><assembly-route-actions>
(114)
assembly-route-at
::=
AT 
>><assembly-route-actions>
(115)
assembly-route-exit
::=
EXIT 
>><assembly-route-actions>
(116)
assembly-route-actions
::=
var-name <assembly-route-with-contract>? APPLY <function-call>
(117)
assembly-route-with-contract
::=
APPLY type-name
(118)
assembly-route-nested
::=
ROUTE STRING 
>><assembly-routing-table>

Unit Test Files

Unit Tests are built into the FLAS language with special syntax.

A unit test file in FLAS consists of a number of test and data declarations.

The test declaration defines a unit test which should be run while the data declaration defines a name for a shared element of test data which can be used in multiple tests.

(119)
unit-test-unit
::=
<unit-test-declaration>
|
<unit-test-ignore>
|
<unit-data-declaration>

Unit Tests

Unit Tests are built into the FLAS language with special syntax.

A unit test in FLAS is defined as being a test either:

  • on the behaviour of a function or a standalone method;
  • on the behaviour of a service, card or object method when receiving certain input;
  • on the display of a card or object template in a given state;
  • on the behaviour of a card event handler.

In order to make all these cases easy, the unit test language allows values and messages to be easily defined and has special syntax for isolating and testing message outputs and template orchestration, independent of the actual template HTML provided.

The assert action tests an expression and compares it to an expected value. For convenience, this assertion allows the user to penetrate encapsulation and directly probe card or object state.

The shove action allows a user to directly update card or object state for test purposes. Note that this may allow the test to put the object in a state which cannot be reached by normal operations. This is both a "bug" and a "feature".

The event action simulates a UI input event and dispatches it to the card. The first argument is a variable which is a reference to the card to receive the event. The second is the name of an event handler. The expression will probably construct an event, but it could also be a reference to a data object.

The invoke action invokes a method on an object. This is just described as an "expression" but the semantics are that it must be a valid object method invocation.

The contract action is supposed to invoke a method in a contract on a card. The first argument is a data variable which is a reference to the card to receive the event. The second argument is the name of the contract which will have the event. The third var is the name of the method to invoke on the contract. The expressions are the data elements to send.

The expect action allows expectations to be defined. This specifies a contract, a method and the arguments that are expected.

Notes: Expectations should be available on invoke, event and contract. In these expressions you should be able to specify an _ to say that you don't care what goes there or specify a function name which says that it is a matcher which takes one arg and returns a boolean. These functions should be nested within the expect block. If the pattern matches and true is returned, it's OK. If the patterns don't match and Error is returned, or the function explicitly returns false, the match fails. Obviously, we expect exactly all of the expectations to happen.

We seem to have omitted tests on the HTML: all based on the "match" command text or styles (the ones specified by the program) IT DOES NOT REFERENCE HTML allow an optional selector - which is a path through the fields in the split HTML allow the keyword "contains" Subsequent indented lines are white-space approximation of the content or value Examples: match text match html match html contains match html ... contains match style ...

(120)
unit-test-declaration
::=
TEST TESTDESCRIPTION  
>><unit-test-step>
(121)
unit-test-ignore
::=
IGNORE TESTDESCRIPTION  
>><unit-test-step>
(122)
unit-test-step
::=
<unit-data-declaration>
|
<unit-event-action>
|
<unit-invoke-action>
|
<unit-contract-action>
|
<unit-test-assert>
|
<unit-test-identical>
|
<unit-test-shove>
|
<unit-test-input>
|
<unit-test-expect>
|
<unit-test-cancel>
|
<unit-test-close-card>
|
<unit-test-match>
|
<internal-test-newdiv>
|
<internal-test-render>
(123)
unit-event-action
::=
EVENT var-name <unit-test-target-zone> <expression>
(124)
unit-invoke-action
::=
INVOKE <expression>
(125)
unit-contract-action
::=
CONTRACT var-name type-name <function-call> <unit-contract-handle-expr>?
(126)
unit-contract-handle-expr
::=
HANDLE var-name
(127)
unit-test-assert
::=
ASSERT <expression> 
>>!<expression>
(128)
unit-test-identical
::=
IDENTICAL <expression> 
>>!<expression>
(129)
unit-test-shove
::=
SHOVE var-name APPLY <member-path> 
>>!<expression>
(130)
unit-test-input
::=
INPUT var-name <unit-test-target-zone> 
>>!<expression>
(131)
unit-test-expect
::=
EXPECT var-name var-name <expression>* <unit-expect-introduce-handler>?
(132)
unit-test-cancel
::=
EXPECT CANCEL var-name
(133)
unit-test-close-card
::=
CLOSE var-name
(134)
unit-expect-introduce-handler
::=
HANDLE introduce-var
(135)
unit-test-match
::=
MATCH var-name <unit-test-match-category> <unit-test-target-zone>? 
>>!<unit-match-free-text>
(136)
unit-test-match-category
::=
HREF
|
IMAGE
|
SCROLL
|
STYLE
|
TEXT
|
TITLE
(137)
unit-test-target-zone
::=
zone-name <unit-test-target-zone-suffix>*
(138)
unit-test-target-zone-suffix
::=
APPLY zone-name <unit-test-target-zone-qualifier>?
|
APPLY NUMBER <unit-test-target-zone-qualifier>?
(139)
unit-test-target-zone-qualifier
::=
COLON zone-name
(140)
unit-match-free-text
::=
FREETEXT

Internal Tests

In addition to standard user tests, FLAS includes some test operations that are primarily aimed at FLAS developers.

As a user, you are welcome to use these to validate your expectations, but you will not be able to use their results to adjust the behavior of your code.

(141)
internal-test-newdiv
::=
NEWDIV NUMBER?
(142)
internal-test-render
::=
RENDER var-name SENDTO template-name

Unit Test Data

Declare a variable in test scope either as the result of a simple expression or by creating a compound object with field assignments.

I feel the expression case possibly needs to be expanded to allow for object constructors to be invoked.
(143)
unit-data-declaration
::=
<unit-expr-data-declaration>
|
<unit-fields-data-declaration>
(144)
unit-expr-data-declaration
::=
DATA <type-reference> var-name SEND <expression> 
(145)
unit-fields-data-declaration
::=
DATA <type-reference> var-name 
>>><unit-fields-data-initializer>
(146)
unit-fields-data-initializer
::=
var-name SEND <expression>

Protocol Tests

Much of what defines FLAS is the concept of the contract.

There are many implementations of any given contract, but there should be certain characteristics common to all implementations of a contract.

The purpose of protocol tests is to verify that for any given contract, all the implementations of the contract obey those invariants.

Thus protocol tests are written in the context of a contract in a given direction, but then automatically applied to all implementations of that contract: objects, services and cards.

informally, basically, I just want to say that if you do this sequence of things to a contract, it will respond appropriately. It's more complex than that, but hopefully when I have some real examples, it will become clear.
(147)
protocol-test-unit
::=
GUARD

System Tests

System tests define end-to-end storyboard tests.

They can come in two varieties: with or without a backend.

In either case, the actions of both ends are actually defined in the test, it's just a question of where the service layer stops and is replaced by "mocks" implemented in the test.

I haven't really thought this through, but I'm sure it will again become apparent when I want to write one.
(148)
system-test-configure
::=
CONFIGURE 
>><system-configure-step>
(149)
system-configure-step
::=
<unit-data-declaration>
|
<ajax-configure-step>
(150)
ajax-configure-step
::=
AJAX CREATE var-name STRING 
>><ajax-create-handler>
(151)
system-test-unit
::=
TEST TESTDESCRIPTION  
>><system-test-step>
(152)
system-test-step
::=
<unit-test-assert>
|
<ajax-test-step>
(153)
ajax-test-step
::=
AJAX PUMP var-name
(154)
ajax-create-handler
::=
SUBSCRIBE STRING 
>><ajax-http-options>
(155)
ajax-http-options
::=
<ajax-http-response-list>
(156)
ajax-http-response-list
::=
RESPONSES 
>><object-literal>
(157)
system-test-finally
::=
FINALLY 
>><system-finally-step>
(158)
system-finally-step
::=
FINALLY