Ejemplo n.º 1
0
 def _method_decl(self, decl, ctx):
     af = decl.access_flags
     if self.is_interface():
         af |= consts.ACC_ABSTRACT
     function = decl.prepare_function(ctx,
                                      is_method_of=self,
                                      static=bool(af & consts.ACC_STATIC))
     m = Method(function, af, self)
     meth_id = function.get_identifier()
     if meth_id in self.methods:
         raise CompilerError("Cannot redeclare %s::%s" %
                             (self.name, function.name))
     self.methods[meth_id] = m
     #
     if m.is_abstract():
         if m.is_private():
             raise CompilerError("Abstract function %s cannot be "
                                 "declared private" % (m.repr()))
         elif decl.body is not None:
             raise CompilerError("Abstract function %s cannot "
                                 "contain body" % (m.repr()))
     else:
         if decl.body is None:
             raise CompilerError("Non-abstract method %s must "
                                 "contain body" % (m.repr()))
Ejemplo n.º 2
0
 def _property_decl(self, decl, ctx):
     if self.is_interface():
         raise CompilerError("Interfaces may not include member variables")
     name = decl.name
     if name in self.properties:
         raise CompilerError("Cannot redeclare %s::$%s" % (self.name, name))
     if decl.expr is None:
         w_initial_value = ctx.space.w_Null
     else:
         w_initial_value = decl.expr.wrap(ctx, ctx.space)
     self._make_property((name, decl.access_flags), w_initial_value)
Ejemplo n.º 3
0
 def use_alias(self, name, short_name):
     id = short_name.lower()
     for decl in self.classes:
         if decl.get_short_name().lower() == id and decl.name != name:
             raise CompilerError("Cannot use %s as %s because the name is "
                                 "already in use" % (name, short_name))
     self.use_aliases[short_name] = name
Ejemplo n.º 4
0
 def _property_decl(self, decl, ctx):
     if self.is_interface():
         raise CompilerError("Interfaces may not include member variables")
     name = decl.name
     if name in self.property_decl:
         raise CompilerError("Cannot redeclare %s::$%s" % (self.name, name))
     if decl.expr is None:
         w_initial_value = ctx.space.w_Null
     else:
         w_initial_value = decl.expr.wrap(ctx, ctx.space)
     p = PropertyDeclaration(name, decl.access_flags, w_initial_value)
     if p.is_abstract():
         raise CompilerError("Properties cannot be declared abstract")
     if p.is_final():
         raise CompilerError("Cannot declare property %s::$%s final, "
                             "the final modifier is allowed only for "
                             "methods and classes" % (self.name, decl.name))
     self.property_decl[name] = p
Ejemplo n.º 5
0
 def _check_method(self, m):
     ONE_ARGS = ('__isset', '__unset')
     NO_ARGS = ('__clone', '__destruct')
     func = m.func
     arity = len(func.get_signature().args)
     ident = func.get_identifier()
     if ident in ONE_ARGS and arity != 1:
         raise CompilerError("Method %s::%s() must take "
                             "exactly 1 argument" % (self.name, func.name))
     if ident in NO_ARGS and arity != 0:
         raise CompilerError("Method %s::%s() cannot accept any arguments" %
                             (self.name, func.name))
     if ident == '__destruct' and m.is_static():
         raise CompilerError("Destructor %s::%s() cannot be static" %
                             (self.name, func.name))
     if ident == '__clone' and m.is_static():
         raise CompilerError("Clone method %s::%s() cannot be static" %
                             (self.name, func.name))
Ejemplo n.º 6
0
 def _check_abstract_local(self):
     if self.is_abstract():
         return
     abstract_methods = []
     for decl in self.method_decl.itervalues():
         if decl.is_abstract():
             abstract_methods.append("%s::%s" % (self.name, decl.func.name))
     if abstract_methods:
         msg = _msg_abstract(self.name, abstract_methods)
         raise CompilerError(msg)
Ejemplo n.º 7
0
 def _check_abstract_local(self):
     if self.is_abstract():
         return
     abstract_methods = []
     for m in self.methods.itervalues():
         if m.is_abstract():
             abstract_methods.append("%s::%s" % (self.name, m.get_name()))
     if abstract_methods:
         msg = _msg_abstract(self.name, abstract_methods)
         raise CompilerError(msg)
Ejemplo n.º 8
0
 def create_bytecode(self):
     if self.pending_gotos:
         raise CompilerError("'goto' to undefined label '%s'" %
                             (self.pending_gotos.keys()[0], ))
     return ByteCode("".join(self.data), self.consts[:], self.names[:],
                     self.varnames[:], self.decls, self.classes,
                     self.functions, self.filename, self.sourcelines,
                     self.method_of_class, self.startlineno,
                     self.lineno_map[:], self.name, self.superglobals,
                     self.this_var_num, self.static_vars)
