示例#1
0
 def build_card(self, deck: Deck, card_data: CardData,
                block: CardBlock) -> None:
     card = deck.make_card()
     card.set_count(card_data.count)
     if 'name' in card_data.data:
         card.name = card_data.data['name']
     if 'description' in card_data.data:
         card.name = card_data.data['description']
     exec = Executor(self.ctx, card, None)
     exec.env['card'] = card_data.data
     exec.env['deck'] = deck.data
     try:
         for renderer in block.renderers:
             exec.execute(renderer)
     except ValidateError as ve:
         raise ValidateError(
             f"while rendering card {json.dumps(card_data.data, ensure_ascii=False)}:\n{ve}"
         ) from ve
     if not card.get_front():
         raise ValidateError(
             f"no front face for card {json.dumps(card_data.data, ensure_ascii=False)}"
         )
     if not card.get_back():
         raise ValidateError(
             f"no back face for card {json.dumps(card_data.data, ensure_ascii=False)}"
         )
示例#2
0
	def parse_scheme(self, elt: Element, scheme: ElementScheme):
		params: Dict[str, Any] = dict()
		for key, value in elt.attrib.items():
			if key not in scheme.attrs:
				raise ValidateError(f"unexpected attribute '{encode(key)}'")
			try:
				params[key] = scheme.attrs[key](value)
			except ValidateError as ve:
				raise ValidateError(f"in attribute '{encode(key)}': {ve}") from ve
		for key in scheme.required:
			if key not in params:
				raise ValidateError(f"missing required attribute '{key}'")
		return params
示例#3
0
def parse_bool(value):
    if value == "true":
        return True
    elif value == "false":
        return False
    else:
        raise ValidateError("expected 'true' or 'false'")
示例#4
0
	def parse_style(self, style_elt: Element):
		params = self.parse_scheme(style_elt, style_scheme)
		name = params['name']
		if name in self.styles:
			raise ValidateError(f"duplicate style '{name}'")
		self.styles[name] = params
		for elt in style_elt:
			raise self.unexpected_elt(elt)
示例#5
0
	def parse_case(self, case_elt: Element) -> StmtCase:
		params = self.parse_scheme(case_elt, case_scheme)
		case = StmtCase(self.getloc(case_elt))
		for elt in case_elt:
			if elt.tag == "when":
				case.whens.append(self.process_element(elt, self.parse_when_block))
			elif elt.tag == "default":
				if case.kelse is not None:
					raise ValidateError("duplicate <else> element")
示例#6
0
def parse_valign(value):
    if value == "top":
        return VAlign.Top
    elif value == "center":
        return VAlign.Center
    elif value == "bottom":
        return VAlign.Bottom
    else:
        raise ValidateError(
            "invalid value (expected 'top', 'center' or 'bottom')")
示例#7
0
	def add_card(self, block: CardBlock, data: Dict[str, str]):
		card_data = CardData()
		for key, value in data.items():
			if key == "count":
				try:
					card_data.count = int(value)
				except ValueError:
					raise ValidateError(f"invalid 'count' value of {encode(value)}")
			card_data.data[key] = value
		block.cards.append(card_data)
示例#8
0
def to_number(val):
    if isinstance(val, int):
        return val
    if isinstance(val, float):
        return val
    try:
        return int(val)
    except ValueError:
        try:
            return float(val)
        except ValueError:
            raise ValidateError("expected integer")
示例#9
0
def parse_halign(value):
    if value == "left":
        return HAlign.Left
    elif value == "center":
        return HAlign.Center
    elif value == "right":
        return HAlign.Right
    elif value == "justify":
        return HAlign.Justify
    else:
        raise ValidateError(
            "invalid value (expected 'left', 'center', 'right' or 'justify')")
示例#10
0
 def compute(self, expr: Expr) -> Any:
     if expr is None:
         return None
     if isinstance(expr, ExprLit):
         return expr.s
     elif isinstance(expr, ExprConcat):
         return ''.join(map(self.eval, expr.pieces))
     elif isinstance(expr, ExprField):
         lhs = self.compute(expr.obj)
         if isinstance(lhs, dict):
             return lhs.get(expr.field, None)
         else:
             raise ValidateError(
                 f"cannot read property '{encode(expr.field)}' of non-object"
             )
     elif isinstance(expr, ExprID):
         if expr.s in self.env:
             return self.env[expr.s]
         else:
             raise ValidateError(
                 f"variable '{encode(expr.s)}' doesn't exist")
     elif isinstance(expr, ExprCall):
         func = expr.func
         if func not in funcs:
             raise ValidateError(f"unknown function '{func}'")
         func_data = funcs[func]
         args = []
         for arg in expr.args:
             args.append(self.compute(arg))
         params = func_data['args']
         if len(args) != len(params):
             raise ValidateError(
                 f"invalid number of arguments for function '{func}'")
         converted_args = []
         for param, arg in zip(params, args):
             converted_args.append(param(arg))
         return func_data['call'](*converted_args)
     else:
         raise ValidateError("invalid expression")
