def parse_configuration_comamnd(self, res, parts): inst = Namespace(type='configuration') res.instructions.append(inst) if len(parts) == 2: inst.name = strip_quotes(parts[1]) else: assert len(parts) == 1 def generic_prop_group(group_data, body_parts): group = Namespace() inst.setdefault(group_data.pythonized, []).append(group) if group_data.nargs > 0: group.args = body_parts[1:group_data.nargs + 1] if len(body_parts) == group_data.nargs + 2: group.cond = parse_cond(body_parts[-1]) else: assert len(body_parts) == group_data.nargs + 1 if group_data.allow_body: for cmd, body_parts in self.parse_body_commands( lowercase=False): group.setdefault(cmd, []).append(body_parts[1:]) elif self.token.type == '{': # TODO(maximsmol): use the real name here self.die( f'Configuration command {group_data.pythonized} should not have a body.' ) for cmd, body_parts in self.parse_body_commands(lowercase=False): if cmd not in configuration_commands: self.die(f'Unknown configuration command {cf.bold(cmd)}.') generic_prop_group(configuration_commands[cmd], body_parts)
def parse_command(self, res): parts = self.parse_command_parts() cmd = self.need_command(parts, lowercase=False) if cmd == 'Macro': name = string_like(parts[1]) # TODO(maximsmol): weird unquoted macro values are allowed # and we skip the spaces in them + this parsing # is all around weird value = string_like(parts[2]) cond = None if len(parts) > 3: # TODO(maximsmol): check that weird unquoted macros are unquoted value_parts = [value] i = 3 for p in parts[3:]: if p.type == 'cond': cond = parse_cond(parts[3]) assert i == len(parts) - 1 break value_parts.append(raw_string(p)) i += 1 # TODO(maximsmol): this actually loses some whitespaces value = ' '.join(value_parts) else: assert len(parts) == 3 inst = Namespace(type='macro') inst.name = name inst.value = value if cond is not None: inst.cond = cond res.instructions.append(inst) elif cmd == 'Conditional': name = raw_string(parts[1]) inst = Namespace(type='conditional') res.instructions.append(inst) inst.name = name inst.value = strip_quotes(parts[2]) cond = None if len(parts) == 4: inst.cond = parse_cond(parts[3]) else: assert len(parts) == 3 elif cmd == 'MacroRequired': inst = Namespace(type='macro_required') if len(parts) == 3: inst.default = strip_quotes(parts[2]) else: assert len(parts) == 2 inst.name = string_like(parts[1]) inst.allow_empty = False elif cmd == 'MacroRequiredAllowEmpty': inst = Namespace(type='macro_required') if len(parts) == 3: inst.default = strip_quotes(parts[2]) else: assert len(parts) == 2 inst.name = string_like(parts[1]) inst.allow_empty = True elif cmd == 'LoadAddressMacro': inst = Namespace(type='address_macro') res.instructions.append(inst) assert len(parts) == 2 inst.name = raw_string(parts[1]) for body_parts in self.parse_body(): # TODO(maximsmol): parse this # this is only used on XBOX afaik pass elif cmd == 'LoadAddressMacroAuto': inst = Namespace(type='address_macro_auto') res.instructions.append(inst) assert len(parts) == 4 inst.name = raw_string(parts[1]) inst.addr = int(raw_string(parts[2]), 16) inst.cond = parse_cond(parts[3]) for body_parts in self.parse_body(): # TODO(maximsmol): parse this # this is only used on XBOX afaik pass elif cmd == 'IgnoreRedundancyWarning': inst = Namespace(type='ignore_redundancy_warning') assert len(parts) == 2 inst.value = strip_quotes(parts[1]).lower() elif cmd in ['Include', 'include']: # Valve, why do you insist on mixing case path = strip_quotes(parts[1]) cond = None if len(parts) == 3: cond = parse_cond(parts[2]) else: assert len(parts) == 2 inst = Namespace(type='include') inst.path = path if cond is not None: inst.cond = cond res.instructions.append(inst) elif cmd == 'Configuration': self.parse_configuration_comamnd(res, parts) elif cmd == 'Project': proj = Namespace(type='project', folders=Namespace(), files=[]) res.instructions.append(proj) if len(parts) == 2: name = strip_quotes(parts[1]) else: assert len(parts) == 1 for cmd, body_parts in self.parse_body_commands(): if cmd == 'folder': self.parse_folder_command(proj, body_parts) elif cmd in ['file']: self.parse_file_command(proj.files, parts) else: self.die(f'Unknown project command {cf.bold(cmd)}.') elif cmd == 'CustomBuildStep': self.parse_cmd_list_schema(res, project_schema, parts) # TODO(maximsmol): type will be renamed to name res.instructions[-1].type = cmd else: self.die(f'Unknown command {cf.bold(cmd)}.')