예제 #1
0
def generate_logical(logical):
    # if it is a comparison, pass it on to the next generator
    if logical.name == 'comparison':
        return generate_comparison(logical)
    # unpack tree if it exists
    if len(logical.content) > 1:
        # hold the unpacked tree
        unpacked_tree = logical.content[:]
        # semi-recursive for loop to unpack tree
        for item in unpacked_tree:
            # if it is an ASTNode
            if isinstance(item, ASTNode):
                # and falls into the 'n' categories
                if item.name.startswith('n'):
                    # unpack it
                    unpacked_tree += unpacked_tree.pop().content
        # root holds the next level downward, op = operator being used
        root, op = generate_logical(unpacked_tree.pop(0)), None
        # iterate through unpacked tree
        for item in unpacked_tree:
            # main tree
            if isinstance(item, ASTNode):
                # get next comparison tree if it is a comparison otherwise get next logical tree
                tree = generate_comparison(
                    item) if item.name == 'comparison' else generate_logical(
                        item)
                # if both are simple data types
                if isinstance(tree.data_type, types.DataType) and isinstance(
                        root.data_type, types.DataType):
                    # check booleans and generate boolean operators
                    if tree.data_type.data_type == types.DataTypes.BOOL and tree.data_type.pointers == 0 and \
                                    root.data_type.data_type == types.DataTypes.BOOL and root.data_type.pointers == 0:
                        root = ExprNode(
                            op, types.DataType(types.DataTypes.BOOL, 0), root,
                            tree)
                        continue
                    # generate bitwise operators
                    else:
                        # extract dominant type and if there is not one, throw error
                        dom = types.dominant(root.data_type, tree.data_type)
                        if dom:
                            if not types.coerce(
                                    types.DataType(types.DataTypes.INT, 0),
                                    dom):
                                errormodule.throw(
                                    'semantic_error',
                                    'Unable to apply bitwise %s to object' %
                                    op.lower(), logical)
                            root = ExprNode('Bitwise' + op, dom, root, tree)
                        else:
                            if not types.coerce(
                                    types.DataType(types.DataTypes.INT, 0),
                                    tree.data_type):
                                errormodule.throw(
                                    'semantic_error',
                                    'Unable to apply bitwise %s to object' %
                                    op.lower(), logical)
                            root = ExprNode('Bitwise' + op, tree.data_type,
                                            root, tree)
                # handle operator overloading
                elif isinstance(root.data_type, types.CustomType):
                    # get and check method
                    method = modules.get_property(tree.data_type,
                                                  '__%s__' % op.lower())
                    functions.check_parameters(method, [tree], item)
                    if method:
                        root = ExprNode('Call', method.data_type.return_type,
                                        method, tree)
                    else:
                        errormodule.throw(
                            'semantic_error',
                            'Object has no method \'__%s__\'' % op.lower(),
                            logical)
                else:
                    errormodule.throw(
                        'semantic_error',
                        'Unable to apply bitwise operator to object', logical)
            # only token is operator
            else:
                name = item.type.lower()
                op = name[0].upper() + name[1:]
        return root
    # otherwise recur to next level down
    else:
        return generate_logical(logical.content[0])
