예제 #1
0
파일: translate.py 프로젝트: fxxing/play
 def parse_integer(self, value: str, base):
     value = value.replace('_', '')
     if value.lower().endswith('l'):
         value = int(value[:-1], base)
         type = LONG_TYPE
         if value > 0x7FFFFFFFFFFFFFFF or value < -0x8000000000000000:
             raise CompileException('int out of range {}'.format(value))
     else:
         value = int(value, base)
         if value > 0x7FFFFFFF or value < -0x80000000:
             raise CompileException('int out of range {}'.format(value))
         type = INT_TYPE
     return Literal(value, type)
예제 #2
0
파일: translate.py 프로젝트: fxxing/play
 def class_creation(self, ctx: PlayParser.ClassCreationContext) -> Expr:
     cls = lookup_class(ctx.classType().IDENTIFIER().getText(),
                        self.current_class)
     if cls.is_interface:
         raise CompileException(
             "Cannot instantiate interface {}".format(cls))
     if cls.is_abstract:
         raise CompileException(
             "Cannot instantiate abstract class {}".format(cls))
     arguments = self.expression_list(ctx.expressionList())
     types = [arg.type for arg in arguments]
     return ClassCreation(cls, cls.lookup_method('<init>', types),
                          arguments)
예제 #3
0
파일: env.py 프로젝트: fxxing/play
 def enter(self, value: Variable):
     current = self.scopes[-1]
     old: Variable = current.get(value.name)
     if old and old.type != value.type:
         raise CompileException('Redefine variable {} with different type {}'.format(old.name, value.type))
     else:
         current[value.name] = value
예제 #4
0
 def lookup_field(self, name: str, silence=False):
     # type: (str) -> Field
     for field in self.inherited_fields:
         if field.name == name:
             return field
     if not silence:
         raise CompileException('Cannot find field {}'.format(name))
예제 #5
0
파일: translate.py 프로젝트: fxxing/play
 def while_statement(self,
                     ctx: PlayParser.WhileStatementContext) -> Statement:
     expr = self.expression(ctx.expression())
     if not expr.type == BOOLEAN_TYPE:
         raise CompileException(
             "while expression must be boolean expression")
     return WhileStatement(expr, self.block(ctx.block()))
예제 #6
0
 def enter_field(self, cls: Class, ctx: PlayParser.FieldDeclarationContext):
     if cls.is_interface or cls.is_native:
         raise CompileException(
             "Interface/native class {} cannot have fields".format(cls))
     field = Field(ctx.variable().IDENTIFIER().getText(), cls,
                   build_type(ctx.variable().typeName(), cls))
     Option().nodes[field] = ctx
     cls.put_field(field)
예제 #7
0
 def put_method(self, method):
     methods = self.static_methods if method.is_static else self.methods
     for m in methods:
         if m.has_same_signature(method):
             raise CompileException(
                 'Duplicated method {} in class {}'.format(
                     method.name, self))
     methods.append(method)
예제 #8
0
파일: translate.py 프로젝트: fxxing/play
 def translate_field(self, field: Field):
     ctx: PlayParser.FieldDeclarationContext = self.nodes[field]
     if ctx.expression():
         expr = self.expression(ctx.expression())
         if not can_cast_to(expr.type, field.type):
             raise CompileException(
                 "Cannot assign to field {} with type {}".format(
                     field.name, expr.type))
         field.initializer = expr
예제 #9
0
파일: translate.py 프로젝트: fxxing/play
 def cast_expression(self, ctx: PlayParser.CastExpressionContext) -> Expr:
     if ctx.unaryExpression():
         return self.unary_expression(ctx.unaryExpression())
     expr = self.not_super(self.cast_expression(ctx.castExpression()))
     type = build_type(ctx.typeName(), self.current_class)
     if not can_cast_to(expr.type, type, force=True):
         raise CompileException('Cannot cast type {} to {}'.format(
             expr.type, type))
     return CastExpr(expr, type)
예제 #10
0
파일: translate.py 프로젝트: fxxing/play
 def return_statement(self,
                      ctx: PlayParser.ReturnStatementContext) -> Statement:
     expr = self.expression(ctx.expression()) if ctx.expression() else None
     return_type = expr.type if expr else None
     if not can_cast_to(return_type, self.current_method.return_type):
         raise CompileException(
             'Cannot return type {} for method {}, expect {}'.format(
                 return_type, self.current_method.name,
                 self.current_method.return_type))
     return ReturnStatement(expr)
