Beispiel #1
0
def validate_varname(name, ctx):

    if not valid_varname(name):
        erstr = "Invalid resource name in " + ctx.label() + "."
        erstr += " Name '" + name + "' is not a valid GML name."
        return [erstr]
    return []
Beispiel #2
0
def validate_varname(name, ctx):

    if not valid_varname(name):
        erstr = "Invalid resource name in " + ctx.label() + "."
        erstr += " Name '" + name + "' is not a valid GML name."
        return [erstr]
    return []
Beispiel #3
0
    def feed(self, symbol):

        returned_output = ""
        warnings = []
        errors = []

        # Helper function for appending output. Will dynamically prefix with a @import_evt line
        def output(returned_output, string, is_import=False):

            mod_string = None
            if is_import and not self.last_out_import:
                mod_string = "@import_evt\n" + string
            elif not is_import and self.last_out_import:
                mod_string = "@endimport\n" + string
            else:
                mod_string = string

            returned_output += mod_string
            self.last_out_import = is_import
            self.prev_codeblock_symbols = [" "]
            return returned_output

        # Get context information
        ctx = self.context_stack[-1] if self.context_stack else None

        #print "S, C, I:", symbol, str(ctx.typ) + "s" + str(ctx.stage) if ctx else None, self.indent_level

        # Parse global symbols
        if not ctx:
            if symbol == 'object':
                self.context_stack.append(Ctx(CtxType.OBJ_DEC))
            elif symbol == 'room':
                self.context_stack.append(Ctx(CtxType.RM_DEC))
            elif symbol == 'script':
                self.context_stack.append(Ctx(CtxType.SCR_DEC))
            elif symbol == '#define' and self.allow_gmldef:
                self.context_stack.append(Ctx(CtxType.SCR_DEC_GM))

            # Error cases
            else:
                erstr = "Unexpected symbol '" + symbol + "'."
                if symbol in KEYWORDS:
                    erstr += " Keywords of this type belong in resource declarations."
                errors.append(erstr)

        # Parse object declaration symbols
        elif ctx.typ == CtxType.OBJ_DEC:

            # Name of object
            if ctx.stage == 0:
                errors.extend(validate_varname(symbol, ctx))
                returned_output = output(returned_output,
                                         "@obj_declare " + symbol + "\n")
                self.obj_names.add(symbol)
                ctx.advance()

            # Symbol following object name
            elif ctx.stage == 1:
                errors.extend(validate_symbol(symbol, ctx, [':', '{']))
                if symbol == ':':
                    ctx.advance()
                else:
                    ctx.stage = 4

            # Name of parent
            elif ctx.stage == 2:
                errors.extend(validate_varname(symbol, ctx))
                if symbol not in self.obj_names:
                    errors.append("No declared object matches name '" +
                                  symbol + "'.")
                returned_output = output(
                    returned_output,
                    "object_set_parent(this_resource," + symbol + ");\n", True)
                ctx.advance()

            elif ctx.stage == 3:
                errors.extend(validate_symbol(symbol, ctx, ['{']))
                ctx.advance()

            # Look for nested declarations
            elif ctx.stage == 4:
                errors.extend(
                    validate_symbol(symbol, ctx,
                                    ['}', 'event', 'properties', 'import']))
                if symbol == '}':
                    self.context_stack.pop()
                elif symbol == 'event':
                    self.context_stack.append(Ctx(CtxType.EVENT))
                elif symbol == 'properties':
                    self.context_stack.append(Ctx(CtxType.PROP))
                elif symbol == 'import':
                    self.context_stack.append(Ctx(CtxType.IMPORT))

            else:
                raise NotImplementedError()

        # Parse room declaration symbols
        elif ctx.typ == CtxType.RM_DEC:

            # Name of room
            if ctx.stage == 0:
                errors.extend(validate_varname(symbol, ctx))
                returned_output = output(returned_output,
                                         "@rm_declare " + symbol + "\n")
                self.rm_names.add(symbol)
                ctx.advance()

            # Curly following room name
            elif ctx.stage == 1:
                errors.extend(validate_symbol(symbol, ctx, ['{']))
                ctx.advance()

            # Look for nested declarations OR list of objects
            elif ctx.stage == 2:

                # Check if symbol is object
                if symbol in self.obj_names:
                    returned_output = output(returned_output, symbol + "\n")
                    ctx.advance()

                # Check nested declarations
                elif symbol == '}':
                    self.context_stack.pop()
                elif symbol == 'properties':
                    self.context_stack.append(Ctx(CtxType.PROP))
                elif symbol == 'import':
                    self.context_stack.append(Ctx(CtxType.IMPORT))

                # Error cases
                else:
                    if valid_varname(symbol):
                        errors.append("Unknown object in room declaration: '" +
                                      symbol + "'.")
                    else:
                        errors.append(
                            "Unexpected symbol in room declaration: '" +
                            symbol + "'.")

            elif ctx.stage == 3:

                # Check if symbol is object
                if symbol in self.obj_names:
                    errors.append("Object names must be separated by commas")

                # Check nested declarations
                elif symbol == '}':
                    self.context_stack.pop()
                elif symbol == 'properties':
                    self.context_stack.append(Ctx(CtxType.PROP))
                elif symbol == 'import':
                    self.context_stack.append(Ctx(CtxType.IMPORT))
                elif symbol == ',':
                    ctx.advance()

                # Error cases
                else:
                    errors.append("Unexpected symbol in room declaration: '" +
                                  symbol + "'.")

            # Following a comma
            elif ctx.stage == 4:

                # Only GML object can follow commas
                if symbol in self.obj_names:
                    returned_output = output(returned_output, symbol + "\n")
                    ctx.stage = 3
                else:
                    errors.append(
                        "Expecting object name after ',' but instead found '" +
                        symbol + "'.")

            else:
                raise NotImplementedError()

        # Parse property symbols
        elif ctx.typ == CtxType.PROP:
            if ctx.stage == 0:
                errors.extend(validate_symbol(symbol, ctx, ['{']))
                self.codeblock = ""
                ctx.advance()

            # Add data to block
            elif ctx.stage == 1:
                if symbol == '}':

                    # Output parsed data
                    prefix = "object" if self.context_stack[
                        -2].typ == CtxType.OBJ_DEC else "room"
                    import_block = parse_properties(self.codeblock, prefix,
                                                    errors)
                    if import_block != None:
                        returned_output = output(returned_output, import_block,
                                                 True)
                    self.context_stack.pop()
                else:
                    self.codeblock_add(symbol)

        # Parse import symbols
        elif ctx.typ == CtxType.IMPORT:
            if ctx.stage == 0:
                errors.extend(validate_symbol(symbol, ctx, ['{']))
                self.codeblock = ""
                ctx.advance()

            # Add data to block
            elif ctx.stage == 1:
                if symbol == '}' and self.indent_level == 0:
                    returned_output = output(returned_output,
                                             self.codeblock + "\n", True)
                    self.context_stack.pop()

                else:
                    if symbol == '{': self.indent_level += 1
                    elif symbol == '}': self.indent_level -= 1
                    self.codeblock_add(symbol)

        # Parse event symbols
        elif ctx.typ == CtxType.EVENT:
            if ctx.stage == 0:

                # Prefix with ev_
                mod_symbol = symbol if symbol[:3] == "ev_" else "ev_" + symbol

                # Match with event type names
                if mod_symbol not in EVENT_TYPES.keys():
                    errors.append("No valid event type matches name: '" +
                                  mod_symbol + "'.")
                else:
                    self.event_type_name = mod_symbol
                    returned_output = output(
                        returned_output,
                        "@obj_evt " + str(EVENT_TYPES[mod_symbol]) + " ")
                ctx.advance()

            elif ctx.stage == 1:
                errors.extend(validate_symbol(symbol, ctx, ['(']))
                ctx.advance()

            elif ctx.stage == 2:
                if is_number(symbol):
                    returned_output = output(returned_output, symbol + "\n")
                    ctx.advance()
                else:

                    # Check no arguments
                    if symbol == ')':
                        returned_output = output(returned_output, "0\n")
                        ctx.stage = 4
                        if not (self.event_type_name == "ev_create"
                                or self.event_type_name == "ev_destroy"
                                or self.event_type_name == "ev_draw"):
                            errors.append(
                                "Expecting event number argument for event of type "
                                + self.event_type_name)

                    # Check if it is a single char for a keycode
                    elif self.event_type_name[:6] == "ev_key" and len(
                            symbol
                    ) == 3 and symbol[0] == '"' and symbol[2] == '"':
                        returned_output = output(
                            returned_output,
                            str(ord(symbol[1].upper())) + "\n")
                        ctx.advance()

                    # Check for event constants
                    else:
                        prefix = symbol[:3]

                        if self.event_type_name == "ev_create" or self.event_type_name == "ev_destroy" or self.event_type_name == "ev_draw":
                            errors.append(
                                "Unexpected event number argument provided for event of type "
                                + self.event_type_name)
                        elif self.event_type_name[:6] == "ev_key":
                            if prefix == "ev_":
                                errors.append(
                                    "Unexpected event number constant beginning with 'ev_' for event type "
                                    + self.event_type_name)
                            elif prefix == "vk_":
                                returned_output = output(
                                    returned_output,
                                    str(KEYS[symbol]) + "\n")
                            else:
                                mod_symbol = "vk_" + symbol
                                if mod_symbol not in KEYS.keys():
                                    errors.append("Unknown key constant " +
                                                  mod_symbol)
                                else:
                                    returned_output = output(
                                        returned_output,
                                        str(KEYS[mod_symbol]) + "\n")
                        else:
                            if prefix == "vk_":
                                errors.append(
                                    "Unexpected event number constant beginning with 'vk_' for event type "
                                    + self.event_type_name)
                            elif prefix == "ev_":
                                returned_output = output(
                                    returned_output,
                                    str(EVENT_NUMS[symbol]) + "\n")
                            else:
                                mod_symbol = "ev_" + symbol
                                if mod_symbol not in EVENT_NUMS.keys():
                                    errors.append(
                                        "Unknown event number constant " +
                                        mod_symbol)
                                else:
                                    returned_output = output(
                                        returned_output,
                                        str(EVENT_NUMS[mod_symbol]) + "\n")

                        ctx.advance()

            elif ctx.stage == 3:
                errors.extend(validate_symbol(symbol, ctx, [')']))
                ctx.advance()

            elif ctx.stage == 4:
                errors.extend(validate_symbol(symbol, ctx, ['{']))
                self.codeblock = ""
                ctx.advance()

            # Add data to block
            elif ctx.stage == 5:
                if symbol == '}' and self.indent_level == 0:
                    returned_output = output(returned_output,
                                             self.codeblock + "\n")
                    self.context_stack.pop()

                else:
                    if symbol == '{': self.indent_level += 1
                    elif symbol == '}': self.indent_level -= 1
                    self.codeblock_add(symbol)

        # Parse script declaration symbols
        elif ctx.typ == CtxType.SCR_DEC:

            # Name of script
            if ctx.stage == 0:
                errors.extend(validate_varname(symbol, ctx))
                returned_output = output(returned_output,
                                         "@scr_declare " + symbol + "\n")
                self.scr_names.add(symbol)
                self.scr_args_current = []
                ctx.advance()

            # Opening parenthesis following script name
            elif ctx.stage == 1:
                errors.extend(validate_symbol(symbol, ctx, ['(']))
                ctx.advance()

            # Argument name or closing paren
            elif ctx.stage == 2:

                # Check if end of arguments
                if symbol == ")":
                    ctx.stage = 5
                else:
                    # Verify name
                    errors.extend(validate_varname(symbol, ctx))
                    self.scr_args_current.append(symbol)
                    ctx.advance()

            # Comma or end paren
            elif ctx.stage == 3:
                errors.extend(validate_symbol(symbol, ctx, [')', ',']))
                if symbol == ")":
                    ctx.stage = 5
                elif symbol == ",":
                    ctx.advance()

            # Argument name
            elif ctx.stage == 4:
                errors.extend(validate_varname(symbol, ctx))
                self.scr_args_current.append(symbol)
                ctx.stage = 3

            # Open curly
            elif ctx.stage == 5:
                errors.extend(validate_symbol(symbol, ctx, ['{']))
                self.codeblock = ""
                var_declarations = ""
                for index, argument in enumerate(self.scr_args_current):
                    var_declarations += "var " + argument + ";"
                    var_declarations += argument + "=argument" + str(
                        index) + ";\n"
                returned_output = output(returned_output, var_declarations)
                ctx.advance()

            # Actual code symbols
            elif ctx.stage == 6:
                if symbol == '}' and self.indent_level == 0:
                    returned_output = output(returned_output,
                                             self.codeblock + "\n")
                    self.context_stack.pop()

                else:
                    if symbol == '{': self.indent_level += 1
                    elif symbol == '}': self.indent_level -= 1
                    else:
                        self.codeblock_add(symbol)

        # Parse GML-style script declaration symbols
        elif ctx.typ == CtxType.SCR_DEC_GM:

            # Name of script
            if ctx.stage == 0:
                errors.extend(validate_varname(symbol, ctx))
                returned_output = output(returned_output,
                                         "@scr_declare " + symbol + "\n")
                self.scr_names.add(symbol)
                self.scr_args_current = []
                self.indent_level = 0
                self.codeblock = ""
                ctx.advance()

            # Actual code symbols
            elif ctx.stage == 1:
                if symbol in KEYWORDS_SE and self.indent_level == 0:
                    returned_output = output(returned_output,
                                             self.codeblock + "\n")
                    self.context_stack.pop()
                    self.indent_level = 0
                    self.feed(
                        symbol)  # Feed the symbol again in the new context

                else:
                    if symbol == '{': self.indent_level += 1
                    elif symbol == '}': self.indent_level -= 1
                    self.codeblock_add(symbol)

        else:
            raise NotImplementedError(
                "Not all context types implemented in compiler")

        # Prefix with initial if first time outputting
        if not self.has_out:
            returned_output = "\n@gml\n" + returned_output
            self.has_out = True

        return (returned_output, warnings, errors)