示例#11
0
	def resolve_style(self, name: str) -> TextStyle:
		if name in self.resolved_styles:
			return self.resolved_styles[name]
		if name not in self.styles:
			raise ValidateError(f"text style '{encode(name)}' is not defined")
		params = self.styles[name]
		self.resolved_styles[name] = None
		parent_name = params.get('parent')
		parent = None
		if parent_name is not None:
			parent = self.resolve_style(parent_name)
		style = TextStyle(name, parent, params)
		self.resolved_styles[name] = style
		return style
示例#12
0
	def parse_google_sheet(self, google_elt: Element, block: CardBlock):
		params = self.parse_scheme(google_elt, google_scheme)
		try:
			def worker(process: TaskProcess):
				data = download_google_sheet_as_dictionary(params['key'], params['sheet'])
				return data
			@asyncify
			def run():
				data = yield run_threaded(f"Downloading {params['key']}/{params['sheet']}", worker)
				for row in data:
					self.add_card(block, row)
			self.pending_tasks.append(run())
		except BaseException as err:
			raise ValidateError(f"failed to download google spreadsheet: {err}")
示例#13
0
 def instantiate_deck(self, db: Deckbuilder, template: DeckTemplate):
     try:
         deck = db.make_deck(template.name,
                             (template.width, template.height))
         deck.scale = template.scale
         if template.back_default:
             deck.set_default_back(
                 self.build_face(deck, template.back_default))
         if template.face_hidden:
             deck.set_hidden_face(
                 self.build_face(deck, template.face_hidden))
         for card_block in template.card_blocks:
             for card in card_block.cards:
                 self.build_card(deck, card, card_block)
     except ValidateError as ve:
         raise ValidateError(
             f"while building deck '{encode(template.name)}': {ve}") from ve
示例#14
0
	def parse_deck(self, deck_elt: Element):
		params = self.parse_scheme(deck_elt, deck_scheme)
		name = params['name']
		if name in self.decks:
			raise ValidateError(f"duplicate deck '{name}'")
		deck = DeckTemplate(name, params['width'], params['height'])
		if 'scale' in params:
			deck.scale = params['scale']
		self.decks[name] = deck
		for elt in deck_elt:
			if elt.tag == "cards":
				self.process_element(elt, self.parse_cards, deck)
			elif elt.tag == "back-default":
				deck.back_default = self.process_element(elt, self.parse_template)
			elif elt.tag == "face-hidden":
				deck.face_hidden = self.process_element(elt, self.parse_template)
			else:
				raise self.unexpected_elt(elt)
示例#15
0
	def parse_image_set(self, imageset_elt: Element, block: CardBlock):
		params = self.parse_scheme(imageset_elt, imageset_scheme)
		try:
			path = params['path']
			def worker(process: TaskProcess):
				data = []
				base_path = self.resolve_path(path)
				for root, dirs, files in os.walk(base_path):
					for file in files:
						if file.endswith(".png") or file.endswith(".jpg") or file.endswith(".jpeg"):
							data.append({
								"path": os.path.abspath(os.path.join(root, file)),
								"filename": file,
								"name": os.path.splitext(file)[0]
							})
				return data
			@asyncify
			def run():
				data = yield run_threaded(f"Collecting images in {path}", worker)
				for row in data:
					self.add_card(block, row)
			self.pending_tasks.append(run())
		except BaseException as err:
			raise ValidateError(f"failed to load image  set: {err}")
示例#16
0
def parse_float(value):
    try:
        return float(value)
    except ValueError:
        raise ValidateError("expected number")
示例#17
0
def parse_int(value):
    try:
        return int(value)
    except ValueError:
        raise ValidateError("expected integer")
示例#18
0
def parse_name(value):
    if not re_style_name.match(value):
        raise ValidateError(
            "expected name (allowed characters are a-z, A-Z, 0-9, and '_', starts with a letter)"
        )
    return value