예제 #11
0
 def enter_class(self, package: Package, src: SourceFile,
                 ctx: PlayParser.ClassDeclarationContext):
     cls = Class(ctx.IDENTIFIER().getText(), package, src)
     cls.is_interface = ctx.INTERFACE() is not None
     cls.is_native = ctx.NATIVE() is not None
     if cls.is_native and cls.is_interface:
         raise CompileException('interface {} cannot be native'.format(cls))
     Option().nodes[cls] = ctx
     package.put(cls)
     SymbolTable().enter_class(cls)
예제 #12
0
파일: translate.py 프로젝트: fxxing/play
 def if_statement(self, ctx: PlayParser.IfStatementContext) -> Statement:
     # unwrap always condition
     condition = self.expression(ctx.expression())
     if not condition.type == BOOLEAN_TYPE:
         raise CompileException("if expression must be boolean expression")
     else_ifs: List[Tuple[Expr, Block]] = []
     for else_if_ctx in ctx.elifClause():
         cond = self.expression(else_if_ctx.expression())
         if not cond.type == BOOLEAN_TYPE:
             raise CompileException(
                 "if expression must be boolean expression")
         else_ifs.append((cond, self.block(else_if_ctx.block())))
     otherwise = None
     if ctx.elseClause():
         otherwise = self.block(ctx.elseClause().block())
     if else_ifs:
         return IfStatement(condition, self.block(ctx.block()),
                            Block([self.build_else(else_ifs, otherwise)]))
     else:
         return IfStatement(condition, self.block(ctx.block()), otherwise)
예제 #13
0
파일: env.py 프로젝트: fxxing/play
def lookup_class(name: str, start: Class) -> Class:
    if name == start.name:
        return start
    if name in start.source.imports:
        return start.source.imports[name]
    found = start.owner.children.get(name)
    if isinstance(found, Class):
        return found
    if isinstance(PLAY_PACKAGE.children.get(name), Class):
        return PLAY_PACKAGE.children[name]
    raise CompileException("Cannot find class {}".format(name))
예제 #14
0
파일: translate.py 프로젝트: fxxing/play
 def assign_statement(self,
                      ctx: PlayParser.AssignStatementContext) -> Statement:
     if ctx.IDENTIFIER():
         target = ctx.IDENTIFIER().getText()
         expr = self.not_super(self.expression(ctx.expression(0)))
         type = build_type(ctx.typeName(),
                           self.current_class) if ctx.typeName() else None
         if type:
             if not can_cast_to(expr.type, type):
                 raise CompileException(
                     'Cannot assign type {} to {}'.format(expr.type, type))
         else:
             type = expr.type  # infer type
         var = Variable(target, type)
         self.env.enter(var)
         return AssignStatement(var, expr)
     else:
         var = self.expression(ctx.expression(0))
         if not isinstance(var, FieldAccess):
             raise CompileException('left value must be variable or field')
         return AssignStatement(var, self.expression(ctx.expression(1)))
예제 #15
0
 def lookup_super_method(self, name: str, arguments):
     # type: (str, List[Type]) -> Method
     method = self.superclass.lookup_method(name, arguments)
     if not method:
         for interface in self.interfaces:
             method = interface.lookup_method(name, arguments)
             if method.is_abstract:
                 method = None
     if method:
         return method
     raise CompileException(
         'Cannot find method {} with parameters {}'.format(name, arguments))
예제 #16
0
 def build(self, cls: Class):
     ctx: PlayParser.ClassDeclarationContext = Option().nodes[cls]
     if ctx.classTypeList():
         for sc in ctx.classTypeList().classType():
             superclass = lookup_class(sc.IDENTIFIER().getText(), cls)
             if superclass.is_native:
                 raise CompileException(
                     'Cannot inherit from native class {}'.format(
                         superclass))
             if superclass.is_interface:
                 cls.interfaces.append(superclass)
             elif cls.superclass:
                 raise CompileException(
                     "Class {} has more than one superclass".format(cls))
             elif superclass.is_native and superclass.qualified_name != 'play.Object':
                 raise CompileException(
                     "Cannot inherit native class {}".format(cls))
             else:
                 cls.superclass = superclass
     obj_cls = PLAY_PACKAGE.children['Object']
     if cls != obj_cls and not cls.is_interface and not cls.superclass:
         cls.superclass = obj_cls
