Example #1
0
    def parse_declaration(self) -> list:
        # Int thing
        # Int thing = expr
        # TODO: module.Thingy thing
        #
        # "Int thing = expr" produces overlapping Declaration and
        # Assignment nodes, that's why this returns a list of nodes
        datatype = self.parse_name()  # TODO: module's Thing
        variable = self.parse_name()

        if self.tokens.coming_up().kind == 'NEWLINE':
            self.tokens.pop_newline()
            return [
                Declaration(Location.between(datatype, variable), datatype,
                            variable.name)
            ]

        self.tokens.check_and_pop('OP', '=')
        initial_value = self.parse_expression()
        self.tokens.pop_newline()
        return [
            Declaration(Location.between(datatype, variable), datatype,
                        variable.name),
            Assignment(Location.between(variable, initial_value), variable,
                       initial_value)
        ]
Example #2
0
    def parse_function_def(self):
        # function main() { ... }
        # function thing() returns Int { ... }
        function_keyword = self.tokens.check_and_pop('NAME', 'function')
        name = self.parse_name()
        args, junk = self._parse_comma_list('(',
                                            ')',
                                            parsemethod=self._type_and_name)

        if self.tokens.coming_up().startswith(['NAME', 'returns']):
            self.tokens.pop()
            returntype = self.parse_name()
        else:
            returntype = None

        opening_brace = self.tokens.check_and_pop('OP', '{')
        if self.tokens.coming_up().kind == 'NEWLINE':
            self.tokens.pop_newline()
        body = []
        while not self.tokens.coming_up().startswith(['OP', '}']):
            body.extend(self.parse_statement())
        closing_brace = self.tokens.check_and_pop('OP', '}')
        self.tokens.pop_newline()

        return FunctionDef(Location.between(function_keyword, closing_brace),
                           name.name, args, returntype, body)
Example #3
0
    def parse_expression(self):
        coming_up = self.tokens.coming_up()
        if coming_up.kind == 'NAME':
            # hello
            result = self.parse_name()
        elif coming_up.kind == 'STRING':
            # "hello"
            result = self.parse_string()
        elif coming_up.kind == 'INTEGER':
            # 123
            result = self.parse_integer()
        elif coming_up.startswith(['OP', '(']):
            result = self.parse_parentheses()
        else:
            raise CompileError(
                "this should be variable name, string, integer or '('",
                coming_up.location)

        # check for function calls, this is a while loop to allow
        # function calls like thing()()()
        while self.tokens.coming_up().startswith(['OP', '(']):
            args, stop_token = self._parse_comma_list('(', ')')
            result = FunctionCall(Location.between(result, stop_token), result,
                                  args)

        return result
Example #4
0
    def _parse_comma_list(self, start='(', stop=')', parsemethod=None):
        # ( )
        # ( element )
        # ( element , )
        # ( element , element )
        # ( element , element , )
        # ...
        if parsemethod is None:
            parsemethod = self.parse_expression

        start_token = self.tokens.check_and_pop('OP', start)
        if self.tokens.coming_up().startswith(['OP', stop]):
            # empty list
            return ([], self.tokens.pop())

        elements = []
        while True:
            if self.tokens.coming_up().startswith(['OP', ',']):
                raise CompileError("don't put a ',' here",
                                   self.tokens.coming_up().location)
            elements.append(parsemethod())

            if self.tokens.coming_up().startswith(['OP', stop]):
                return (elements, self.tokens.pop())

            comma = self.tokens.check_and_pop('OP', ',')
            if self.tokens.coming_up().startswith(['OP', ',']):
                raise CompileError(
                    "two ',' characters",
                    Location.between(comma, self.tokens.coming_up()))

            if self.tokens.coming_up().startswith(['OP', stop]):
                return (elements, self.tokens.pop())
Example #5
0
 def assignment(self):
     # thing = value
     # TODO: thing's stuff = value
     target = self.parse_name()
     self.tokens.check_and_pop('OP', '=')
     value = self.parse_expression()
     self.tokens.pop_newline()
     return Assignment(Location.between(target, value), target, value)
Example #6
0
    def parse_if(self):
        # if cond { statements }
        the_if = self.tokens.check_and_pop('NAME', 'if')
        condition = self.parse_expression()

        self.tokens.check_and_pop('OP', '{')
        body = []

        # allow "if thing { }" without a newline
        if not self.tokens.coming_up().startswith(['OP', '}']):
            self.tokens.pop_newline()
            while not self.tokens.coming_up().startswith(['OP', '}']):
                body.extend(self.parse_statement())
        closing_brace = self.tokens.check_and_pop('OP', '}')

        self.tokens.pop_newline()
        return If(Location.between(the_if, closing_brace), condition, body)
Example #7
0
 def parse_return(self):
     the_return = self.tokens.check_and_pop('NAME', 'return')
     value = self.parse_expression()
     self.tokens.pop_newline()
     return Return(Location.between(the_return, value), value)