Exemplo n.º 1
0
def parseTopLevel(mod, source, forJIT=False):
    # Classify the block
    try:
        blockHead = lexer.lex(source.peek(), False)
    except Exception:
        # Clear the bad line from the buffer
        source.getLine()
        raise
    if blockHead[0].name == 'def':
        # Determine function name and return type
        blockHead = lexer.lex(source.getLine(), mod.debugLexer)
        dtype = dtypes.getType(blockHead[1].data)
        funcName = blockHead[2].data[0]
        args = [[dtypes.getType(i.data), j.data]
                for i, j in ast.splitArguments(blockHead[2].data[1])]
        if funcName in mod.userFunctions.keys():
            raise ValueError(
                "ERROR: Function {} is already defined.".format(funcName))
        # Handle function arguments
        mod.body += [
            "define {} @{}({})".format(
                dtype.irname, funcName, ",".join(
                    [i.irname + " %arg_" + j for i, j in args])) + "{"
        ]
        mod.body += ["entry:"]
        for argType, argName in args:
            mem = mod.newVariable(argName, argType)
            mod.body += [
                "store {} {}, {}* {}".format(argType.irname, "%arg_" + argName,
                                             mem.irname, mem.addr)
            ]
        # Read in the function body
        output = None
        if source.end(1):
            raise ValueError(
                "ERROR: Expected a block (maybe you forgot to indent?)")
        while not source.end(1):
            result = parseBlock(mod, source, 1)
            if result is not None:
                output = result
        # Check that the return type is correct and end the function definition
        if output is None or (dtype.name != output.name):
            raise ValueError(
                "ERROR: Return type {} does not match declaration {}.".format(
                    output.name, dtype.name))
        mod.userFunctions[funcName] = (dtype, args)
        mod.alreadyDeclared.append(funcName)
        mod.endScope()
        mod.body += ["ret {} {}".format(output.irname, output.addr)]
        mod.body += ["}"]
    else:
        # Top-level statement
        mod.isGlobal = forJIT
        mod.out = mod.main
        mod.lastOutput = parseBlock(mod, source, 0, forJIT)
        mod.out = mod.body
        mod.isGlobal = False
    return
Exemplo n.º 2
0
 def resolveTyping(self, name=None, catalog=builtins.catalog):
     if name is None:
         name = self.token.name
     # Handle untyped options
     if name in catalog.keys() and type(catalog[name]) is not dict:
         self.evaluator = catalog[name]
         return
     argTypes = [i.dtype for i in self.children]
     best, bestArgs, cost = None, [], 9999999
     for candidate in catalog[name]:
         candidateCost = 0
         candidateArgs = candidate.split(' ')
         if len(candidateArgs) != len(argTypes):
             continue
         try:
             for a, ca in zip(argTypes, candidateArgs):
                 candidateCost += a.casting.index(ca)
         except ValueError:
             continue
         if candidateCost < cost:
             best, bestArgs, cost = candidate, candidateArgs, candidateCost
         elif candidateCost == cost:
             raise ValueError(
                 "ERROR: Tie for overload resolution of token '{}' with types {}"
                 .format(self.token.name, argTypes))
     if best is None:
         raise ValueError(
             "No valid candidates for token '{}' with types {}".format(
                 name, [i.name for i in argTypes]))
     # We've found the best candidate, record findings to self
     self.evaluator, self.dtype = catalog[name][best]
     self.children = [
         i.castTo(dtypes.getType(j))
         for i, j in zip(self.children, bestArgs)
     ]
     return