예제 #2
0
def generate_unary_atom(u_atom):
    # generate hold atom
    atom = generate_atom(u_atom.content[-1])
    if len(u_atom.content) > 1:
        # check for packages
        if isinstance(atom, Package):
            errormodule.throw('semantic_error',
                              'Unable to apply operator to package', u_atom)
            return
        # check for tuples
        if isinstance(atom.data_type, types.Tuple):
            errormodule.throw('semantic_error',
                              'Unable to apply operator to multiple values',
                              u_atom)
            return
        # check data type literal
        if isinstance(atom.data_type, types.DataTypeLiteral):
            errormodule.throw('semantic_error',
                              'Unable to apply operator to Data Type literal',
                              u_atom)
            return
        # check for template
        if isinstance(atom.data_type, types.Template):
            errormodule.throw('semantic_error',
                              'Unable to apply operator to template', u_atom)
            return
        prefix = u_atom.content[0].content[0]
        # handle sine change
        if prefix.type == '-':
            # test for numericality
            if types.numeric(atom.data_type):
                # handle modules
                if isinstance(atom.data_type, types.CustomType):
                    invert_method = modules.get_property(
                        atom.data_type, '__invert__')
                    return ExprNode('Call',
                                    invert_method.data_type.return_type,
                                    invert_method)
                # change the sine of an element
                else:
                    return ExprNode('ChangeSine', atom.data_type, atom)
            else:
                # throw error
                errormodule.throw(
                    'semantic_error',
                    'Unable to change sine on non-numeric type.', u_atom)
        elif prefix.type == 'AMP':
            dt = copy(atom.data_type)
            # create pointer
            dt.pointers += 1
            # reference pointer
            return ExprNode('Reference', dt, atom)
        # handle deref op
        elif prefix.type == '*':
            do = len(unparse(u_atom.content[0].content[1])) + 1 if len(
                u_atom.content[0].content) > 1 else 1
            # handle pointer error
            # < because that means there is more dereferencing than there are references to dereference
            if atom.data_type.pointers < do:
                errormodule.throw('semantic_error',
                                  'Unable to dereference a non-pointer',
                                  u_atom.content[0])
            elif isinstance(atom.data_type, types.VoidPointer):
                if atom.data_type.pointers <= do:
                    errormodule.throw('semantic_error',
                                      'Unable to dereference void pointer',
                                      u_atom.content[0])
                vp = copy(atom.data_type)
                vp.pointers -= 1
                return ExprNode('Dereference', vp, do, atom)
            else:
                dt = copy(atom.data_type)
                dt.pointers -= do
                # return dereference with count
                return ExprNode('Dereference', dt, do, atom)

    else:
        return atom
예제 #3
0
def generate_arithmetic(ari):
    # names of overload methods
    method_names = {
        '+': '__add__',
        '-': '__sub__',
        '*': '__mul__',
        '/': '__div__',
        '%': '__mod__',
        '^': '__pow__'
    }
    # unpack tree in operator sets
    unpacked_tree = ari.content[:]
    while unpacked_tree[-1].name in {'add_sub_op', 'mul_div_mod_op', 'exp_op'}:
        unpacked_tree += unpacked_tree.pop().content
    # root = base tree, op = operator, tree = resulting tree
    root, op, tree = None, None, None
    for item in unpacked_tree:
        # ast => expression
        if isinstance(item, ASTNode):
            # if there is an operator, generate arithmetic tree
            if op:
                # generate next value
                val = generate_unary_atom(
                    item
                ) if item.name == 'unary_atom' else generate_arithmetic(item)
                # check operands and extract data type
                dt = check_operands(root.data_type, val.data_type, op, ari)
                if tree:
                    # operator overloading
                    if isinstance(tree.data_type, types.CustomType):
                        # convert to method name
                        name = method_names[op]
                        # get method and check parameters
                        method = modules.get_property(tree.data_type, name)
                        # assume method exists
                        functions.check_parameters(method.data_type, [val],
                                                   item)
                        tree = ExprNode('Call', method.data_type.return_type,
                                        method, [tree])
                    # add arguments to previous tree (allow for multiple items)
                    elif tree.name == op:
                        tree.arguments.append(val)
                    # create expression node from tree
                    else:
                        tree = ExprNode(op, dt, tree, val)
                # create root tree
                else:
                    # operator overloading
                    if isinstance(root.data_type, types.CustomType):
                        # convert to method name
                        name = method_names[op]
                        # get method and check parameters
                        method = modules.get_property(root.data_type, name)
                        # assume method exists
                        functions.check_parameters(method.data_type, [val],
                                                   item)
                        tree = ExprNode('Call', method.data_type.return_type,
                                        method, [root])
                    # default generation
                    else:
                        tree = ExprNode(op, dt, root, val)
                op, root, = None, tree
            # otherwise, generate root
            else:
                root = generate_unary_atom(
                    item
                ) if item.name == 'unary_atom' else generate_arithmetic(item)
        # token => operator
        else:
            op = item.value
    # ensure tree is initialized
    if not tree:
        tree = root
    return tree