예제 #17
0
 def check_inside_loop(self,
                       statement: Statement,
                       loops: List[LoopStatement] = None):
     if not statement:
         return
     if not loops:
         loops = []
     if isinstance(statement, BreakStatement):
         if not loops:
             raise CompileException('break must inside loop')
     elif isinstance(statement, ContinueStatement):
         if not loops:
             raise CompileException('continue must inside loop')
     elif isinstance(statement, IfStatement):
         self.check_inside_loop(statement.then, loops)
         if statement.otherwise:
             self.check_inside_loop(statement.otherwise, loops)
     elif isinstance(statement, LoopStatement):
         self.check_inside_loop(statement.block, [] + [statement])
     elif isinstance(statement, Block):
         for s in statement.statements:
             self.check_inside_loop(s, loops)
예제 #18
0
파일: env.py 프로젝트: fxxing/play
    def lookup(self, name, static) -> Expr:
        for scope in reversed(self.scopes):
            if name in scope:
                return scope[name]
        if not static:
            field = self.cls.lookup_field(name, silence=True)
            if field:
                return FieldAccess(None, field)

        try:
            return ClassExpr(lookup_class(name, self.cls))
        except CompileException:
            pass
        raise CompileException('Cannot find symbol {}'.format(name))
예제 #19
0
파일: symbol.py 프로젝트: fxxing/play
 def enter_package(self, package: str) -> Package:
     symbol = self.__symbols.get(package)
     if isinstance(symbol, Package):
         return symbol
     elif not symbol:
         owner = self.enter_package(package[:package.rfind('.')] if '.' in
                                    package else '')
         symbol = Package(package, owner)
         owner.put(symbol)
         self.__symbols[package] = symbol
         return symbol
     else:
         raise CompileException(
             "Expect package symbol, but it is {}".format(symbol))
예제 #20
0
    def lookup_method(self, name: str, arguments, is_static=False):
        # type: (str, List[Type], bool) -> Method
        methods = self.static_methods if is_static else self.inherited_methods
        for method in methods:
            if method.name != name:
                continue
            if len(method.parameters) != len(arguments):
                continue
            for i, parameter in enumerate(method.parameters):
                if arguments[i] != parameter.type:
                    break
            else:
                return method

        raise CompileException(
            'Cannot find method {} with parameters {}'.format(name, arguments))
예제 #21
0
def build_type(ctx: PlayParser.TypeNameContext, start: Class) -> Type:
    if ctx.classType():
        return ObjectType(
            lookup_class(ctx.classType().IDENTIFIER().getText(), start))
    if ctx.BOOLEAN():
        return BOOLEAN_TYPE
    if ctx.BYTE():
        return BYTE_TYPE
    if ctx.SHORT():
        return SHORT_TYPE
    if ctx.INT():
        return INT_TYPE
    if ctx.LONG():
        return LONG_TYPE
    if ctx.FLOAT():
        return FLOAT_TYPE
    if ctx.DOUBLE():
        return DOUBLE_TYPE
    raise CompileException("Error")
예제 #22
0
파일: translate.py 프로젝트: fxxing/play
 def primary_expression(self,
                        ctx: PlayParser.PrimaryExpressionContext) -> Expr:
     if self.current_method.is_static and (ctx.THIS() or ctx.SUPER()):
         raise CompileException('Cannot use this/super in static method')
     if ctx.methodCall():
         return self.method_call(ctx.methodCall())
     if ctx.classCreation():
         return self.class_creation(ctx.classCreation())
     if ctx.expression():
         return self.expression(ctx.expression())
     if ctx.THIS():
         return self.this_var
     if ctx.SUPER():
         return self.super_var
     if ctx.IDENTIFIER():
         return self.env.lookup(ctx.IDENTIFIER().getText(),
                                self.current_method.is_static)
     if ctx.literal():
         return self.literal(ctx.literal())
     never_be_here()
