// List of users that are allowed to request an echo. How this list
// list.
allowedUsers = getAllowedUsers();
// The message is accepted only if the user is allowed. In case it is
// not, the message will not match the rule and will be just ignored.
observe this accepts m:Post{UserName in allowedUsers}
{
unechoed += [m.Content];
}
// When an Echo is issued, to be sure its content is unechoed
// add an assertion to validate this logic.
observe this issues m:Echo{}
{
assert m.Content in unechoed;
unechoed = unechoed.Remove(m.Content);
}
}
The contract on the endpoint assures that only data that has been posted can be echoed. Observe that since this is our top-level protocol, we do not need process rules to consume messages and dispatch them up the stack.
Next, the parsing actor is defined that maps from a TCP socket to the echo endpoint. This parser will be automatically started on a socket that uses the port for the Echo protocol.
// This is the actor that listens on the server socket indexed by
// the EchoPort.
actor autostart EchoServerParser(
Socket serverSocket where value.SourcePort == EchoPort)
{
// A MiniTCP Segment is matched, the Payload is decoded to a Post
// message and dispatched to EchoServer.
process serverSocket accepts Segment{Payload is m:Post
from BinaryDecoder}
{
dispatch (endpoint EchoServer over socket) accepts m;
}
// A similar rule for the other direction.
//...
}
Language Reference
Lexis
Lexical Unit
LexicalUnit ::= LexicalElement*
LexicalElement ::= Whitespace | Comment | Token
Token ::= Identifier | Keyword | Literal | OperatorOrPunctuator
Whitespace
Whitespace ::= any charater with Unicode class Zs
| tab characters (U+0009, U+000B)
| formfeed character (U+000C)
| Newline
NewLine ::= carriage return (U+000D)
| line feed (U+000A),
| next line (U+0085)
Comment ::= SingleLineComment | MultiLineComment
SingleLineComment ::= // (! NewLine)*
MultiLineComment ::= /* ( ! */ )* */
Literals
Literal ::= BooleanLiteral | IntegerLiteral | FractionalLiteral | CharacterLiteral | StringLiteral
| NullLiteral | NothingLiteral | BinaryLiteral | GuidLiteral | DecimalLiteral
BooleanLiteral ::= true | false
IntegerLiteral ::= Sign? DecimalDigit+ | ( 0x | 0X ) HexDigit+ | ( 0b | 0B ) BinaryDigit+
| (0o | 0O) OctetDigit+
FractionalLiteral ::= Sign? DecimalDigit* . DecimalDigit+ Exponent?
DecimalLiteral ::= FractionalLiteral (m | M) | Sign? DecimalDigit+ (m | M)
Exponent ::= ( e | E ) Sign? DecimalDigit+
Sign ::= + | -
BinaryDigit ::= 0 | 1
OctetDigit ::= BinaryDigit | 2 |3 |4 |5 |6 |7
DecimalDigit ::= OctetDigit |8 |9
HexDigit ::= DecimalDigit | a | A |b | B |c | C |d |D |e |E|f |F
CharacterLiteral ::= ' ( ! ' & VisibleCharacter | \' | CharacterEscape ) '
CharacterEscape ::= \xHexDigit#4 | \xHexDigit#8 | \CharacterEscapeControl
CharacterEscapeControl ::= 0 | a |b | f | n | r |t |v
StringLiteral ::= SingleLineStringLiteral | MultilineStringLiteral
SingleLineStringLiteral ::= " ( ! " & VisibleCharacter | \" | CharacterEscape )* " MultiLineStringLiteral ::=
@ " ( ! " & VisibleCharacter | \" | Newline | CharacterEscape )* "
BlockLiteral ::= { ( \} | \{ | \\ | VisibleCharater | NewLine | BlockLiteral )* }
NullLiteral ::= null
NothingLiteral ::= nothing
BinaryLiteral ::= $[ ( HexDigit HexDigit )* ] | Base64Literal
Base64Literal ::= TO BE DONE
GuidLiteral ::= { HexDigit#8 - HexDigit#4 - HexDigit#4 - HexDigit#4 - HexDigit#12 }
VisibleCharacter ::= TO BE DONE (specify unicodes)
Newline ::= TO BE DONE (specify unicodes for CR or CR LF)
The intention of the BlockLiteral is to allow embedding of an alien grammar within OPN. It allows nesting braces without escaping as long as the braces are balanced. If this is not the case, writers have to escape unbalanced braces. The same rule holds for the backslash ( \ ), and can be escaped, that is (\\), if needed.
Identifiers and Keywords
QualifiedIdentifier ::= Identifier ( . Identifier )*
Identifier ::= KeywordOrIdentifier without Keyword | @ KeywordOrIdentifier | $ StringLiteral
KeywordOrIdentifier ::= IdentifierBegin IdentifierContinue* IdentifierEnd | IdentifierSingle
IdentifierBegin ::= one of _ Letter
IdentifierContinue ::= one of Letter DecimalDigit
IdentifierEnd = one of _ Letter DecimalDigit
IdentifierSingle = Letter
Letter ::= unicode character of class Lu, Ll, Lt, Lm, Lo, Nl, Mn, Mc, Pc, Cf
Keyword ::= any of:
abstract accepts actor annotation any array as aspect assert autostart
binary binding bool break byte
case catch change char connection const consumes continue contract
decimal default delete dispatch do double
enum else endpoint error exception extends extern
false finally flags float from for foreach follows
get guid
if in int interface internal invariant is issues
json
long
map metadata message module
new nothing null
observe operation operator over override
pattern precedes process protocol provides public
regex ref return role rule
sbyte select set short static string success switch syntax
throw treedata true try type typedef
uint ulong using ushort
value var virtual void
where while with
xml xpath
WeakKeyword::= any of:
all bind create exists freeze optional out result some start stop this ignore separator
Operators and Punctuators
Note that multi-character operators (for example &&, >=, #.., and so on) should be considered as single tokens, and therefore they do not allow spaces or tabs interleaved.
OperatorOrPunctuator ::= any of:
{ } [ ] ( ) . , + - * / % ! = < > & ^ ; # ` ?
&& || == != <= >= => | & ^ ==> <=> ~ .. ... << >> += -= ++ -- ?? #? #..