示例#19
0
 def execute(self, stmt: Stmt):
     self.fuel -= 1
     if self.fuel <= 0:
         raise ValidateError("evaluation took too many steps")
     try:
         if isinstance(stmt, StmtSequence):
             for child in stmt.stmts:
                 self.execute(child)
         elif isinstance(stmt, StmtDrawRect):
             self.get_face().draw_rect(
                 (
                     validators.parse_int(self.eval(stmt.x)),
                     validators.parse_int(self.eval(stmt.y)),
                     validators.parse_int(self.eval(stmt.width)),
                     validators.parse_int(self.eval(stmt.height)),
                 ),
                 self.eval_nullable(validators.parse_color, stmt.color,
                                    None),
                 self.eval_nullable(validators.parse_color, stmt.line_color,
                                    None),
                 self.eval_nullable(validators.parse_int, stmt.line_width,
                                    1))
         elif isinstance(stmt, StmtDrawText):
             self.get_face().draw_text(
                 (
                     validators.parse_int(self.eval(stmt.x)),
                     validators.parse_int(self.eval(stmt.y)),
                     validators.parse_int(self.eval(stmt.width)),
                     validators.parse_int(self.eval(stmt.height)),
                 ), self.ctx.resolve_style(self.eval(stmt.style)),
                 textparser.TextParser(self.ctx,
                                       self.eval(stmt.text)).parse())
         elif isinstance(stmt, StmtDrawImage):
             self.get_face().draw_image(
                 (validators.parse_int(self.eval(
                     stmt.x)), validators.parse_int(self.eval(stmt.y))),
                 self.ctx.resolve_path(self.eval(stmt.src)),
                 (self.eval_nullable(validators.parse_float, stmt.align_x,
                                     0),
                  self.eval_nullable(validators.parse_float, stmt.align_y,
                                     0)))
         elif isinstance(stmt, StmtFace):
             if self.face is not None:
                 raise ValidateError("face already selected")
             if not self.card:
                 raise ValidateError("no active card")
             self.face = self.card.front
             if not self.face:
                 self.face = self.card.deck.make_face()
                 self.card.set_front(self.face)
             self.execute(stmt.stmt)
             self.face = None
         elif isinstance(stmt, StmtForEach):
             var = stmt.var
             old_val = self.env.get(var, None)
             container = to_list(self.compute(stmt.in_expr))
             for elt in container:
                 self.env[var] = elt
                 self.execute(stmt.body)
             self.env[var] = old_val
         elif isinstance(stmt, StmtSetName):
             card = self.get_card()
             card.name = self.eval(stmt.value)
         elif isinstance(stmt, StmtSetDescription):
             card = self.get_card()
             card.description = self.eval(stmt.value)
         elif isinstance(stmt, StmtSetVar):
             var = stmt.var
             value = self.compute(stmt.value)
             self.env[var] = value
         elif isinstance(stmt, StmtIf):
             if to_number(self.compute(stmt.condition)):
                 self.execute(stmt.body)
         elif isinstance(stmt, StmtWhile):
             while to_number(self.compute(stmt.condition)):
                 self.execute(stmt.body)
         elif isinstance(stmt, StmtCase):
             for when in stmt.whens:
                 if to_number(self.compute(when.condition)):
                     self.execute(when.body)
                     break
             else:
                 if stmt.kelse is not None:
                     self.execute(stmt.kelse)
         elif isinstance(stmt, StmtFor):
             var = stmt.var
             old_val = self.env.get(var, None)
             kfrom = to_number(self.compute(stmt.kfrom))
             to = to_number(self.compute(stmt.kto))
             step = 1
             if stmt.step:
                 step = to_number(self.compute(stmt.step))
             value = kfrom
             if step == 0:
                 raise ValidateError("step is 0")
             while True:
                 if step > 0:
                     if value > to:
                         break
                 elif step < 0:
                     if value < to:
                         break
                 self.env[var] = value
                 self.execute(stmt.body)
                 value += step
             self.env[var] = old_val
         else:
             raise ValidateError("invalid statement")
     except ValidateError as ve:
         raise ValidateError(
             f"in line {stmt.location[0]}, col {stmt.location[1]}:\n{ve}"
         ) from ve
示例#20
0
def to_list(val):
    if not isinstance(val, list):
        raise ValidateError("expected list")
    return val
示例#21
0
 def get_face(self) -> CardFaceTemplate:
     if self.face is None:
         raise ValidateError("no card face selected")
     return self.face
示例#22
0
	def parse_inline(self, inline_elt: Element):
		params = self.parse_scheme(inline_elt, inline_scheme)
		name = params['name']
		if name in self.inlines:
			raise ValidateError(f"duplicate inline '{name}'")
		self.inlines[name] = InlineSymbol(params['name'], params['src'], params.get('offset-y', 0))
示例#23
0
 def resolve_inline(self, name: str) -> 'InlineSymbol':
     if name in self.inlines:
         return self.inlines[name]
     raise ValidateError(f"inline symbol '{encode(name)}' is not defined")
示例#24
0
 def get_card(self) -> CardTemplate:
     if self.card is None:
         raise ValidateError("no card selected")
     return self.card
示例#25
0
	def process_element(self, elt: Element, func: Callable[..., T], *args: Any, **kwargs: Any) -> T:
		try:
			return func(elt, *args, **kwargs)
		except ValidateError as ve:
			loc = self.getloc(elt)
			raise ValidateError(f"in <{encode(elt.tag)}> at line {loc[0]}, col {loc[1]}:\n{ve}") from ve
示例#26
0
 def resolve_style(self, name: str) -> 'TextStyle':
     if name in self.styles:
         return self.styles[name]
     raise ValidateError(f"text style '{encode(name)}' is not defined")
示例#27
0
	def unexpected_elt(self, elt: Element) -> NoReturn:
		loc = self.getloc(elt)
		raise ValidateError(f"unexpected child <{elt.tag}> at line {loc[0]}, col {loc[1]}")
示例#28
0
def to_int(val):
    try:
        return int(val)
    except ValueError:
        raise ValidateError("expected integer")
示例#29
0
def parse_color(value):
    if not re_color.match(value):
        raise ValidateError("invalid color (expected #RRGGBB or #AARRGGBB)")
    return value
示例#30
0
	def error(self, msg: str) -> NoReturn:
		raise ValidateError(f"at position {self.pos}: {msg}")