예제 #4
0
def generate_shift(shift):
    # if there is a shift performed
    if len(shift.content) > 1:
        # extract operator-expr list
        unpacked_tree = shift.content[:]
        while unpacked_tree[-1].name == 'n_shift':
            unpacked_tree += unpacked_tree.pop().content
        # get first expression
        root = generate_arithmetic(unpacked_tree.pop(0))
        # check for overload flag
        overload = False
        # check root data type
        if not isinstance(root.data_type, types.DataType):
            if isinstance(root.data_type, types.CustomType):
                overload = True
            else:
                errormodule.throw(
                    'semantic_error',
                    'Invalid type for left operand of binary shift',
                    shift.content[0])
        # operator used
        op = ''
        for item in unpacked_tree:
            # ast node => arithmetic expr
            if isinstance(item, ASTNode):
                # generate next tree element
                tree = generate_arithmetic(item)
                # check for overloads
                if overload:
                    method = modules.get_property(root.data_type,
                                                  '__%s__' % op.lower())
                    if not method:
                        errormodule.throw(
                            'semantic_error',
                            'Invalid type for left operand of binary shift',
                            shift.content[0])
                    functions.check_parameters(method.data_type, [tree], item)
                    overload = isinstance(method.data_type.return_type,
                                          types.CustomType)
                    root = ExprNode('Call', method.data_type.return_type,
                                    method, [tree])

                # type check element
                if isinstance(tree.data_type, types.DataType):
                    # ensure it is an integer (binary shifts can only be continued by integers)
                    if tree.data_type.data_type == types.DataTypes.INT and tree.data_type.pointers == 0:
                        root = ExprNode(op, root.data_type, root, tree)
                        continue
                errormodule.throw(
                    'semantic_error',
                    'Invalid type for right operand of binary shift', item)
            # token => operator
            else:
                if item.type == '<<':
                    op = 'Lshift'
                elif item.type == '>>':
                    op = 'ARshift'
                else:
                    op = 'LRshift'
        return root
    # otherwise, pass on to arithmetic parser
    else:
        return generate_arithmetic(shift.content[0])