Exemplo n.º 3
0
 def __init__(self, tokens, module):
     # Keep reference to parent module
     self.module = module
     self.children = []
     self.dtype = None
     if tokens is None:
         return
     # Find the token of lowest precedence
     index, self.token = min(enumerate(tokens[::-1]),
                             key=lambda t: t[1].precedence)
     index = len(tokens) - index - 1
     leftTokens, rightTokens = tokens[:index], tokens[index + 1:]
     if module.debugAST:
         sys.stderr.write("AST: " + self.token.name + ', ' +
                          str(self.token.data) + "\n")
     # Now, construct the node according to the operator found
     if self.token.name == "print":
         assertEmpty(leftTokens)
         self.children = [ASTNode(rightTokens, self.module)]
     elif self.token.name in [
             '=', '+=', '-=', '/=', '//=', '**=', '*=', '%='
     ]:
         # Assignment operator and variants
         if self.token.name != '=':
             # Handle extra operation
             if type(self.token.data) is list:
                 left = self.token.data
             else:
                 left = [lexer.NameToken('name', self.token.data)]
             # TODO: replace this ugly hack with a proper builtin function
             TokenType = {
                 '+=': lexer.BinaryPlusToken,
                 '-=': lexer.BinaryMinusToken,
                 '/=': lexer.MultiplyFamilyToken,
                 '//=': lexer.MultiplyFamilyToken,
                 '**=': lexer.ExponentToken,
                 '*=': lexer.MultiplyFamilyToken,
                 '%=': lexer.MultiplyFamilyToken
             }[self.token.name]
             rightTokens = left + [
                 TokenType(self.token.name[:-1]),
                 lexer.ParensToken('()', rightTokens)
             ]
             self.token.name = '='
         if type(self.token.data) is list:
             # Array indexing assignment
             self.children = [
                 ASTNode(self.token.data[:-1], self.module),
                 ASTNode(self.token.data[-1].data,
                         self.module).castTo(dtypes.Int),
                 ASTNode(rightTokens, self.module)
             ]
             self.children[-1] = self.children[-1].castTo(
                 self.children[0].dtype.subtype)
             self.token.name = "index="
         else:
             # Regular old variable assignment
             self.children = [ASTNode(rightTokens, self.module)]
     elif self.token.name in [
             'and', 'or', 'xor', '-', '+', '%', '*', '//', '/', '**', '<=',
             '>=', '<', '>', '!=', '=='
     ]:
         # Binary operators!
         self.children = [
             ASTNode(t, self.module) for t in [leftTokens, rightTokens]
         ]
     elif self.token.name in ["unary +", "unary -"]:
         assertEmpty(leftTokens)
         self.children = [ASTNode(rightTokens, self.module)]
         self.dtype = self.children[0].dtype
     elif self.token.name == "literal":
         assertEmpty(leftTokens, rightTokens)
         self.dtype = self.token.data[0]
     elif self.token.name == "function":
         assertEmpty(leftTokens, rightTokens)
         caller, data = self.token.data
         if caller in builtins.catalog.keys():
             # Known builtin disguised as a function
             self.children = [
                 ASTNode(t, self.module) for t in splitArguments(data)
             ]
             self.dtype = self.children[0].dtype
             self.resolveTyping(caller, builtins.catalog)
             return
         elif caller in self.module.userFunctions.keys():
             # Known, user-defined function
             self.dtype, args = self.module.userFunctions[caller]
             self.children = [
                 ASTNode(t, self.module).castTo(a[0])
                 for t, a in zip(splitArguments(data), args)
             ]
         elif caller in dtypes.baseTypes:
             # Explicit type cast
             self.token.name = "()"
             self.children = [
                 ASTNode(data, self.module).castTo(dtypes.getType(caller),
                                                   True)
             ]
             self.dtype = self.children[0].dtype
         else:
             # Unknown function, assume it's declared somewhere else
             self.children = [ASTNode(self.token.data[1], self.module)]
             self.dtype = self.children[0].dtype
         self.token.data = [caller, self.dtype]
     elif self.token.name == '()':
         assertEmpty(leftTokens, rightTokens)
         self.token.name = "()"
         self.children = [ASTNode(self.token.data, self.module)]
         self.dtype = self.children[0].dtype
     elif self.token.name == "name":
         assertEmpty(leftTokens, rightTokens)
         self.dtype = type(self.module.getVariable(self.token.data, True))
     elif self.token.name == "indexing":
         assertEmpty(rightTokens)
         self.children = [
             ASTNode(i, self.module) for i in [leftTokens, self.token.data]
         ]
     elif self.token.name == "array":
         assertEmpty(leftTokens, rightTokens)
         self.children = [ASTNode(self.token.data[1], self.module)]
     elif self.token.name == "literalArray":
         self.children = [
             ASTNode(t, self.module)
             for t in splitArguments(self.token.data)
         ]
         self.dtype = self.children[0].dtype
         self.children = [i.castTo(self.dtype) for i in self.children]
         self.dtype = dtypes.Array(self.dtype)
     else:
         raise ValueError("ERROR: Can't parse:'{}'.\n".format(
             self.token.name))
     # Resolve the types given the child types and available builtins.
     self.resolveTyping()
     return
Exemplo n.º 4
0
def createArray(inputs, token, mod):
    dtype = dtypes.Array(dtypes.getType(token.data[0]))
    addr, allocID = mod.allocate(dtype.subtype, inputs[0].addr)
    result = dtype(addr)
    result.allocID = allocID
    return result
Exemplo n.º 5
0
# For type-dependent builtins, it also says the accepted and return types.
catalog = {
    # Untyped builtins
    'function': callFunction,
    'literal': literal,
    'name': name,
    "()": parentheses,
    'print': printStatement,
    'literalArray': literalArray,
    '=': assignment,
    'index=': indexingAssignment,
    'free': freeMemory,
    'array': createArray,
    # Typed name:{"Arg1Type Args2Type":[function,retType]}
    'indexing': {
        "Array:{} Int".format(i): [indexArray, dtypes.getType(i)]
        for i in ["Real", "Int"]
    },
    'unary -':
    {i: [unaryPlusMinus, dtypes.getType(i)]
     for i in ['Real', 'Int']},
    'unary +':
    {i: [unaryPlusMinus, dtypes.getType(i)]
     for i in ['Real', 'Int']},
    '**': {
        "Real Real": [power, dtypes.Real]
    },
    '/': {
        "Real Real": [simpleBinary, dtypes.Real]
    },
    '//': {