The acor keyword introduces an object accessor function.
The agent keyword introduces an agent declaration.
The ajax keyword creates or access an AJAX server in a system test.
The application keyword introduces an application in an assembly file.
The apply operator.
ARROW is used to describe function types.
The assert keyword introduces an assert step in a unit test.
The at keyword is used in assembly files to indicate actions carried out at a particular route.
The baseuri keyword is used in an assembly file to identify the base URI of the application.
One of the standard binary operators. They have precedence, but this is not apparent from the grammar.
We should specify the precedence here.
The CANCEL operator is used to specify expectations that a subscription will be cancelled.
The card keyword introduces a card definition.
The cast function states that the expression should be given a specific compile-time type which will be checked at runtime.
A closing curly bracket delimits the end of a constructor pattern or object creation.
The CLOSE command is used in unit tests to close a card.
Can be an operator or can be used to define object literals.
Separates similar items in a list.
The system test keyword configure.
The contract keyword introduces a contract declaration.
It is also used in unit tests to invoke a contract method on a card or service.
A closing round bracket delimits the end of an expression or pattern.
The ajax system test keyword create.
A closing square bracket delimits the end of a list operation or polymorphic variable list.
The ctor keyword introduces an object constructor declaration.
The data keyword introduces a data declaration in a unit test.
The enter keyword is used in assembly files to indicate actions carried out when first entering particular route.
The entity keyword introduces an entity definition.
Defines the variable/function definition operator.
The event keyword introduces an event handler.
The exit keyword is used in assembly files to indicate actions carried out when leaving a particular route.
The expect keyword introduces a mock expectation.
The boolean literal False.
The system test keyword finally.
Free text spread across multiple lines which can be used to match HTML output from a template.
Defines the variable/function definition operator.
The HANDLE operator is used to assign subscription handles to handle variables.
The handler keyword introduces a callback handler.
href is a keyword used with the match unit test command to match hyperlink text.
The identical keyword introduces an assertion that two expressions refer to the same node.
The ignore keyword causes a unit test to be ignored.
image is a keyword used with the match unit test command to match image URIs.
The implements keyword introduces a contract implementation in a card.
The input keyword allows tests to enter data into boxes.
The invoke keyword is used in unit tests to invoke a method on an object.
istype is a special function for testing the runtime type of an expression.
The match keyword introduces a template matching step in a unit test.
The method keyword introduces a standalone method definition.
The newdiv keyword is used in internal testing.
A numeric literal.
The object keyword introduces an object declaration.
An opening curly bracket introduces a constructor pattern match or object creation.
The optional keyword indicates that a contract method does not need to be implemented.
An opening square bracket introduces a sub-element of an expression or pattern.
The ORELSE token allows simple alternative styling patterns.
An opening square bracket introduces various list operations as well as polymorphic variables.
The provides keyword introduces a block indicating that the service portion of a contract will be provided.
The ajax system test keyword pump.
The render keyword is used to force cards to render in tests.
The requires keyword identifies a variable which is bound to a service of the specified contract.
The ajax system test keyword create.
The route keyword introduces a nested route in a routing table in an assembly file.
The routes keyword introduces a routing table in an assembly file.
scroll is a keyword used with the match unit test command to check on where the window has scrolled to.
scroll is a keyword used with the match unit test command to check on where the window has scrolled to.
Method actions, variable assignments and template definitions are defined using the SEND operator.
The SENDTO operator is used to pass things around in templates.
The service keyword introduces a service declaration.
The shove keyword is used in unit tests to directly affect object or card state.
The state keyword introduces a card or object state.
A string literal.
The struct keyword introduces a struct declaration.
The style keyword is used to match card styles.
The system test keyword subscribe.
The template keyword introduces a template definition.
The test keyword introduces a unit test case.
The test keyword introduces a unit test case.
The text keyword is used to match text on a card.
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.
The boolean literal True.
The type keyword is used to turn a type name literal into a type object.
The union keyword introduces a union declaration.
One of the standard unary operators. They have precedence, but this is not apparent from the grammar.
We should specify the precedence here.
Function and variable names are one or more characters, where the first character must be a lower case alphabetic character.
Polymorphic variable names must be one or two capital letters.
The name of a template or template item, which must match the name of a provided webzip element.
Concrete type names must start with a capital letter and have at least two characters in the name.
Function and variable names are one or more characters, where the first character must be a lower case alphabetic character.
Function and variable names are one or more characters, where the first character must be a lower case alphabetic character.
FLAS code is organized by files, where each file may hold multiple units for compilation purposes.
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.
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.
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.
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.
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.
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.
This set of units can be defined at the top level in files or within the scope of a function.
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:
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.
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.
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.
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.
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
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.
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.
Applications and libraries in FLAS are assembled into components using an assembly file.
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.
Unit Tests are built into the FLAS language with special syntax.
A unit test in FLAS is defined as being a test either:
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 ...
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.
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.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.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.