Ejemplo n.º 9
0
 def _init_constructor(self):
     if '__construct' in self.methods:
         method = self.methods['__construct']
     elif self.get_identifier() in self.methods:
         method = self.methods[self.get_identifier()]
     else:
         return
     if method.is_static():
         raise CompilerError("Constructor %s cannot be static" %
                             (method.repr()))
     self.constructor_method = method
Ejemplo n.º 10
0
 def _init_constructor(self):
     if '__construct' in self.method_decl:
         method = self.method_decl['__construct']
     elif self.get_identifier() in self.method_decl:
         method = self.method_decl[self.get_identifier()]
     else:
         return
     if method.is_static():
         raise CompilerError("Constructor %s::%s() cannot be static" %
                             (self.name, method.func.name))
     self.ctor_id = method.func.get_identifier()
Ejemplo n.º 11
0
 def prepare_function(ctx, name, argdecls, closuredecls, lineno,
                      returns_reference, body, is_method_of=None,
                      static=False):
     new_context = CompilerContext(ctx.filename, ctx.sourcelines, lineno,
                                   ctx.space, name, is_global=False)
     args = []
     typehints = []
     for i, arg in enumerate(argdecls):
         assert isinstance(arg, Argument)
         name = arg.name
         if arg.is_reference:
             opcode = consts.ARG_REFERENCE
         else:
             opcode = consts.ARG_ARGUMENT
         if arg.defaultvalue is None:
             w_default = None
         else:
             w_default = arg.defaultvalue.wrap(ctx, ctx.space)
         if arg.typehint is not None:
             typehints.append((i, arg.typehint,
                             w_default is ctx.space.w_Null))
         args.append((opcode, name, w_default))
         if not new_context.force_var_name(name):
             ctx.warn("Argument list contains twice '$%s'" % (name,))
     if is_method_of is not None:
         new_context.method_of_class = is_method_of
         new_context.current_class = is_method_of
         if not static:
             new_context.this_var_num = len(argdecls)
             if not new_context.force_var_name("this"):
                 raise CompilerError("Cannot re-assign $this")
     new_context.returns_reference = returns_reference
     #
     if body is not None:
         for decl in closuredecls:
             new_context.force_var_name(decl.name)
         #
         for i, typehint, allow_null in typehints:
             j = i * 2 + allow_null
             if typehint == 'array':
                 new_context.emit(consts.TYPEHINT_ARRAY, j)
             else:
                 new_context.emit(consts.LOAD_NAME,
                                 new_context.create_name(typehint))
                 new_context.emit(consts.TYPEHINT_CLASS, j)
         #
         body.compile(new_context)
         new_context.emit(consts.LOAD_NULL)
         new_context.emit(consts.RETURN)
     else:
         new_context.emit(consts.ABSTRACT_METHOD)
     bytecode = new_context.create_bytecode()
     return Function(args, closuredecls, typehints, bytecode)
Ejemplo n.º 12
0
 def patch_with(self, pos, a):
     assert self.data[pos - 3] == '\xA0'
     assert self.data[pos - 2] == '\x8C'
     assert self.data[pos - 1] == '\x07'
     self.data[pos - 3] = chr((a & 0x7f) | 0x80)
     a ^= 0x80
     a >>= 7
     self.data[pos - 2] = chr((a & 0x7f) | 0x80)
     a ^= 0x80
     a >>= 7
     if a >= 0x80:
         raise CompilerError("Internal error: bytecode too big")
     self.data[pos - 1] = chr(a)
Ejemplo n.º 13
0
 def _compile_method(self, decl, ctx):
     if self.is_interface():
         decl.access_flags |= consts.ACC_ABSTRACT
     meth_id = decl.name.lower()
     if meth_id in self.method_decl:
         raise CompilerError("Cannot redeclare %s::%s()" %
                             (self.name, decl.name))
     if decl.is_abstract():
         if decl.is_private():
             raise CompilerError("Abstract function %s::%s() cannot be "
                                 "declared private" %
                                 (self.name, decl.name))
         elif decl.body is not None:
             raise CompilerError("Abstract function %s::%s() cannot "
                                 "contain body" % (self.name, decl.name))
     else:
         if decl.body is None:
             raise CompilerError("Non-abstract method %s::%s() must "
                                 "contain body" % (self.name, decl.name))
     function = decl.prepare_function(ctx, is_method_of=self)
     m = MethodDeclaration(function, decl.access_flags, self)
     self._check_method(m)
     self.method_decl[meth_id] = m