예제 #5
0
def generate_comparison(comparison):
    # generate shift if it is a shift tree (because the comparison generator is recursive)
    if comparison.name == 'shift':
        return generate_shift(comparison)
    # evaluate comparison if there is one
    if len(comparison.content) > 1:
        # generate inversion operator
        if comparison.name == 'not':
            # generate base tree to invert
            tree = generate_shift(comparison.content[1])
            # check for data types
            if isinstance(tree.data_type, types.DataType):
                # unable to ! pointers
                if tree.data_type.pointers > 0:
                    errormodule.throw(
                        'semantic_error',
                        'The \'!\' operator is not applicable to pointer',
                        comparison)
                # generate normal not operator
                return ExprNode('Not', tree.data_type, tree)
            # generate overloaded not operator
            elif isinstance(tree.data_type, types.CustomType):
                # get and check overloaded not method
                not_method = modules.get_property(tree.data_type, '__not__')
                functions.check_parameters(not_method, tree, comparison)
                if not_method:
                    return ExprNode('Call', not_method.data_type.return_type,
                                    not_method, tree)
                else:
                    errormodule.throw('semantic_error',
                                      'Object has no method \'__not__\'',
                                      comparison)
            else:
                errormodule.throw(
                    'semantic_error',
                    'The \'!\' operator is not applicable to object',
                    comparison)
        # otherwise generate normal comparison operator
        else:
            # comparison op method dictionary
            comparison_methods = {
                '<=': '__lteq__',
                '>=': '__gteq__',
                "<": '__lt__',
                '>': '__gt__',
                '==': '__eq__',
                '!=': '__neq__',
                '===': '__seq__',
                '!==': '__sneq__'
            }
            # unpack tree into expressions and operators
            unpacked_tree = comparison.content[:]
            for item in unpacked_tree:
                if item.name == 'n_comparison':
                    unpacked_tree += unpacked_tree.pop().content
            # root = first element in unpacked tree, op = operator
            root, op = generate_comparison(unpacked_tree.pop(0)), None
            for item in unpacked_tree:
                # all elements are ASTs
                # not is base expression
                if item.name == 'not':
                    # extract next operator tree
                    n_tree = generate_comparison(item)
                    # check for overloads
                    if isinstance(root.data_type, types.CustomType):
                        method = modules.get_property(root.data_type,
                                                      comparison_methods[op])
                        if not method:
                            if op in {'<=', '>=', '<', '>'}:
                                errormodule.throw(
                                    'semantic_error',
                                    'Unable to use numeric comparison with non-numeric type',
                                    comparison)
                        else:
                            functions.check_parameters(method.data_type,
                                                       [n_tree], comparison)
                            root = ExprNode('Call',
                                            method.data_type.return_type,
                                            method, [n_tree])
                    # check numeric comparison
                    if op in {'<=', '>=', '<', '>'}:
                        # check invalid overloads
                        if isinstance(n_tree.data_type, types.CustomType):
                            errormodule.throw(
                                'semantic_error',
                                'Invalid type match up for numeric comparison',
                                comparison)
                        if types.numeric(n_tree.data_type) and types.numeric(
                                root.data_type):
                            root = ExprNode(
                                op, types.DataType(types.DataTypes.BOOL, 0),
                                root, n_tree)
                        else:
                            errormodule.throw(
                                'semantic_error',
                                'Unable to use numeric comparison with non-numeric type',
                                comparison)
                    # generate standard comparison
                    elif op in {'==', '!=', '===', '!=='}:
                        root = ExprNode(
                            op, types.DataType(types.DataTypes.BOOL, 0), root,
                            n_tree)
                # if it is not a base expression, it is an operators
                elif item.name == 'comparison_op':
                    op = item.content[0].value
            return root
    # otherwise recur
    else:
        return generate_comparison(comparison.content[0])