Beispiel #4
0
    def feed(self, symbol):

        returned_output = ""
        warnings = []
        errors = []

        # Helper function for appending output. Will dynamically prefix with a @import_evt line
        def output(returned_output, string, is_import=False):

            mod_string = None
            if is_import and not self.last_out_import:
                mod_string = "@import_evt\n" + string
            elif not is_import and self.last_out_import:
                mod_string = "@endimport\n" + string
            else:
                mod_string = string

            returned_output += mod_string
            self.last_out_import = is_import
            self.prev_codeblock_symbols = [" "]
            return returned_output

        # Get context information
        ctx = self.context_stack[-1] if self.context_stack else None

        #print "S, C, I:", symbol, str(ctx.typ) + "s" + str(ctx.stage) if ctx else None, self.indent_level

        # Parse global symbols
        if not ctx:
            if symbol == 'object':
                self.context_stack.append(Ctx(CtxType.OBJ_DEC))
            elif symbol == 'room':
                self.context_stack.append(Ctx(CtxType.RM_DEC))
            elif symbol == 'script':
                self.context_stack.append(Ctx(CtxType.SCR_DEC))
            elif symbol == '#define' and self.allow_gmldef:
                self.context_stack.append(Ctx(CtxType.SCR_DEC_GM))

            # Error cases
            else:
                erstr = "Unexpected symbol '" + symbol + "'."
                if symbol in KEYWORDS:
                    erstr += " Keywords of this type belong in resource declarations."
                errors.append(erstr)

        # Parse object declaration symbols
        elif ctx.typ == CtxType.OBJ_DEC:

            # Name of object
            if ctx.stage == 0:
                errors.extend(validate_varname(symbol, ctx))
                returned_output = output(returned_output, "@obj_declare " + symbol + "\n")
                self.obj_names.add(symbol)
                ctx.advance()

            # Symbol following object name
            elif ctx.stage == 1:
                errors.extend(validate_symbol(symbol, ctx, [':', '{']))
                if symbol == ':':
                    ctx.advance()
                else:
                    ctx.stage = 4

            # Name of parent
            elif ctx.stage == 2:
                errors.extend(validate_varname(symbol, ctx))
                if symbol not in self.obj_names:
                    errors.append("No declared object matches name '" + symbol + "'.")
                returned_output = output(returned_output, "object_set_parent(this_resource," + symbol + ");\n", True)
                ctx.advance()

            elif ctx.stage == 3:
                errors.extend(validate_symbol(symbol, ctx, ['{']))
                ctx.advance()

            # Look for nested declarations
            elif ctx.stage == 4:
                errors.extend(validate_symbol(symbol, ctx, ['}', 'event', 'properties', 'import']))
                if symbol == '}':
                    self.context_stack.pop()
                elif symbol == 'event':
                    self.context_stack.append(Ctx(CtxType.EVENT))
                elif symbol == 'properties':
                    self.context_stack.append(Ctx(CtxType.PROP))
                elif symbol == 'import':
                    self.context_stack.append(Ctx(CtxType.IMPORT))

            else:
                raise NotImplementedError()

        # Parse room declaration symbols
        elif ctx.typ == CtxType.RM_DEC:

            # Name of room
            if ctx.stage == 0:
                errors.extend(validate_varname(symbol, ctx))
                returned_output = output(returned_output, "@rm_declare " + symbol + "\n")
                self.rm_names.add(symbol)
                ctx.advance()

            # Curly following room name
            elif ctx.stage == 1:
                errors.extend(validate_symbol(symbol, ctx, ['{']))
                ctx.advance()

            # Look for nested declarations OR list of objects
            elif ctx.stage == 2:

                # Check if symbol is object
                if symbol in self.obj_names:
                    returned_output = output(returned_output, symbol + "\n")
                    ctx.advance()

                # Check nested declarations
                elif symbol == '}':
                    self.context_stack.pop()
                elif symbol == 'properties':
                    self.context_stack.append(Ctx(CtxType.PROP))
                elif symbol == 'import':
                    self.context_stack.append(Ctx(CtxType.IMPORT))

                # Error cases
                else:
                    if valid_varname(symbol):
                        errors.append("Unknown object in room declaration: '" + symbol + "'.")
                    else:
                        errors.append("Unexpected symbol in room declaration: '" + symbol + "'.")

            elif ctx.stage == 3:

                # Check if symbol is object
                if symbol in self.obj_names:
                    errors.append("Object names must be separated by commas")

                # Check nested declarations
                elif symbol == '}':
                    self.context_stack.pop()
                elif symbol == 'properties':
                    self.context_stack.append(Ctx(CtxType.PROP))
                elif symbol == 'import':
                    self.context_stack.append(Ctx(CtxType.IMPORT))
                elif symbol == ',':
                    ctx.advance()

                # Error cases
                else:
                    errors.append("Unexpected symbol in room declaration: '" + symbol + "'.")

            # Following a comma
            elif ctx.stage == 4:

                # Only GML object can follow commas
                if symbol in self.obj_names:
                    returned_output = output(returned_output, symbol + "\n")
                    ctx.stage = 3
                else:
                    errors.append("Expecting object name after ',' but instead found '" + symbol + "'.")

            else:
                raise NotImplementedError()

        # Parse property symbols
        elif ctx.typ == CtxType.PROP:
            if ctx.stage == 0:
                errors.extend(validate_symbol(symbol, ctx, ['{']))
                self.codeblock = ""
                ctx.advance()

            # Add data to block
            elif ctx.stage == 1:
                if symbol == '}':

                    # Output parsed data
                    prefix = "object" if self.context_stack[-2].typ == CtxType.OBJ_DEC else "room"
                    import_block = parse_properties(self.codeblock, prefix, errors)
                    if import_block != None:
                        returned_output = output(returned_output, import_block, True)
                    self.context_stack.pop()
                else:
                    self.codeblock_add(symbol)
            
        # Parse import symbols
        elif ctx.typ == CtxType.IMPORT:
            if ctx.stage == 0:
                errors.extend(validate_symbol(symbol, ctx, ['{']))
                self.codeblock = ""
                ctx.advance()

            # Add data to block
            elif ctx.stage == 1:
                if symbol == '}' and self.indent_level == 0:
                    returned_output = output(returned_output, self.codeblock + "\n", True)
                    self.context_stack.pop()

                else:
                    if symbol == '{': self.indent_level += 1
                    elif symbol == '}': self.indent_level -= 1
                    self.codeblock_add(symbol)
            
        # Parse event symbols
        elif ctx.typ == CtxType.EVENT:
            if ctx.stage == 0:

                # Prefix with ev_
                mod_symbol = symbol if symbol[:3] == "ev_" else "ev_" + symbol

                # Match with event type names
                if mod_symbol not in EVENT_TYPES.keys():
                    errors.append("No valid event type matches name: '" + mod_symbol + "'.")
                else:
                    self.event_type_name = mod_symbol
                    returned_output = output(returned_output, "@obj_evt " + str(EVENT_TYPES[mod_symbol]) + " ")
                ctx.advance()

            elif ctx.stage == 1:
                errors.extend(validate_symbol(symbol, ctx, ['(']))
                ctx.advance()

            elif ctx.stage == 2:
                if is_number(symbol):
                    returned_output = output(returned_output, symbol + "\n")
                    ctx.advance()
                else:

                    # Check no arguments
                    if symbol == ')':
                        returned_output = output(returned_output, "0\n")
                        ctx.stage = 4
                        if not (self.event_type_name == "ev_create" or self.event_type_name == "ev_destroy" or self.event_type_name == "ev_draw"):
                            errors.append("Expecting event number argument for event of type " + self.event_type_name)

                    # Check if it is a single char for a keycode
                    elif self.event_type_name[:6] == "ev_key" and len(symbol) == 3 and symbol[0] == '"' and symbol[2] == '"':
                        returned_output = output(returned_output, str(ord(symbol[1].upper())) + "\n")
                        ctx.advance()

                    # Check for event constants
                    else:
                        prefix = symbol[:3]

                        if self.event_type_name == "ev_create" or self.event_type_name == "ev_destroy" or self.event_type_name == "ev_draw":
                            errors.append("Unexpected event number argument provided for event of type " + self.event_type_name)
                        elif self.event_type_name[:6] == "ev_key":
                            if prefix == "ev_":
                                errors.append("Unexpected event number constant beginning with 'ev_' for event type " + self.event_type_name)
                            elif prefix == "vk_":
                                returned_output = output(returned_output, str(KEYS[symbol]) + "\n")
                            else:
                                mod_symbol = "vk_" + symbol
                                if mod_symbol not in KEYS.keys():
                                    errors.append("Unknown key constant " + mod_symbol)
                                else:
                                    returned_output = output(returned_output, str(KEYS[mod_symbol]) + "\n")
                        else:
                            if prefix == "vk_":
                                errors.append("Unexpected event number constant beginning with 'vk_' for event type " + self.event_type_name)
                            elif prefix == "ev_":
                                returned_output = output(returned_output, str(EVENT_NUMS[symbol]) + "\n")
                            else:
                                mod_symbol = "ev_" + symbol
                                if mod_symbol not in EVENT_NUMS.keys():
                                    errors.append("Unknown event number constant " + mod_symbol)
                                else:
                                    returned_output = output(returned_output, str(EVENT_NUMS[mod_symbol]) + "\n")

                        ctx.advance()

            elif ctx.stage == 3:
                errors.extend(validate_symbol(symbol, ctx, [')']))
                ctx.advance()

            elif ctx.stage == 4:
                errors.extend(validate_symbol(symbol, ctx, ['{']))
                self.codeblock = ""
                ctx.advance()

            # Add data to block
            elif ctx.stage == 5:
                if symbol == '}' and self.indent_level == 0:
                    returned_output = output(returned_output, self.codeblock + "\n")
                    self.context_stack.pop()

                else:
                    if symbol == '{': self.indent_level += 1
                    elif symbol == '}': self.indent_level -= 1
                    self.codeblock_add(symbol)

        # Parse script declaration symbols
        elif ctx.typ == CtxType.SCR_DEC:

            # Name of script
            if ctx.stage == 0:
                errors.extend(validate_varname(symbol, ctx))
                returned_output = output(returned_output, "@scr_declare " + symbol + "\n")
                self.scr_names.add(symbol)
                self.scr_args_current = []
                ctx.advance()

            # Opening parenthesis following script name
            elif ctx.stage == 1:
                errors.extend(validate_symbol(symbol, ctx, ['(']))
                ctx.advance()

            # Argument name or closing paren
            elif ctx.stage == 2:

                # Check if end of arguments
                if symbol == ")":
                    ctx.stage = 5
                else:
                    # Verify name
                    errors.extend(validate_varname(symbol, ctx))
                    self.scr_args_current.append(symbol)
                    ctx.advance()

            # Comma or end paren
            elif ctx.stage == 3:
                errors.extend(validate_symbol(symbol, ctx, [')', ',']))
                if symbol == ")":
                    ctx.stage = 5
                elif symbol == ",":
                    ctx.advance()

            # Argument name
            elif ctx.stage == 4:
                errors.extend(validate_varname(symbol, ctx))
                self.scr_args_current.append(symbol)
                ctx.stage = 3

            # Open curly
            elif ctx.stage == 5:
                errors.extend(validate_symbol(symbol, ctx, ['{']))
                self.codeblock = ""
                var_declarations = ""
                for index, argument in enumerate(self.scr_args_current):
                    var_declarations += "var " + argument + ";"
                    var_declarations += argument + "=argument" + str(index) + ";\n"
                returned_output = output(returned_output, var_declarations)
                ctx.advance()

            # Actual code symbols
            elif ctx.stage == 6:
                if symbol == '}' and self.indent_level == 0:
                    returned_output = output(returned_output, self.codeblock + "\n")
                    self.context_stack.pop()

                else:
                    if symbol == '{': self.indent_level += 1
                    elif symbol == '}': self.indent_level -= 1
                    else:
                        self.codeblock_add(symbol)

        # Parse GML-style script declaration symbols
        elif ctx.typ == CtxType.SCR_DEC_GM:

            # Name of script
            if ctx.stage == 0:
                errors.extend(validate_varname(symbol, ctx))
                returned_output = output(returned_output, "@scr_declare " + symbol + "\n")
                self.scr_names.add(symbol)
                self.scr_args_current = []
                self.indent_level = 0
                self.codeblock = ""
                ctx.advance()

            # Actual code symbols
            elif ctx.stage == 1:
                if symbol in KEYWORDS_SE and self.indent_level == 0:
                    returned_output = output(returned_output, self.codeblock + "\n")
                    self.context_stack.pop()
                    self.indent_level = 0
                    self.feed(symbol) # Feed the symbol again in the new context

                else:
                    if symbol == '{': self.indent_level += 1
                    elif symbol == '}': self.indent_level -= 1
                    self.codeblock_add(symbol)

        else:
            raise NotImplementedError("Not all context types implemented in compiler")
            

        # Prefix with initial if first time outputting
        if not self.has_out:
            returned_output = "\n@gml\n" + returned_output
            self.has_out = True

        return (returned_output, warnings, errors)