Ejemplo n.º 14
0
 def initialize(self, node, ctx):
     self.access_flags = node.access_flags
     self.extends_name = node.extends
     self.base_interface_names = node.baseinterfaces
     for decl in node.body.getstmtlist():
         if isinstance(decl, ConstDecl):
             if decl.name in self.constants_w:
                 raise CompilerError(
                     "Cannot redefine class constant %s::%s" %
                     (self.name, decl.name))
             self.constants_w[decl.name] = decl.const_expr.wrap(
                 ctx, ctx.space)
         elif isinstance(decl, MethodDecl):
             self._method_decl(decl, ctx)
         else:
             assert isinstance(decl, PropertyDecl)
             self._property_decl(decl, ctx)
     self._check_abstract_local()
     self._init_constructor()
Ejemplo n.º 15
0
 def _emit_break_continue_pop(self, levels):
     # we must (sometimes) emit a BREAK_CONTINUE_POP instruction
     assert levels >= 1
     looplabels = None
     # compute the total stack items to remove
     remove_stack = 0
     for i in range(levels):
         num = len(self.llabels) - i - 1
         if num < 0:
             raise CompilerError("Cannot break/continue %d level%s" %
                                 (levels, "s" if levels > 1 else ""))
         looplabels = self.llabels[num]
         remove_stack += looplabels.extra_stack
     # we don't exit the last loop (even a 'break;' jumps just before
     # the final DISCARD_TOP, in case of 'foreach')
     if looplabels is not None:
         remove_stack -= looplabels.extra_stack
     if remove_stack > 0:
         self.emit(consts.BREAK_CONTINUE_POP, remove_stack)
     return looplabels
Ejemplo n.º 16
0
 def __init__(self, access_flags):
     self.access_flags = normalize_access(access_flags)
     if self.is_final() and self.is_abstract():
         raise CompilerError("Cannot use the final modifier on an "
                             "abstract class member")
Ejemplo n.º 17
0
    def prepare_function(self,
                         name,
                         argdecls,
                         closuredecls,
                         lineno,
                         returns_reference,
                         body,
                         is_method_of=None,
                         static=False):
        new_context = CompilerContext(self.filename,
                                      self.sourcelines,
                                      lineno,
                                      self.space,
                                      name,
                                      is_global=False)
        new_context.current_namespace = self.current_namespace
        new_context.use_aliases = self.use_aliases
        args = []
        typehints = []
        for i, arg in enumerate(argdecls):
            assert isinstance(arg, Argument)
            name = arg.name
            if arg.is_reference:
                opcode = consts.ARG_REFERENCE
            else:
                opcode = consts.ARG_ARGUMENT
            if arg.defaultvalue is None:
                w_default = None
            else:
                w_default = arg.defaultvalue.wrap(self, self.space)
            _hint = arg.typehint
            if _hint is not None:
                hint_str = _hint.as_unqualified()
                if hint_str and hint_str.lower() == 'self':
                    if is_method_of is None:
                        raise CompilerError("Cannot use 'self' typehint")
                    hint = is_method_of.name
                elif hint_str and hint_str.lower() == 'parent':
                    if is_method_of is None or is_method_of.extends_name is None:
                        raise CompilerError("Cannot use 'parent' typehint")
                    hint = is_method_of.extends_name
                else:
                    hint = _hint.get_qualified_name(self)
                typehints.append((i, hint, w_default is self.space.w_Null))
            args.append((opcode, name, w_default))
            if not new_context.force_var_name(name):
                self.warn("Argument list contains twice '$%s'" % (name, ))

        if is_method_of is not None:
            new_context.method_of_class = is_method_of
            new_context.current_class = is_method_of
            if not static:
                new_context.this_var_num = len(argdecls)
                if not new_context.force_var_name("this"):
                    raise CompilerError("Cannot re-assign $this")
        new_context.returns_reference = returns_reference
        #
        if body is not None:
            for decl in closuredecls:
                new_context.force_var_name(decl.name)
            #
            for i, typehint, allow_null in typehints:
                j = i * 2 + allow_null
                if typehint == 'array':
                    new_context.emit(consts.TYPEHINT_ARRAY, j)
                else:
                    new_context.emit(consts.LOAD_NAME,
                                     new_context.create_name(typehint))
                    new_context.emit(consts.TYPEHINT_CLASS, j)
            #
            body.compile(new_context)
            new_context.emit(consts.LOAD_NULL)
            new_context.emit(consts.RETURN)
        else:
            new_context.emit(consts.ABSTRACT_METHOD)
        bytecode = new_context.create_bytecode()
        return Function(args, closuredecls, typehints, bytecode)