예제 #6
0
def generate_type(ext):
    pointers = 0
    # handle std types (from extension)
    if ext.name == 'types':
        if ext.content[0].name == 'deref_op':
            # extract data type pointers
            pointers = len(unparse(ext.content[0]))
        # update ext to simple types
        ext = ext.content[-1]  # selects last element (always simple types)
    # if it is token, assume array, list or dict
    if isinstance(ext.content[0], Token):
        # assume array
        if ext.content[0].type == 'ARRAY_TYPE':
            # ext.content[1].content[1] == pure_types -> array_modifier -> types
            et = generate_type(ext.content[1].content[1])
            # extract count value
            # ext.content[1].content[1] == pure_types -> array_modifiers -> expr
            error_ast = ext.content[1].content[3]
            try:
                count = get_array_bound(
                    generate_expr(ext.content[1].content[3]))
            except IndexError:
                errormodule.throw('semantic_error', 'Index out of range',
                                  error_ast)
                return
            if not count and count != 0:
                errormodule.throw('semantic_error',
                                  'Non-constexpr array bound', error_ast)
            elif type(count) == bool:
                errormodule.throw('semantic_error',
                                  'Invalid value for array bound', error_ast)
            try:
                _ = count < 0
                count = float(count)
            except (ValueError, TypeError):
                errormodule.throw('semantic_error',
                                  'Invalid value for array bound', error_ast)
            if not count.is_integer():
                errormodule.throw('semantic_error',
                                  'Invalid value for array bound', error_ast)
            elif count < 1:
                errormodule.throw('semantic_error',
                                  'Invalid value for array bound', error_ast)
            return types.ArrayType(et, int(count), pointers)
        # assume list
        elif ext.content[0].type == 'LIST_TYPE':
            # ext.content[1].content[1] == pure_types -> list_modifier -> types
            return types.ListType(generate_type(ext.content[1].content[1]),
                                  pointers)
        # assume function
        elif ext.content[0].type in {'FUNC', 'ASYNC'}:
            params, return_types = None, None
            for item in ext.content[1].content:
                if not isinstance(item, Token):
                    if item.name == 'func_params_decl':
                        params = generate_parameter_list(item)
                    elif item.name == 'rt_type':
                        return_types = get_return_from_type(item)
            return types.Function(params, return_types, 0,
                                  ext.content[0].value == 'ASYNC', False)
        # assume dict
        else:
            # ext.content[1].content[1] == pure_types -> dict_modifier -> types
            kt, vt = generate_type(ext.content[1].content[1]), generate_type(
                ext.content[1].content[3])
            # check mutability
            if types.mutable(kt):
                errormodule.throw('semantic_error',
                                  'Invalid key type for dictionary',
                                  ext.content[1].content[1])
            # compile dictionary type
            return types.MapType(kt, vt, pointers)
    else:
        if ext.content[0].name == 'pure_types':
            # data type literal
            if ext.content[0].content[0].type == 'DATA_TYPE':
                return types.DataTypeLiteral(types.DataTypes.DATA_TYPE)
            # return matched pure types
            return types.DataType({
                'INT_TYPE': types.DataTypes.INT,
                'BOOL_TYPE': types.DataTypes.BOOL,
                'BYTE_TYPE': types.DataTypes.BYTE,
                'FLOAT_TYPE': types.DataTypes.FLOAT,
                'LONG_TYPE': types.DataTypes.LONG,
                'COMPLEX_TYPE': types.DataTypes.COMPLEX,
                'STRING_TYPE': types.DataTypes.STRING,
                'CHAR_TYPE': types.DataTypes.CHAR,
                'OBJECT_TYPE': types.OBJECT_TEMPLATE,
            }[ext.content[0].content[0].type], 0)
        else:
            # get root symbol
            name = ext.content[0].content[0].value
            if name.type == 'THIS':
                sym = modules.get_instance()
            else:
                sym = util.symbol_table.look_up(name)
            # hold previous symbol ASTNode for error messages
            prev_sym = ext.content[0].content[0]
            # extract outer symbols if necessary
            if len(ext.content[0].content) > 1:
                content = ext.content[0].content[1:]
                for item in content:
                    if isinstance(item, Token):
                        if item.type == 'IDENTIFIER':
                            # make sure symbol is a custom type
                            if not isinstance(sym, types.CustomType):
                                errormodule.throw(
                                    'semantic_error',
                                    'Object is not a valid is a data type',
                                    prev_sym)
                            identifier = item.value
                            # get member for modules
                            if sym.data_type.data_type == types.DataTypes.MODULE:
                                # get and check property
                                prop = modules.get_property(
                                    sym.data_type, identifier)
                                if not prop:
                                    errormodule.throw(
                                        'semantic_error',
                                        'Object has no member \'%s\'' %
                                        identifier, item)
                                # update previous symbol
                                prev_sym = item
                                # update symbol
                                sym = prop
                            # invalid get member on interfaces
                            elif sym.data_type.data_type == types.DataTypes.INTERFACE:
                                errormodule.throw(
                                    'semantic_error',
                                    '\'.\' is not valid for this object', item)
                            # assume struct or enum
                            else:
                                for member in sym.data_type.members:
                                    # if there is a match, extract value
                                    if member.name == identifier:
                                        prev_sym = item
                                        sym = member
                                        # break to prevent else condition
                                        break
                                # if there is no match, throw error
                                else:
                                    errormodule.throw(
                                        'semantic_error',
                                        'Object has no member \'%s\'' %
                                        identifier, item)
                    # continue recursive for loop
                    elif item.name == 'dot_id':
                        content.extend(item.content)
            # final check for invalid data types
            if not isinstance(sym, types.CustomType):
                errormodule.throw('semantic_error',
                                  'Object is not a valid is a data type',
                                  prev_sym)
            # add instance marker if necessary
            if sym.data_type.data_type != types.DataTypes.INTERFACE:
                sym.data_type.instance = True
            return sym.data_type