mirror of
https://github.com/classilla/tenfourfox.git
synced 2024-06-06 22:29:34 +00:00
780 lines
21 KiB
Python
780 lines
21 KiB
Python
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
import os, sys
|
|
from ply import lex, yacc
|
|
|
|
from ipdl.ast import *
|
|
|
|
def _getcallerpath():
|
|
'''Return the absolute path of the file containing the code that
|
|
**CALLED** this function.'''
|
|
return os.path.abspath(sys._getframe(1).f_code.co_filename)
|
|
|
|
##-----------------------------------------------------------------------------
|
|
|
|
class ParseError(Exception):
|
|
def __init__(self, loc, fmt, *args):
|
|
self.loc = loc
|
|
self.error = ('%s%s: error: %s'% (
|
|
Parser.includeStackString(), loc, fmt)) % args
|
|
def __str__(self):
|
|
return self.error
|
|
|
|
def _safeLinenoValue(t):
|
|
lineno, value = 0, '???'
|
|
if hasattr(t, 'lineno'): lineno = t.lineno
|
|
if hasattr(t, 'value'): value = t.value
|
|
return lineno, value
|
|
|
|
def _error(loc, fmt, *args):
|
|
raise ParseError(loc, fmt, *args)
|
|
|
|
class Parser:
|
|
# when we reach an |include [protocol] foo;| statement, we need to
|
|
# save the current parser state and create a new one. this "stack" is
|
|
# where that state is saved
|
|
#
|
|
# there is one Parser per file
|
|
current = None
|
|
parseStack = [ ]
|
|
parsed = { }
|
|
|
|
def __init__(self, type, name, debug=0):
|
|
assert type and name
|
|
self.type = type
|
|
self.debug = debug
|
|
self.filename = None
|
|
self.includedirs = None
|
|
self.loc = None # not always up to date
|
|
self.lexer = None
|
|
self.parser = None
|
|
self.tu = TranslationUnit(type, name)
|
|
self.direction = None
|
|
self.errout = None
|
|
|
|
def parse(self, input, filename, includedirs, errout):
|
|
assert os.path.isabs(filename)
|
|
|
|
if filename in Parser.parsed:
|
|
return Parser.parsed[filename].tu
|
|
|
|
self.lexer = lex.lex(debug=self.debug,
|
|
optimize=not self.debug,
|
|
lextab="ipdl_lextab")
|
|
self.parser = yacc.yacc(debug=self.debug,
|
|
optimize=not self.debug,
|
|
tabmodule="ipdl_yacctab")
|
|
self.filename = filename
|
|
self.includedirs = includedirs
|
|
self.tu.filename = filename
|
|
self.errout = errout
|
|
|
|
Parser.parsed[filename] = self
|
|
Parser.parseStack.append(Parser.current)
|
|
Parser.current = self
|
|
|
|
try:
|
|
ast = self.parser.parse(input=input, lexer=self.lexer,
|
|
debug=self.debug)
|
|
except ParseError, p:
|
|
print >>errout, p
|
|
return None
|
|
|
|
Parser.current = Parser.parseStack.pop()
|
|
return ast
|
|
|
|
def resolveIncludePath(self, filepath):
|
|
'''Return the absolute path from which the possibly partial
|
|
|filepath| should be read, or |None| if |filepath| cannot be located.'''
|
|
for incdir in self.includedirs +[ '' ]:
|
|
realpath = os.path.join(incdir, filepath)
|
|
if os.path.isfile(realpath):
|
|
return os.path.abspath(realpath)
|
|
return None
|
|
|
|
# returns a GCC-style string representation of the include stack.
|
|
# e.g.,
|
|
# in file included from 'foo.ipdl', line 120:
|
|
# in file included from 'bar.ipd', line 12:
|
|
# which can be printed above a proper error message or warning
|
|
@staticmethod
|
|
def includeStackString():
|
|
s = ''
|
|
for parse in Parser.parseStack[1:]:
|
|
s += " in file included from `%s', line %d:\n"% (
|
|
parse.loc.filename, parse.loc.lineno)
|
|
return s
|
|
|
|
def locFromTok(p, num):
|
|
return Loc(Parser.current.filename, p.lineno(num))
|
|
|
|
|
|
##-----------------------------------------------------------------------------
|
|
|
|
reserved = set((
|
|
'answer',
|
|
'as',
|
|
'async',
|
|
'both',
|
|
'bridges',
|
|
'call',
|
|
'child',
|
|
'class',
|
|
'compress',
|
|
'compressall',
|
|
'__delete__',
|
|
'delete', # reserve 'delete' to prevent its use
|
|
'from',
|
|
'goto',
|
|
'high',
|
|
'include',
|
|
'intr',
|
|
'manager',
|
|
'manages',
|
|
'namespace',
|
|
'normal',
|
|
'nullable',
|
|
'opens',
|
|
'or',
|
|
'parent',
|
|
'prio',
|
|
'protocol',
|
|
'recv',
|
|
'returns',
|
|
'send',
|
|
'spawns',
|
|
'start',
|
|
'state',
|
|
'struct',
|
|
'sync',
|
|
'union',
|
|
'upto',
|
|
'urgent',
|
|
'using'))
|
|
tokens = [
|
|
'COLONCOLON', 'ID', 'STRING',
|
|
] + [ r.upper() for r in reserved ]
|
|
|
|
t_COLONCOLON = '::'
|
|
|
|
literals = '(){}[]<>;:,~'
|
|
t_ignore = ' \f\t\v'
|
|
|
|
def t_linecomment(t):
|
|
r'//[^\n]*'
|
|
|
|
def t_multilinecomment(t):
|
|
r'/\*(\n|.)*?\*/'
|
|
t.lexer.lineno += t.value.count('\n')
|
|
|
|
def t_NL(t):
|
|
r'(?:\r\n|\n|\n)+'
|
|
t.lexer.lineno += len(t.value)
|
|
|
|
def t_ID(t):
|
|
r'[a-zA-Z_][a-zA-Z0-9_]*'
|
|
if t.value in reserved:
|
|
t.type = t.value.upper()
|
|
return t
|
|
|
|
def t_STRING(t):
|
|
r'"[^"\n]*"'
|
|
t.value = t.value[1:-1]
|
|
return t
|
|
|
|
def t_error(t):
|
|
_error(Loc(Parser.current.filename, t.lineno),
|
|
'lexically invalid characters `%s', t.value)
|
|
|
|
##-----------------------------------------------------------------------------
|
|
|
|
def p_TranslationUnit(p):
|
|
"""TranslationUnit : Preamble NamespacedStuff"""
|
|
tu = Parser.current.tu
|
|
tu.loc = Loc(tu.filename)
|
|
for stmt in p[1]:
|
|
if isinstance(stmt, CxxInclude):
|
|
tu.addCxxInclude(stmt)
|
|
elif isinstance(stmt, Include):
|
|
tu.addInclude(stmt)
|
|
elif isinstance(stmt, UsingStmt):
|
|
tu.addUsingStmt(stmt)
|
|
else:
|
|
assert 0
|
|
|
|
for thing in p[2]:
|
|
if isinstance(thing, StructDecl):
|
|
tu.addStructDecl(thing)
|
|
elif isinstance(thing, UnionDecl):
|
|
tu.addUnionDecl(thing)
|
|
elif isinstance(thing, Protocol):
|
|
if tu.protocol is not None:
|
|
_error(thing.loc, "only one protocol definition per file")
|
|
tu.protocol = thing
|
|
else:
|
|
assert(0)
|
|
|
|
# The "canonical" namespace of the tu, what it's considered to be
|
|
# in for the purposes of C++: |#include "foo/bar/TU.h"|
|
|
if tu.protocol:
|
|
assert tu.filetype == 'protocol'
|
|
tu.namespaces = tu.protocol.namespaces
|
|
tu.name = tu.protocol.name
|
|
else:
|
|
assert tu.filetype == 'header'
|
|
# There's not really a canonical "thing" in headers. So
|
|
# somewhat arbitrarily use the namespace of the last
|
|
# interesting thing that was declared.
|
|
for thing in reversed(tu.structsAndUnions):
|
|
tu.namespaces = thing.namespaces
|
|
break
|
|
|
|
p[0] = tu
|
|
|
|
##--------------------
|
|
## Preamble
|
|
def p_Preamble(p):
|
|
"""Preamble : Preamble PreambleStmt ';'
|
|
|"""
|
|
if 1 == len(p):
|
|
p[0] = [ ]
|
|
else:
|
|
p[1].append(p[2])
|
|
p[0] = p[1]
|
|
|
|
def p_PreambleStmt(p):
|
|
"""PreambleStmt : CxxIncludeStmt
|
|
| IncludeStmt
|
|
| UsingStmt"""
|
|
p[0] = p[1]
|
|
|
|
def p_CxxIncludeStmt(p):
|
|
"""CxxIncludeStmt : INCLUDE STRING"""
|
|
p[0] = CxxInclude(locFromTok(p, 1), p[2])
|
|
|
|
def p_IncludeStmt(p):
|
|
"""IncludeStmt : INCLUDE PROTOCOL ID
|
|
| INCLUDE ID"""
|
|
loc = locFromTok(p, 1)
|
|
|
|
Parser.current.loc = loc
|
|
if 4 == len(p):
|
|
id = p[3]
|
|
type = 'protocol'
|
|
else:
|
|
id = p[2]
|
|
type = 'header'
|
|
inc = Include(loc, type, id)
|
|
|
|
path = Parser.current.resolveIncludePath(inc.file)
|
|
if path is None:
|
|
raise ParseError(loc, "can't locate include file `%s'"% (
|
|
inc.file))
|
|
|
|
inc.tu = Parser(type, id).parse(open(path).read(), path, Parser.current.includedirs, Parser.current.errout)
|
|
p[0] = inc
|
|
|
|
def p_UsingStmt(p):
|
|
"""UsingStmt : USING CxxType FROM STRING
|
|
| USING CLASS CxxType FROM STRING
|
|
| USING STRUCT CxxType FROM STRING"""
|
|
if 6 == len(p):
|
|
header = p[5]
|
|
elif 5 == len(p):
|
|
header = p[4]
|
|
else:
|
|
header = None
|
|
if 6 == len(p):
|
|
kind = p[2]
|
|
else:
|
|
kind = None
|
|
if 6 == len(p):
|
|
cxxtype = p[3]
|
|
else:
|
|
cxxtype = p[2]
|
|
p[0] = UsingStmt(locFromTok(p, 1), cxxtype, header, kind)
|
|
|
|
##--------------------
|
|
## Namespaced stuff
|
|
def p_NamespacedStuff(p):
|
|
"""NamespacedStuff : NamespacedStuff NamespaceThing
|
|
| NamespaceThing"""
|
|
if 2 == len(p):
|
|
p[0] = p[1]
|
|
else:
|
|
p[1].extend(p[2])
|
|
p[0] = p[1]
|
|
|
|
def p_NamespaceThing(p):
|
|
"""NamespaceThing : NAMESPACE ID '{' NamespacedStuff '}'
|
|
| StructDecl
|
|
| UnionDecl
|
|
| ProtocolDefn"""
|
|
if 2 == len(p):
|
|
p[0] = [ p[1] ]
|
|
else:
|
|
for thing in p[4]:
|
|
thing.addOuterNamespace(Namespace(locFromTok(p, 1), p[2]))
|
|
p[0] = p[4]
|
|
|
|
def p_StructDecl(p):
|
|
"""StructDecl : STRUCT ID '{' StructFields '}' ';'
|
|
| STRUCT ID '{' '}' ';'"""
|
|
if 7 == len(p):
|
|
p[0] = StructDecl(locFromTok(p, 1), p[2], p[4])
|
|
else:
|
|
p[0] = StructDecl(locFromTok(p, 1), p[2], [ ])
|
|
|
|
def p_StructFields(p):
|
|
"""StructFields : StructFields StructField ';'
|
|
| StructField ';'"""
|
|
if 3 == len(p):
|
|
p[0] = [ p[1] ]
|
|
else:
|
|
p[1].append(p[2])
|
|
p[0] = p[1]
|
|
|
|
def p_StructField(p):
|
|
"""StructField : Type ID"""
|
|
p[0] = StructField(locFromTok(p, 1), p[1], p[2])
|
|
|
|
def p_UnionDecl(p):
|
|
"""UnionDecl : UNION ID '{' ComponentTypes '}' ';'"""
|
|
p[0] = UnionDecl(locFromTok(p, 1), p[2], p[4])
|
|
|
|
def p_ComponentTypes(p):
|
|
"""ComponentTypes : ComponentTypes Type ';'
|
|
| Type ';'"""
|
|
if 3 == len(p):
|
|
p[0] = [ p[1] ]
|
|
else:
|
|
p[1].append(p[2])
|
|
p[0] = p[1]
|
|
|
|
def p_ProtocolDefn(p):
|
|
"""ProtocolDefn : OptionalProtocolSendSemanticsQual PROTOCOL ID '{' ProtocolBody '}' ';'"""
|
|
protocol = p[5]
|
|
protocol.loc = locFromTok(p, 2)
|
|
protocol.name = p[3]
|
|
protocol.priorityRange = p[1][0]
|
|
protocol.sendSemantics = p[1][1]
|
|
p[0] = protocol
|
|
|
|
if Parser.current.type == 'header':
|
|
_error(protocol.loc, 'can\'t define a protocol in a header. Do it in a protocol spec instead.')
|
|
|
|
|
|
def p_ProtocolBody(p):
|
|
"""ProtocolBody : SpawnsStmtsOpt"""
|
|
p[0] = p[1]
|
|
|
|
##--------------------
|
|
## spawns/bridges/opens stmts
|
|
|
|
def p_SpawnsStmtsOpt(p):
|
|
"""SpawnsStmtsOpt : SpawnsStmt SpawnsStmtsOpt
|
|
| BridgesStmtsOpt"""
|
|
if 2 == len(p):
|
|
p[0] = p[1]
|
|
else:
|
|
p[2].spawnsStmts.insert(0, p[1])
|
|
p[0] = p[2]
|
|
|
|
def p_SpawnsStmt(p):
|
|
"""SpawnsStmt : PARENT SPAWNS ID AsOpt ';'
|
|
| CHILD SPAWNS ID AsOpt ';'"""
|
|
p[0] = SpawnsStmt(locFromTok(p, 1), p[1], p[3], p[4])
|
|
|
|
def p_AsOpt(p):
|
|
"""AsOpt : AS PARENT
|
|
| AS CHILD
|
|
| """
|
|
if 3 == len(p):
|
|
p[0] = p[2]
|
|
else:
|
|
p[0] = 'child'
|
|
|
|
def p_BridgesStmtsOpt(p):
|
|
"""BridgesStmtsOpt : BridgesStmt BridgesStmtsOpt
|
|
| OpensStmtsOpt"""
|
|
if 2 == len(p):
|
|
p[0] = p[1]
|
|
else:
|
|
p[2].bridgesStmts.insert(0, p[1])
|
|
p[0] = p[2]
|
|
|
|
def p_BridgesStmt(p):
|
|
"""BridgesStmt : BRIDGES ID ',' ID ';'"""
|
|
p[0] = BridgesStmt(locFromTok(p, 1), p[2], p[4])
|
|
|
|
def p_OpensStmtsOpt(p):
|
|
"""OpensStmtsOpt : OpensStmt OpensStmtsOpt
|
|
| ManagersStmtOpt"""
|
|
if 2 == len(p):
|
|
p[0] = p[1]
|
|
else:
|
|
p[2].opensStmts.insert(0, p[1])
|
|
p[0] = p[2]
|
|
|
|
def p_OpensStmt(p):
|
|
"""OpensStmt : PARENT OPENS ID ';'
|
|
| CHILD OPENS ID ';'"""
|
|
p[0] = OpensStmt(locFromTok(p, 1), p[1], p[3])
|
|
|
|
##--------------------
|
|
## manager/manages stmts
|
|
|
|
def p_ManagersStmtOpt(p):
|
|
"""ManagersStmtOpt : ManagersStmt ManagesStmtsOpt
|
|
| ManagesStmtsOpt"""
|
|
if 2 == len(p):
|
|
p[0] = p[1]
|
|
else:
|
|
p[2].managers = p[1]
|
|
p[0] = p[2]
|
|
|
|
def p_ManagersStmt(p):
|
|
"""ManagersStmt : MANAGER ManagerList ';'"""
|
|
if 1 == len(p):
|
|
p[0] = [ ]
|
|
else:
|
|
p[0] = p[2]
|
|
|
|
def p_ManagerList(p):
|
|
"""ManagerList : ID
|
|
| ManagerList OR ID"""
|
|
if 2 == len(p):
|
|
p[0] = [ Manager(locFromTok(p, 1), p[1]) ]
|
|
else:
|
|
p[1].append(Manager(locFromTok(p, 3), p[3]))
|
|
p[0] = p[1]
|
|
|
|
def p_ManagesStmtsOpt(p):
|
|
"""ManagesStmtsOpt : ManagesStmt ManagesStmtsOpt
|
|
| MessageDeclsOpt"""
|
|
if 2 == len(p):
|
|
p[0] = p[1]
|
|
else:
|
|
p[2].managesStmts.insert(0, p[1])
|
|
p[0] = p[2]
|
|
|
|
def p_ManagesStmt(p):
|
|
"""ManagesStmt : MANAGES ID ';'"""
|
|
p[0] = ManagesStmt(locFromTok(p, 1), p[2])
|
|
|
|
|
|
##--------------------
|
|
## Message decls
|
|
|
|
def p_MessageDeclsOpt(p):
|
|
"""MessageDeclsOpt : MessageDeclThing MessageDeclsOpt
|
|
| TransitionStmtsOpt"""
|
|
if 2 == len(p):
|
|
p[0] = p[1]
|
|
else:
|
|
p[2].messageDecls.insert(0, p[1])
|
|
p[0] = p[2]
|
|
|
|
def p_MessageDeclThing(p):
|
|
"""MessageDeclThing : MessageDirectionLabel ':' MessageDecl ';'
|
|
| MessageDecl ';'"""
|
|
if 3 == len(p):
|
|
p[0] = p[1]
|
|
else:
|
|
p[0] = p[3]
|
|
|
|
def p_MessageDirectionLabel(p):
|
|
"""MessageDirectionLabel : PARENT
|
|
| CHILD
|
|
| BOTH"""
|
|
if p[1] == 'parent':
|
|
Parser.current.direction = IN
|
|
elif p[1] == 'child':
|
|
Parser.current.direction = OUT
|
|
elif p[1] == 'both':
|
|
Parser.current.direction = INOUT
|
|
else:
|
|
assert 0
|
|
|
|
def p_MessageDecl(p):
|
|
"""MessageDecl : OptionalSendSemanticsQual MessageBody"""
|
|
msg = p[2]
|
|
msg.priority = p[1][0]
|
|
msg.sendSemantics = p[1][1]
|
|
|
|
if Parser.current.direction is None:
|
|
_error(msg.loc, 'missing message direction')
|
|
msg.direction = Parser.current.direction
|
|
|
|
p[0] = msg
|
|
|
|
def p_MessageBody(p):
|
|
"""MessageBody : MessageId MessageInParams MessageOutParams OptionalMessageCompress"""
|
|
# FIXME/cjones: need better loc info: use one of the quals
|
|
loc, name = p[1]
|
|
msg = MessageDecl(loc)
|
|
msg.name = name
|
|
msg.addInParams(p[2])
|
|
msg.addOutParams(p[3])
|
|
msg.compress = p[4]
|
|
|
|
p[0] = msg
|
|
|
|
def p_MessageId(p):
|
|
"""MessageId : ID
|
|
| __DELETE__
|
|
| DELETE
|
|
| '~' ID"""
|
|
loc = locFromTok(p, 1)
|
|
if 3 == len(p):
|
|
_error(loc, "sorry, `%s()' destructor syntax is a relic from a bygone era. Declare `__delete__()' in the `%s' protocol instead", p[1]+p[2], p[2])
|
|
elif 'delete' == p[1]:
|
|
_error(loc, "`delete' is a reserved identifier")
|
|
p[0] = [ loc, p[1] ]
|
|
|
|
def p_MessageInParams(p):
|
|
"""MessageInParams : '(' ParamList ')'"""
|
|
p[0] = p[2]
|
|
|
|
def p_MessageOutParams(p):
|
|
"""MessageOutParams : RETURNS '(' ParamList ')'
|
|
| """
|
|
if 1 == len(p):
|
|
p[0] = [ ]
|
|
else:
|
|
p[0] = p[3]
|
|
|
|
def p_OptionalMessageCompress(p):
|
|
"""OptionalMessageCompress : MessageCompress
|
|
| """
|
|
if 1 == len(p):
|
|
p[0] = ''
|
|
else:
|
|
p[0] = p[1]
|
|
|
|
def p_MessageCompress(p):
|
|
"""MessageCompress : COMPRESS
|
|
| COMPRESSALL"""
|
|
p[0] = p[1]
|
|
|
|
##--------------------
|
|
## State machine
|
|
|
|
def p_TransitionStmtsOpt(p):
|
|
"""TransitionStmtsOpt : TransitionStmt TransitionStmtsOpt
|
|
|"""
|
|
if 1 == len(p):
|
|
# we fill in |loc| in the Protocol rule
|
|
p[0] = Protocol(None)
|
|
else:
|
|
p[2].transitionStmts.insert(0, p[1])
|
|
p[0] = p[2]
|
|
|
|
def p_TransitionStmt(p):
|
|
"""TransitionStmt : OptionalStart STATE State ':' Transitions"""
|
|
p[3].start = p[1]
|
|
p[0] = TransitionStmt(locFromTok(p, 2), p[3], p[5])
|
|
|
|
def p_OptionalStart(p):
|
|
"""OptionalStart : START
|
|
| """
|
|
p[0] = (len(p) == 2) # True iff 'start' specified
|
|
|
|
def p_Transitions(p):
|
|
"""Transitions : Transitions Transition
|
|
| Transition"""
|
|
if 3 == len(p):
|
|
p[1].append(p[2])
|
|
p[0] = p[1]
|
|
else:
|
|
p[0] = [ p[1] ]
|
|
|
|
def p_Transition(p):
|
|
"""Transition : Trigger ID GOTO StateList ';'
|
|
| Trigger __DELETE__ ';'
|
|
| Trigger DELETE ';'"""
|
|
if 'delete' == p[2]:
|
|
_error(locFromTok(p, 1), "`delete' is a reserved identifier")
|
|
|
|
loc, trigger = p[1]
|
|
if 6 == len(p):
|
|
nextstates = p[4]
|
|
else:
|
|
nextstates = [ State.DEAD ]
|
|
p[0] = Transition(loc, trigger, p[2], nextstates)
|
|
|
|
def p_Trigger(p):
|
|
"""Trigger : SEND
|
|
| RECV
|
|
| CALL
|
|
| ANSWER"""
|
|
p[0] = [ locFromTok(p, 1), Transition.nameToTrigger(p[1]) ]
|
|
|
|
def p_StateList(p):
|
|
"""StateList : StateList OR State
|
|
| State"""
|
|
if 2 == len(p):
|
|
p[0] = [ p[1] ]
|
|
else:
|
|
p[1].append(p[3])
|
|
p[0] = p[1]
|
|
|
|
def p_State(p):
|
|
"""State : ID"""
|
|
p[0] = State(locFromTok(p, 1), p[1])
|
|
|
|
##--------------------
|
|
## Minor stuff
|
|
def p_Priority(p):
|
|
"""Priority : NORMAL
|
|
| HIGH
|
|
| URGENT"""
|
|
prios = {'normal': 1,
|
|
'high': 2,
|
|
'urgent': 3}
|
|
p[0] = prios[p[1]]
|
|
|
|
def p_OptionalSendSemanticsQual(p):
|
|
"""OptionalSendSemanticsQual : SendSemanticsQual
|
|
| """
|
|
if 2 == len(p): p[0] = p[1]
|
|
else: p[0] = [ NORMAL_PRIORITY, ASYNC ]
|
|
|
|
def p_SendSemanticsQual(p):
|
|
"""SendSemanticsQual : ASYNC
|
|
| SYNC
|
|
| PRIO '(' Priority ')' ASYNC
|
|
| PRIO '(' Priority ')' SYNC
|
|
| INTR"""
|
|
if p[1] == 'prio':
|
|
mtype = p[5]
|
|
prio = p[3]
|
|
else:
|
|
mtype = p[1]
|
|
prio = NORMAL_PRIORITY
|
|
|
|
if mtype == 'async': mtype = ASYNC
|
|
elif mtype == 'sync': mtype = SYNC
|
|
elif mtype == 'intr': mtype = INTR
|
|
else: assert 0
|
|
|
|
p[0] = [ prio, mtype ]
|
|
|
|
def p_OptionalProtocolSendSemanticsQual(p):
|
|
"""OptionalProtocolSendSemanticsQual : ProtocolSendSemanticsQual
|
|
| """
|
|
if 2 == len(p): p[0] = p[1]
|
|
else: p[0] = [ (NORMAL_PRIORITY, NORMAL_PRIORITY), ASYNC ]
|
|
|
|
def p_ProtocolSendSemanticsQual(p):
|
|
"""ProtocolSendSemanticsQual : ASYNC
|
|
| SYNC
|
|
| PRIO '(' Priority UPTO Priority ')' ASYNC
|
|
| PRIO '(' Priority UPTO Priority ')' SYNC
|
|
| PRIO '(' Priority UPTO Priority ')' INTR
|
|
| INTR"""
|
|
if p[1] == 'prio':
|
|
mtype = p[7]
|
|
prio = (p[3], p[5])
|
|
else:
|
|
mtype = p[1]
|
|
prio = (NORMAL_PRIORITY, NORMAL_PRIORITY)
|
|
|
|
if mtype == 'async': mtype = ASYNC
|
|
elif mtype == 'sync': mtype = SYNC
|
|
elif mtype == 'intr': mtype = INTR
|
|
else: assert 0
|
|
|
|
p[0] = [ prio, mtype ]
|
|
|
|
def p_ParamList(p):
|
|
"""ParamList : ParamList ',' Param
|
|
| Param
|
|
| """
|
|
if 1 == len(p):
|
|
p[0] = [ ]
|
|
elif 2 == len(p):
|
|
p[0] = [ p[1] ]
|
|
else:
|
|
p[1].append(p[3])
|
|
p[0] = p[1]
|
|
|
|
def p_Param(p):
|
|
"""Param : Type ID"""
|
|
p[0] = Param(locFromTok(p, 1), p[1], p[2])
|
|
|
|
def p_Type(p):
|
|
"""Type : MaybeNullable BasicType"""
|
|
# only actor types are nullable; we check this in the type checker
|
|
p[2].nullable = p[1]
|
|
p[0] = p[2]
|
|
|
|
def p_BasicType(p):
|
|
"""BasicType : ScalarType
|
|
| ScalarType '[' ']'"""
|
|
if 4 == len(p):
|
|
p[1].array = 1
|
|
p[0] = p[1]
|
|
|
|
def p_ScalarType(p):
|
|
"""ScalarType : ActorType
|
|
| CxxID""" # ID == CxxType; we forbid qnames here,
|
|
# in favor of the |using| declaration
|
|
if isinstance(p[1], TypeSpec):
|
|
p[0] = p[1]
|
|
else:
|
|
loc, id = p[1]
|
|
p[0] = TypeSpec(loc, QualifiedId(loc, id))
|
|
|
|
def p_ActorType(p):
|
|
"""ActorType : ID ':' State"""
|
|
loc = locFromTok(p, 1)
|
|
p[0] = TypeSpec(loc, QualifiedId(loc, p[1]), state=p[3])
|
|
|
|
def p_MaybeNullable(p):
|
|
"""MaybeNullable : NULLABLE
|
|
| """
|
|
p[0] = (2 == len(p))
|
|
|
|
##--------------------
|
|
## C++ stuff
|
|
def p_CxxType(p):
|
|
"""CxxType : QualifiedID
|
|
| CxxID"""
|
|
if isinstance(p[1], QualifiedId):
|
|
p[0] = TypeSpec(p[1].loc, p[1])
|
|
else:
|
|
loc, id = p[1]
|
|
p[0] = TypeSpec(loc, QualifiedId(loc, id))
|
|
|
|
def p_QualifiedID(p):
|
|
"""QualifiedID : QualifiedID COLONCOLON CxxID
|
|
| CxxID COLONCOLON CxxID"""
|
|
if isinstance(p[1], QualifiedId):
|
|
loc, id = p[3]
|
|
p[1].qualify(id)
|
|
p[0] = p[1]
|
|
else:
|
|
loc1, id1 = p[1]
|
|
_, id2 = p[3]
|
|
p[0] = QualifiedId(loc1, id2, [ id1 ])
|
|
|
|
def p_CxxID(p):
|
|
"""CxxID : ID
|
|
| CxxTemplateInst"""
|
|
if isinstance(p[1], tuple):
|
|
p[0] = p[1]
|
|
else:
|
|
p[0] = (locFromTok(p, 1), str(p[1]))
|
|
|
|
def p_CxxTemplateInst(p):
|
|
"""CxxTemplateInst : ID '<' ID '>'"""
|
|
p[0] = (locFromTok(p, 1), str(p[1]) +'<'+ str(p[3]) +'>')
|
|
|
|
def p_error(t):
|
|
lineno, value = _safeLinenoValue(t)
|
|
_error(Loc(Parser.current.filename, lineno),
|
|
"bad syntax near `%s'", value)
|