예제 #23
0
 def enter_method(self, cls: Class,
                  ctx: PlayParser.MethodDeclarationContext):
     name = ctx.IDENTIFIER().getText()
     if name == cls.name:
         name = '<init>'
     method = Method(name, cls)
     method.is_native = ctx.NATIVE() is not None
     method.is_static = ctx.STATIC() is not None
     method.is_abstract = not method.is_native and ctx.block() is None
     if method.is_native and ctx.block() is not None:
         raise CompileException(
             'Native method {} in class {} cannot have body'.format(
                 method.name, method.owner))
     if ctx.parameters():
         for v in ctx.parameters().variable():
             parameter_type = build_type(v.typeName(), cls)
             method.parameters.append(
                 Parameter(v.IDENTIFIER().getText(), parameter_type))
     if ctx.typeName():
         method.return_type = build_type(ctx.typeName(), cls)
     Option().nodes[method] = ctx
     cls.put_method(method)
예제 #24
0
    def check(self, current: Class, path: List[Class]):
        if current in self.visited:
            return
        self.visited.add(current)
        superclasses = current.superclasses
        for sc in superclasses:
            try:
                index = path.index(sc)
                chain = []
                for c in path[index:]:
                    chain.append(c.qualified_name)
                chain.append(current.qualified_name)
                chain.append(path[index].qualified_name)
                raise CompileException(
                    "There's a circular hierarchy dependency: {}".format(
                        ' -> '.join(chain)))
            except:
                pass

        new_path = path + [current]
        for sc in superclasses:
            self.check(sc, new_path)
        self.checked.add(current)
예제 #25
0
파일: translate.py 프로젝트: fxxing/play
    def method_call(self,
                    ctx: PlayParser.MethodCallContext,
                    select: Expr = None) -> Expr:
        if self.current_method.is_static and ctx.THIS() or ctx.SUPER():
            raise CompileException('Cannot use this/super in static method')

        if select and (ctx.THIS() or ctx.SUPER()):
            raise CompileException('this() and super() cannot has prefix')
        arguments = self.expression_list(ctx.expressionList())
        types = [arg.type for arg in arguments]
        if ctx.THIS():
            method = self.current_class.lookup_method('<init>', types)
        elif ctx.SUPER():
            if self.current_method.name != '<init>':
                raise CompileException(
                    'Cannot call super outside constructor {}'.format(
                        self.current_class))
            method = self.current_class.superclass.lookup_method(
                '<init>', types)
            if method.is_private:
                raise CompileException('access private method in {}'.format(
                    self.current_class.superclass))
        else:
            method_name = ctx.IDENTIFIER().getText()
            if select:
                if not isinstance(select.type, ObjectType):
                    raise CompileException("cannot lookup method in {}".format(
                        select.type))
                if select == self.super_var:
                    method = self.current_class.lookup_super_method(
                        method_name, types)
                else:
                    method = select.type.cls.lookup_method(
                        method_name, types, isinstance(select.type, ClassType))
                if method.is_private and select.type.cls != self.current_class:
                    raise CompileException(
                        'access private method in {}'.format(select.type))
            else:
                method = self.current_class.lookup_method(
                    method_name,
                    types,
                    is_static=self.current_method.is_static)
        return MethodCall(select, method, arguments)
예제 #26
0
 def put_field(self, field):
     for f in self.fields:
         if f.name == field.name:
             raise CompileException(
                 'Duplicated field {} in class {}'.format(field.name, self))
     self.fields.append(field)
예제 #27
0
파일: translate.py 프로젝트: fxxing/play
 def not_super(self, expr: Expr) -> Expr:
     if expr == self.super_var:
         raise CompileException('Cannot user super')
     return expr
예제 #28
0
파일: translate.py 프로젝트: fxxing/play
 def parse_bool(self, value: str):
     if value == 'true':
         return Literal(True, BOOLEAN_TYPE)
     if value == 'false':
         return Literal(False, BOOLEAN_TYPE)
     raise CompileException('Invalid boolean type')
예제 #29
0
파일: translate.py 프로젝트: fxxing/play
def assert_type(actual, expect):
    if not isinstance(expect, (set, list)):
        expect = [expect]
    if actual not in expect:
        raise CompileException('Invalid type {}, expect {}'.format(
            actual, expect))
예제 #30
0
 def put(self, child):
     if child.name in self.children and self.children[child.name] != child:
         raise CompileException('Duplicated symbol {} in package {}'.format(
             child.name, self.qualified_name))
     self.children[child.name] = child