blob: a8e3c16a67b93149c03ed547030d257cb9bf1287 [file] [log] [blame]
syntax SPL(k = 0) {
primitiveTemplate identifier for String default using NAME:
value = "%token%";
primitiveTemplate stringSymbol for String using STRING:
value = "%token%",
serializer="'\'' + %value%.toCString() + '\''";
primitiveTemplate uriSymbol for String using URI:
value = "%token%",
serializer="'\'' + %value%.toCString() + '\''";
primitiveTemplate headerIdSymbol for String using HEADERID:
value = "%token%",
serializer="'\'' + %value%.toCString() + '\''";
primitiveTemplate integerSymbol for Integer default using INT:
value = "Integer.valueOf(%token%)";
template Program main
: service
;
template Service context
: "service" name "{" [
[ "processing" "{" ] {indentIncr = 0, startNL = false, endNL = false, nbNL = 0} [
declarations
sessions
] {nbNL = 2} "}"
] "}"
;
-- @begin Sessions
template Session abstract;
template Registration context
: "registration" "{" [
declarations
sessions
] {nbNL = 2} "}"
;
template Dialog context
: "dialog" "{" [
declarations
methods
] {nbNL = 2} "}"
;
template Event
: "event" eventId
"{" [
declarations
methods
] {nbNL = 2} "}"
;
-- @begin Methods
template Method context
: $methodHeader
"{" [
(isDefined(branches) ?
branches
:
statements
)
] "}"
;
-- template SimpleMethod
-- : $methodHeader "{" [
-- statements
-- ] "}"
-- ;
-- template ComposedMethod
-- : $methodHeader "{" [
-- branches
-- ] "}"
-- ;
function methodHeader(Method)
: type
(direction = #in ?
"incoming"
:
(direction = #out ?
"outgoing"
:
-- inout
)
)
methodName
"(" arguments{separator = ","} ")"
;
template Argument addToContext
: type name
;
-- @begin Method Names
template MethodName abstract;
template SIPMethodName
: name
;
template ControlMethodName
: name
;
-- @end Method Names
-- @end Methods
-- @end Sessions
-- @begin Branches
template Branch abstract;
template DefaultBranch
: "branch" "default"
"{" statements "}"
;
template NamedBranch
: "branch" name{separator = "|"}
"{" statements "}"
;
-- @end Branches
-- @begin Declarations
template Declaration abstract;
template VariableDeclaration addToContext
: type name (isDefined(initExp) ? "=" initExp) ";"
;
-- @begin FunctionDeclarations
template FunctionDeclaration abstract;
template RemoteFunctionDeclaration addToContext
: functionLocation returnType name "(" arguments{separator = ","} ")" ";"
;
template LocalFunctionDeclaration addToContext
: returnType name "(" arguments{separator = ","} ")" "{" [
statements
] "}"
;
-- @end FunctionDeclarations
-- @begin StructureDeclarations
template StructureDeclaration
: "type" name "{" [
properties
] "}"
;
template StructureProperty
: type name ";"
;
-- @end StructureDeclarations
-- @end Declarations
-- @begin Statements
template Statement abstract;
template CompoundStat
: "{" [ statements ] "}"
;
template SetStat
: target "=" setValue ";"
;
template DeclarationStat
: declaration
;
template ReturnStat
: "return"
(isDefined(returnedValue) ? returnedValue)
(isDefined(branch) ? "branch" branch{refersTo = name, autoCreate = ifmissing})
";"
;
template IfStat
: "if" "(" condition ")" [
thenStatement
]
(isDefined(elseStatement) ?
"else" [
elseStatement
]
)
;
template WhenStat context
: "when" idExp "(" whenHeaders{separator = ","} ")" "{" [
statements
] "}"
(isDefined(elseStatement) ?
"else" [
elseStatement
]
)
;
template WhenHeader addToContext
: headerId{as = headerIdSymbol} type name (isDefined(value) ? value)
;
template ForeachStat context
: "foreach" "(" iterator "in" sequenceExp ")" "{" [
statements
] "}"
;
template Iterator addToContext
: name
;
template SelectStat
: "select" "(" matchedExp ")" "{" [
selectCases
(isDefined(selectDefault) ?
selectDefault
)
] "}"
;
template SelectCase
: "case" values{separator = "|"} ":" [ statements ]
;
template SelectDefault
: "default" ":" [ statements ]
;
template FunctionCallStat
: functionCall ";"
;
template ContinueStat
: "continue" ";"
;
template BreakStat
: "break" ";"
;
template PushStat
: "push" target pushedValue ";"
;
-- @end Statements
-- @begin Expressions
template Expression abstract operatored;
template ConstantExp
: value
;
operatorTemplate OperatorExp(operators =
-- opPoint opRarrow
opNot opMinus1
opStar opSlash
opPlus opMinus2
opEq opGt opLt opGe opLe opNe
opAnd opOr
opMatch opNoMatch
, source = leftExp, storeOpTo = opName, storeRightTo = rightExp);
-- must be nonPrimary because it finishes (or may finish) by an expression
template ForwardExp nonPrimary
: (isParallel ? "parallel") "forward" (isDefined(exp) ? exp)
;
-- must be operatorTemplate because it is left recursive
operatorTemplate WithExp(operators = opWith, source = exp)
: "{" msgFields{separator = ","} "}"
;
template MessageField abstract;
template ReasonMessageField
: "reason" "=" exp
;
template HeadedMessageField
: headerId{as = headerIdSymbol} exp
;
-- TODO: BlockExp?
template ReasonExp
: "reason"
;
template BODYExp
: "BODY"
;
template RequestURIExp
: "requestURI"
;
template PopExp
: "pop" source
;
template FunctionCallExp
: functionCall
;
template FunctionCall
: function{refersTo = name} "(" parameters{separator = ","} ")"
;
template Place abstract;
template SIPHeaderPlace
: header
;
template VariablePlace abstract;
template Variable
: source{refersTo = name}
;
-- template PropertyCallPlace
-- : -- TODO
-- ;
-- @end Expressions
-- @begin Constants
template Constant abstract;
template BooleanConstant
: (value ? "true" : "false")
;
template IntegerConstant
: value
;
template StringConstant
: value{as = stringSymbol}
;
template URIConstant
: uri{as = uriSymbol}
;
template SequenceConstant
: "<" values{separator = ","} ">"
;
template ResponseConstant
: response
;
-- @end Constants
-- @begin Responses
template Response abstract;
template SuccessResponse abstract
: "/" <no_space> "SUCCESS"
(isDefined(successKind) ? <no_space> "/" <no_space> successKind)
;
template ErrorResponse abstract
: "/" <no_space> "ERROR"
;
template ClientErrorResponse
: "/" <no_space> "ERROR" <no_space> "/" <no_space> "CLIENT"
(isDefined(errorKind) ? <no_space> "/" <no_space> errorKind)
;
template GlobalErrorResponse
: "/" <no_space> "ERROR" <no_space> "/" <no_space> "GLOBAL"
(isDefined(errorKind) ? <no_space> "/" <no_space> errorKind)
;
template RedirectionErrorResponse
: "/" <no_space> "ERROR" <no_space> "/" <no_space> "REDIRECTION"
(isDefined(errorKind) ? <no_space> "/" <no_space> errorKind)
;
template ServerErrorResponse
: "/" <no_space> "ERROR" <no_space> "/" <no_space> "SERVER"
(isDefined(errorKind) ? <no_space> "/" <no_space> errorKind)
;
-- @end Responses
-- @begin Types
template TypeExpression abstract;
template SimpleType
: type
;
template SequenceType
: (isDefined(modifier) ?
modifier
)
type "<" (isDefined(size) ? size) ">"
;
enumerationTemplate Modifier auto
: #LIFO = "LIFO",
#FIFO = "FIFO"
;
-- @end Types
enumerationTemplate SIPMethod auto
: #ACK = "ACK",
#BYE = "BYE",
#CANCEL = "CANCEL",
#INVITE = "INVITE",
#NOTIFY = "NOTIFY",
#OPTIONS = "OPTIONS",
#REACK = "REACK",
#REGISTER = "REGISTER",
#REINVITE = "REINVITE",
#RESUBSCRIBE = "RESUBSCRIBE",
#SUBSCRIBE = "SUBSCRIBE"
;
enumerationTemplate ControlMethod auto
: #deploy = "deploy",
#undeploy = "undeploy",
#uninvite = "uninvite",
#unregister = "unregister",
#unsubscribe = "unsubscribe"
;
enumerationTemplate FunctionLocation auto
: #remote = "remote",
#local = "local"
;
enumerationTemplate SuccessKind auto
: #OK = "OK",
#ACCEPTED = "ACCEPTED"
;
enumerationTemplate ClientErrorKind auto
: #ADDRESS_INCOMPLETE = "ADDRESS_INCOMPLETE",
#AMBIGUOUS = "AMBIGUOUS",
#BAD_EXTENSION = "BAD_EXTENSION",
#BAD_REQUEST = "BAD_REQUEST",
#BUSY_HERE = "BUSY_HERE",
#CALL_OR_TRANSACTION_DOES_NOT_EXIST = "CALL_OR_TRANSACTION_DOES_NOT_EXIST",
#EXTENSION_REQUIRED = "EXTENSION_REQUIRED",
#FORBIDDEN = "FORBIDDEN",
#GONE = "GONE",
#INTERVAL_TOO_BRIEF = "INTERVAL_TOO_BRIEF",
#LOOP_DETECTED = "LOOP_DETECTED",
#METHOD_NOT_ALLOWED = "METHOD_NOT_ALLOWED",
#NOT_ACCEPTABLE_HERE = "NOT_ACCEPTABLE_HERE",
#NOT_ACCEPTABLE = "NOT_ACCEPTABLE",
#NOT_FOUND = "NOT_FOUND",
#PAYMENT_REQUIRED = "PAYMENT_REQUIRED",
#PROXY_AUTHENTICATION_REQUIRED = "PROXY_AUTHENTICATION_REQUIRED",
#REQUESTURI_TOO_LONG = "REQUESTURI_TOO_LONG",
#REQUEST_ENTITY_TOO_LARGE = "REQUEST_ENTITY_TOO_LARGE",
#REQUEST_PENDING = "REQUEST_PENDING",
#REQUEST_TERMINATED = "REQUEST_TERMINATED",
#REQUEST_TIMEOUT = "REQUEST_TIMEOUT",
#TEMPORARILY_UNAVAILABLE = "TEMPORARILY_UNAVAILABLE",
#TOO_MANY_HOPS = "TOO_MANY_HOPS",
#UNAUTHORIZED = "UNAUTHORIZED",
#UNDECIPHERABLE = "UNDECIPHERABLE",
#UNSUPPORTED_MEDIA_TYPE = "UNSUPPORTED_MEDIA_TYPE",
#UNSUPPORTED_URI_SCHEME = "UNSUPPORTED_URI_SCHEME"
;
enumerationTemplate GlobalErrorKind auto
: #BUSY_EVERYWHERE = "BUSY_EVERYWHERE",
#DECLINE = "DECLINE",
#DOES_NOT_EXIST_ANYWHERE = "DOES_NOT_EXIST_ANYWHERE",
#NOT_ACCEPTABLE = "NOT_ACCEPTABLE"
;
enumerationTemplate RedirectionErrorKind auto
: #ALTERNATIVE_SERVICE = "ALTERNATIVE_SERVICE",
#MOVED_PERMANENTLY = "MOVED_PERMANENTLY",
#MOVED_TEMPORARILY = "MOVED_TEMPORARILY",
#MULTIPLE_CHOICES = "MULTIPLE_CHOICES",
#USE_PROXY = "USE_PROXY"
;
enumerationTemplate ServerErrorKind auto
: #BAD_GATEWAY = "BAD_GATEWAY",
#MESSAGE_TOO_LARGE = "MESSAGE_TOO_LARGE",
#NOT_IMPLEMENTED = "NOT_IMPLEMENTED",
#SERVER_INTERNAL_ERROR = "SERVER_INTERNAL_ERROR",
#SERVER_TIMEOUT = "SERVER_TIMEOUT",
#SERVICE_UNAVAILABLE = "SERVICE_UNAVAILABLE",
#VERSION_NOT_SUPPORTED = "VERSION_NOT_SUPPORTED"
;
enumerationTemplate SIPHeader auto
: #CALL_ID = "CALL_ID",
#CONTACT = "CONTACT",
#CSEQ = "CSEQ",
#EVENT = "EVENT",
#FROM = "FROM",
#MAX_FORWARDS = "MAX_FORWARDS",
#SUBSCRIPTION_STATE = "SUBSCRIPTION_STATE",
#TO = "TO",
#VIA = "VIA"
;
enumerationTemplate PrimitiveType auto
: #void = "void",
#bool = "bool",
#int = "int",
#request = "request",
#response = "response",
#string = "string",
#time = "time",
#uri = "uri"
;
symbols {
lsquare = "[";
rsquare = "]" : rightSpace;
excl = "!";
coma = "," : leftNone, rightSpace;
lparen = "(";
rparen = ")" : leftNone, rightSpace;
lcurly = "{" : leftSpace;
rcurly = "}" : leftNone, rightSpace;
semi = ";" : leftNone, rightSpace;
colon = ":" : leftNone, rightSpace;
colons = "::";
pipe = "|" : leftSpace, rightSpace;
sharp = "#" : leftSpace;
qmark = "?";
-- operator symbols
point = "." : leftNone;
rarrow = "->" : leftNone;
minus = "-" : leftSpace, rightSpace;
star = "*" : leftSpace, rightSpace;
slash = "/" : leftSpace, rightSpace;
plus = "+" : leftSpace, rightSpace;
eq = "=" : leftSpace, rightSpace;
eqeq = "==";
gt = ">" : leftSpace, rightSpace;
lt = "<" : leftSpace, rightSpace;
ge = ">=" : leftSpace, rightSpace;
le = "<=" : leftSpace, rightSpace;
ne = "!=" : leftSpace, rightSpace;
larrow = "<-" : leftSpace, rightSpace;
ampamp = "&&";
pipepipe = "||";
}
operators {
priority 0 { -- 0 is highest
-- opPoint = point, 2;
-- opRarrow = rarrow, 2;
opWith = "with", 2;
}
priority 1 {
opNot = excl, 1; -- no corresponding symbol => symbol is the keyword defined by the quoted string (which is also the name)
opMinus1 = minus, 1;
}
priority 2 {
opStar = star, 2;
opSlash = slash, 2;
}
priority 3 {
opPlus = plus, 2;
opMinus2 = minus, 2;
}
priority 4 {
opEq = eqeq, 2;
opGt = gt, 2;
opLt = lt, 2;
opGe = ge, 2;
opLe = le, 2;
opNe = ne, 2;
}
priority 5 {
opAnd = ampamp, 2;
opOr = pipepipe, 2;
}
priority 6 {
opMatch = "match", 2;
opNoMatch = "nomatch", 2;
}
}
token NAME : word(
start = [alpha] | "_",
part = [alnum] | "_"
, words = ("true" : BOOLEAN, "false" : BOOLEAN)
);
token COMMENT : endOfLine(start = "//") | multiLine(start = "/*", end = "*/");
token URI : multiLine(start = "\'", end = "\'");
token HEADERID : word(
start = "#",
part = [alnum] | "_" | "!" | "%" | "*" | "-" | "+" | "'" | "`" | "~",
end = ":"
);
lexer = "
%options testLiterals = false;
NL
: ( '\\r' '\\n'
| '\\n' '\\r' //Improbable
| '\\r'
| '\\n'
)
{newline();}
;
WS
: ( ' '
| '\\t'
)
;
%protected
DIGIT
: '0'..'9'
;
INT
: (DIGIT)+
;
%protected
ESC
: '\\\\'!
( 'n' %v2{%setText(\"\\n\");}
| 'r' %v2{%setText(\"\\r\");}
| 't' %v2{%setText(\"\\t\");}
| 'b' %v2{%setText(\"\\b\");}
| 'f' %v2{%setText(\"\\f\");}
| '\"' %v2{%setText(\"\\\"\");}
| '\\.' %v2{%setText(\".\");} // SPL-specific
| '\\'' %v2{%setText(\"\\'\");}
| '\\\\' %v2{%setText(\"\\\\\");}
| (
('0'..'3')
(
%v2 options {
%v2 warnWhenFollowAmbig = false;
%v2 }
: ('0'..'7')
(
%v2 options {
%v2 warnWhenFollowAmbig = false;
%v2 }
: '0'..'7'
)?
)?
| ('4'..'7')
(
%v2 options {
%v2 warnWhenFollowAmbig = false;
%v2 }
: ('0'..'7')
)?
)
{
%v2 String s = %getText;
%v2 int i;
%v2 int ret = 0;
%v2 String ans;
%v2 for (i=0; i<s.length(); ++i)
%v2 ret = ret*8 + s.charAt(i) - '0';
%v2 ans = String.valueOf((char) ret);
%v2 %setText(ans);
}
)
;
STRING
: '\\\"'!
( ESC
| '\\n' {newline();}
| ~('\\\\'|'\\\"'|'\\n')
)*
'\\\"'!
%v3 {setText(ei.unescapeString(getText(), 1));}
;
";
}