Example #1
0
def load_package(include_stmt, extern=False):
    # package name
    name = ''
    # if it is anonymous
    used = False
    # alias if necessary
    alias = None
    for item in include_stmt.content:
        if isinstance(item, ASTNode):
            # update name to be end of suffix
            if item.name == 'dot_id':
                name = unparse(item)[-1].value
            # if this sub tree exists, that means the inclusion is used
            elif item.name == 'use':
                used = True
            # if there is a rename, that means an alias was used
            elif item.name == 'rename':
                alias = item.content[0].value[1:-1]
                if not re.match(r'[^\d\W]\w*', alias):
                    errormodule.throw('package_error', 'Invalid package name',
                                      include_stmt)
        else:
            # get base name
            if item.type == 'IDENTIFIER':
                name = item.value
    # package cannot be used and external
    if used and extern:
        errormodule.throw('package_error',
                          'Package cannot be both external and anonymous.',
                          include_stmt)
    # if get fails due to file path not being found
    try:
        code, path = get(name)
    except FileNotFoundError:
        errormodule.throw('package_error',
                          'Unable to locate package by name \'%s\'.' % name,
                          include_stmt)
        return
    # prevent redundant imports
    if name in imports:
        ast = imports[name]
    # if working directory needs to be updated
    elif path:
        # store cwd
        cwd = os.getcwd()
        # chdir to the parent directory of the file to allow for local importing
        os.chdir(path)
        # get the data necessary
        ast = get_ast(code)
        # change back to cwd
        os.chdir(cwd)
    else:
        # just get the ast, no cwd recursion necessary
        ast = get_ast(code)
    # set alias if there was none provided
    if not alias:
        alias = name
    if name not in imports:
        imports[name] = ast
    return util.Package(alias, extern, used, ast)
Example #2
0
def warn(message, params):
    if isinstance(params, ASTNode):
        raw_tokens = unparse(params)
    else:
        raw_tokens = [params]
    line, ndx = get_position(raw_tokens[0].ndx)
    print('[WARNING] %s %s' % (message, '[line:%d position:%d]' % (line, ndx)))
Example #3
0
def _print_semantic_error(message, params):
    if isinstance(params, ASTNode):
        raw_tokens = unparse(params)
    else:
        raw_tokens = [params]
    len_carrots = (raw_tokens[-1].ndx + len(raw_tokens[-1].value)) - raw_tokens[0].ndx if len(raw_tokens) > 1 else len(raw_tokens[0].value)
    line, ndx = get_position(raw_tokens[0].ndx)
    message += ' [line:%d position:%d]' % (line, ndx)
    message += '\n\n%s' % getln(line, ndx, len_carrots)
    raise SyCloneRecoverableError(message)
Example #4
0
def generate_delete(stmt):
    # hold Identifiers to be put in final StatementNode
    identifiers = []
    # hold the initial variable names given
    variables = [stmt.content[1]]
    # if there are multiple variables
    if isinstance(stmt.content[-1], ASTNode):
        # iterate through unparsed statement and add all identifiers
        for item in unparse(stmt.content[-1]):
            if item.type == 'IDENTIFIER':
                variables.append(item)
    # iterate through generated variable list
    for item in variables:
        # look up to get identifier
        sym = util.symbol_table.look_up(item.value)
        # attempt to delete, fail if impossible
        if not util.symbol_table.delete(item.value):
            errormodule.throw('semantic_error', 'Unable to delete non-existent symbol', item)
        # add identifiers to list
        identifiers.append(Identifier(sym.name, sym.data_type, Modifiers.CONSTANT in sym.modifiers))
    return StatementNode('Delete', *identifiers)
Example #5
0
def generate_assign_var(assign_var):
    # generate identifier
    def generate_id_type(id_type):
        # handle this token
        # uses Module.get_instance()
        if id_type.content[0].type == 'THIS':
            return get_instance()
        # otherwise look up symbol and return identifier
        else:
            sym = util.symbol_table.look_up(id_type.content[0].value)
            if not sym:
                errormodule.throw('semantic_error', 'Variable \'%s\' not defined' % id_type.content[0].value, id_type)
            return Identifier(sym.name, sym.data_type, Modifiers.CONSTANT in sym.modifiers)

    # if there is single ASTNode, assume the it is id_types
    if isinstance(assign_var.content[0], ASTNode):
        # return generate id type
        return generate_id_type(assign_var.content[0])
    # there is a dereference operator
    else:
        # check if there is an id type after the dereference operator
        if isinstance(assign_var.content[-1].content[0], ASTNode):
            root = generate_id_type(assign_var.content[-1].content[0])
        # otherwise generate sub var
        else:
            root = generate_assign_var(assign_var.content[-1].content[1])
            # check for trailer
            if len(assign_var.content[-1].content) > 3:
                root = add_trailer(root, assign_var.content[-1].content[2])
        # calculate the dereference count
        deref_count = 1 if len(assign_var.content) == 2 else len(unparse(assign_var.content[1])) + 1
        # check for non-pointer dereference
        if deref_count > root.data_type.pointers:
            errormodule.throw('semantic_error', 'Unable to dereference a non-pointers', assign_var)
        dt = copy(root.data_type)
        dt.pointers -= deref_count
        return ExprNode('Dereference', dt, deref_count, root)
Example #6
0
def compile_parameters(param_ast):
    params = []
    expr = ''

    if not isinstance(param_ast, ASTNode):
        return params

    for item in param_ast.content:
        if isinstance(item, ASTNode):
            if item.name == 'expr':
                expr = item
            elif item.name == 'named_param':
                ue = unparse(expr)
                if len(ue) > 1 or isinstance(
                        ue[0], ASTNode) or ue[0].type != 'IDENTIFIER':
                    errormodule.throw(
                        'semantic_error', 'Invalid parameter name', param_ast.
                        content[0 if isinstance(param_ast.content[0], ASTNode
                                                ) else 1])
                expr = (ue[0].value, generate_expr(item.content[1]))
            elif item.name == 'n_param':
                params += compile_parameters(item)
    return [generate_expr(expr) if isinstance(expr, ASTNode) else expr
            ] + params
Example #7
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
Example #8
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