def gencode(self, env, opt): if opt.bp is None: g.r.addReport( m.Report('error', self.tok, 'break in unbreakable point')) return m.Insts() else: return m.Insts(m.Type(), [m.Inst(opc.JUMP, opt.bp)])
class Post_dec(AST): def __init__(self, tok, left): self.tok = tok self.left = left def gencode(self, env, opt): if (result := self.assertOnlyRValue(env, opt)) is not None: return result left = self.left.gencode(env, newopt(opt, 1, 'r')) codes = left.bytecodes typ = copy(left.typ) if (opt.popc == 1): codes.append(m.Inst(opc.DUP, self.nullarg)) else: typ = m.Type() if typ.isPointer(): codes.append(m.Inst(opc.DEC, env.calcPointeredSize(typ))) else: codes.append(m.Inst(opc.DEC, 1)) codes.extend(self.left.gencode(env, newopt(opt, 0, 'l')).bytecodes) return m.Insts(typ, codes)
def gencode(self, env, opt): if self.body: codes = self.body.gencode(env, newopt(opt, 1)).bytecodes else: codes = [m.Inst(opc.PUSH, 0)] codes.append(m.Inst(opc.RET, self.nullarg)) return m.Insts(m.Type(), codes)
def gencode(self, env, opt): env.pushScope() insts = [] for elem in self.body: insts.extend(elem.gencode(env, newopt(opt, 0)).bytecodes) env.popScope() return m.Insts(m.Type(), insts)
def gencode(self, env, opt): if opt.cp is None: g.r.addReport( m.Report( 'error', self.tok, 'to continue, you need extra gem! (you can\'t continue here.)' )) return m.Insts() else: return m.Insts(m.Type(), [m.Inst(opc.JUMP, opt.cp)])
def gencode(self, env, opt): cond = self.cond.gencode(env, newopt(opt, 1)).bytecodes then = self.then.gencode(env, newopt(opt, 0)).bytecodes l0 = env.issueLabel() codes = cond codes.append(m.Inst(opc.JIF0, l0)) codes.extend(then) codes.append(m.Inst(opc.LABEL, l0)) return m.Insts(m.Type(), codes)
class Cast(AST): def __init__(self, tok, targetType, body): self.tok = tok self.targetType = targetType self.body = body def gencode(self, env, opt): if (result := self.assertOnlyPop1(env, opt)) is not None: return result bodyc = self.body.gencode(env, newopt(opt, 1)) codes = bodyc.bytecodes if bodyc.typ.basetype == 'int': if self.targetType.basetype == 'float': codes.append(m.Inst(opc.ITOF, self.nullarg)) return m.Insts(m.Type('float'), codes) else: g.r.addReport( m.Report( 'fatal', self.tok, 'Program error occurred while evaluating \'Cast\' #0')) return m.Insts() elif bodyc.typ.basetype == 'float': if self.targetType.basetype == 'int': codes.append(m.Inst(opc.FTOI, self.nullarg)) return m.Insts(m.Type('int'), codes) else: g.r.addReport( m.Report( 'fatal', self.tok, 'Program error occurred while evaluating \'Cast\' #1')) return m.Insts() else: g.r.addReport( m.Report( 'fatal', self.tok, 'Program error occurred while evaluating \'Cast\' #2')) return m.Insts()
def gencode(self, env, opt): if isinstance(self.body, m.Type): return m.Insts(m.Type('int'), [m.Inst(opc.PUSH, env.calcTypeSize(self.body))]) elif isinstance(self.body, Symbol): try: var = env.variableLookup(self.body.symbolname) except m.SymbolNotFoundException as e: g.r.addReport( m.Report('fatal', self.tok, f"cannot eval size of type '{type(self.body)}'")) return m.Insts() return m.Insts(m.Type('int'), [m.Inst(opc.PUSH, env.calcTypeSize(var.typ))]) else: g.r.addReport( m.Report('fatal', self.tok, f"cannot eval size of type '{type(self.body)}'")) return m.Insts()
def gencode(self, env, opt): env.calcTypeSize(self.typ, self.init) var = env.addLocal(m.Symbol(self.symbolname, self.typ)) if self.init is None: return m.Insts() elif isinstance(self.init, list): codes = [] for i, elem in enumerate(self.init): codes.extend(elem.gencode(env, newopt(opt, 1)).bytecodes) codes.append(var.genAddrCode()) codes.append(m.Inst(opc.PUSH, i)) codes.append(m.Inst(opc.ADDI, self.nullarg)) codes.append(m.Inst(opc.STOREP, self.nullarg)) return m.Insts(m.Type(), codes) else: codes = self.init.gencode(env, newopt(opt, 1)).bytecodes codes.append(m.Inst(opc.STOREL, var.id)) return m.Insts(m.Type(), codes)
def gencode(self, env, opt): l0 = env.issueLabel() body = self.body.gencode(env, newopt(opt, cp=l0, bp=None)).bytecodes cond = self.cond.gencode(env, newopt(opt, 1)).bytecodes codes = [m.Inst(opc.LABEL, l0)] codes.extend(body) codes.extend(cond) codes.append(m.Inst(opc.INV, self.nullarg)) codes.append(m.Inst(opc.JIF0, l0)) return m.Insts(m.Type(), codes)
def gencode(self, env, opt): right = self.right.gencode(env, newopt(opt, 1)) left = self.left.gencode(env, newopt(opt, 1, 'l')) typ = m.Type() codes = right.bytecodes if opt.popc == 1: codes.append(m.Inst(opc.DUP, 1)) typ = right.typ codes.extend(left.bytecodes) return m.Insts(typ, codes)
def gencode(self, env, opt): tableCodes = self.cond.gencode(env, newopt(opt, 1)).bytecodes bodyCodes = [] end = env.issueLabel() default = None for elem in self.cases: label = env.issueLabel() if elem[0] == 'default': default = label bodyCodes.append(m.Inst(opc.LABEL, label)) for e in elem[1]: bodyCodes.extend( e.gencode(env, newopt(opt, 1, bp=end)).bytecodes) else: tableCodes.append(m.Inst(opc.DUP, 1)) tableCodes.extend(elem[0].gencode(env, newopt(opt, 1)).bytecodes) tableCodes.append(m.Inst(opc.NEQI, self.nullarg)) #TODO Int以外にも対応させる tableCodes.append(m.Inst(opc.JIF0, label)) bodyCodes.append(m.Inst(opc.LABEL, label)) for e in elem[1]: bodyCodes.extend( e.gencode(env, newopt(opt, 1, bp=end)).bytecodes) if default is not None: tableCodes.append(m.Inst(opc.JUMP, default)) else: tableCodes.append(m.Inst(opc.JUMP, end)) bodyCodes.append(m.Inst(opc.LABEL, end)) bodyCodes.append(m.Inst(opc.POP, self.nullarg)) codes = tableCodes codes.extend(bodyCodes) return m.Insts(m.Type(), codes)
def gencode(self, env, opt): l0 = env.issueLabel() l1 = env.issueLabel() if self.init is None: # TODO 1ライン化するか関数化して全部に適用 init = [] else: init = self.init.gencode(env, newopt(opt, 0)).bytecodes cond = self.cond.gencode(env, newopt(opt, 1)).bytecodes loop = self.loop.gencode(env, newopt(opt, 0)).bytecodes body = self.body.gencode(env, newopt(opt, 0, cp=l0, bp=l1)).bytecodes codes = init codes.append(m.Inst(opc.LABEL, l0)) codes.extend(cond) codes.append(m.Inst(opc.JIF0, l1)) codes.extend(body) codes.extend(loop) codes.append(m.Inst(opc.JUMP, l0)) codes.append(m.Inst(opc.LABEL, l1)) return m.Insts(m.Type(), codes)
class Symbol(AST): def __init__(self, tok, symbolname): self.tok = tok self.symbolname = symbolname def gencode(self, env, opt): try: var = env.variableLookup(self.symbolname) except m.SymbolNotFoundException as e: # 変数が見つからなかったら、Enumとして解決を試みる try: value = env.enumLookup(self.symbolname) except m.SymbolNotFoundException as e: g.r.addReport(m.Report('error', self.tok, f'{e} not found')) return m.Insts() if (result := self.assertOnlyRValue(env, opt)) is not None: return result if (result := self.assertOnlyPop1(env, opt)) is not None: return result return m.Insts(m.Type('int'), [m.Inst(opc.PUSH, value)])
def gencode(self, env, opt): for elem in self.body: dumps = elem.gencode(env, newopt(opt, 0)) env.addStatic(m.Symbol("__MAGIC_RETADDR__", m.Type(), 0)) env.addStatic(m.Symbol("__MAGIC_RETFP__", m.Type(), 0)) return env
def gencode(self, env, opt): env.addEnum(self.symbolname, self.typ) return m.Insts(m.Type(), [])
def gencode(self, env, opt): label = env.currentFuncName + self.name return m.Insts(m.Type(), [m.Inst(opc.JUMP, label)])
def projectAST(ast, s=0): if (ast is None): return None elif isinstance(ast, c_ast.ArrayDecl): return projectAST(ast.type, s).setLength(projectAST(ast.dim, s)) #MEMO dim_quals unused elif isinstance(ast, c_ast.ArrayRef): # [name*, subscript*] return node.Indirect( a2t(ast), node.Add(a2t(ast), projectAST(ast.name, s), projectAST(ast.subscript, s))) elif isinstance(ast, c_ast.Assignment): # [op, lvalue*, rvalue*] if ast.op == '=': return node.Assign(a2t(ast), projectAST(ast.lvalue, s), projectAST(ast.rvalue, s)) elif ast.op == '+=': return node.Assign( a2t(ast), projectAST(ast.lvalue, s), node.Add(a2t(ast), projectAST(ast.lvalue, s), projectAST(ast.rvalue, s))) elif ast.op == '-=': return node.Assign( a2t(ast), projectAST(ast.lvalue, s), node.Sub(a2t(ast), projectAST(ast.lvalue, s), projectAST(ast.rvalue, s))) elif ast.op == '*=': return node.Assign( a2t(ast), projectAST(ast.lvalue, s), node.Mul(a2t(ast), projectAST(ast.lvalue, s), projectAST(ast.rvalue, s))) elif ast.op == '/=': return node.Assign( a2t(ast), projectAST(ast.lvalue, s), node.Div(a2t(ast), projectAST(ast.lvalue, s), projectAST(ast.rvalue, s))) elif ast.op == '%=': return node.Assign( a2t(ast), projectAST(ast.lvalue, s), node.Mod(a2t(ast), projectAST(ast.lvalue, s), projectAST(ast.rvalue, s))) elif ast.op == '<<=': return node.Assign( a2t(ast), projectAST(ast.lvalue, s), node.LShift(a2t(ast), projectAST(ast.lvalue, s), projectAST(ast.rvalue, s))) elif ast.op == '>>=': return node.Assign( a2t(ast), projectAST(ast.lvalue, s), node.RShift(a2t(ast), projectAST(ast.lvalue, s), projectAST(ast.rvalue, s))) elif ast.op == '&=': return node.Assign( a2t(ast), projectAST(ast.lvalue, s), node.And(a2t(ast), projectAST(ast.lvalue, s), projectAST(ast.rvalue, s))) elif ast.op == '|=': return node.Assign( a2t(ast), projectAST(ast.lvalue, s), node.Or(a2t(ast), projectAST(ast.lvalue, s), projectAST(ast.rvalue, s))) elif ast.op == '^=': return node.Assign( a2t(ast), projectAST(ast.lvalue, s), node.Xor(a2t(ast), projectAST(ast.lvalue, s), projectAST(ast.rvalue, s))) else: g.r.addReport( m.Report('fatal', a2t(ast), f"unsupported assignment op '{ast.op}'")) return elif isinstance(ast, c_ast.BinaryOp): # [op, left* right*] if ast.op == '+': return node.Add(a2t(ast), projectAST(ast.left, s), projectAST(ast.right, s)) elif ast.op == '-': return node.Sub(a2t(ast), projectAST(ast.left, s), projectAST(ast.right, s)) elif ast.op == '*': return node.Mul(a2t(ast), projectAST(ast.left, s), projectAST(ast.right, s)) elif ast.op == '/': return node.Div(a2t(ast), projectAST(ast.left, s), projectAST(ast.right, s)) elif ast.op == '%': return node.Mod(a2t(ast), projectAST(ast.left, s), projectAST(ast.right, s)) elif ast.op == '<<': return node.LShift(a2t(ast), projectAST(ast.left, s), projectAST(ast.right, s)) elif ast.op == '>>': return node.RShift(a2t(ast), projectAST(ast.left, s), projectAST(ast.right, s)) elif ast.op == '&': return node.And(a2t(ast), projectAST(ast.left, s), projectAST(ast.right, s)) elif ast.op == '|': return node.Or(a2t(ast), projectAST(ast.left, s), projectAST(ast.right, s)) elif ast.op == '^': return node.Xor(a2t(ast), projectAST(ast.left, s), projectAST(ast.right, s)) elif ast.op == '<': return node.Lt(a2t(ast), projectAST(ast.left, s), projectAST(ast.right, s)) elif ast.op == '<=': return node.Lte(a2t(ast), projectAST(ast.left, s), projectAST(ast.right, s)) elif ast.op == '>': return node.Gt(a2t(ast), projectAST(ast.left, s), projectAST(ast.right, s)) elif ast.op == '>=': return node.Gte(a2t(ast), projectAST(ast.left, s), projectAST(ast.right, s)) elif ast.op == '==': return node.Eq(a2t(ast), projectAST(ast.left, s), projectAST(ast.right, s)) elif ast.op == '!=': return node.Neq(a2t(ast), projectAST(ast.left, s), projectAST(ast.right, s)) elif ast.op == '&&': return node.And(a2t(ast), projectAST(ast.left, s), projectAST(ast.right, s)) elif ast.op == '||': return node.Or(a2t(ast), projectAST(ast.left, s), projectAST(ast.right, s)) else: g.r.addReport( m.Report('fatal', a2t(ast), f"unsupported binary op '{ast.op}'")) return elif isinstance(ast, c_ast.Break): # [] return node.Break(a2t(ast)) elif isinstance(ast, c_ast.Case): # [expr*, stmts**] return [ projectAST(ast.expr, s), [projectAST(e, s + 1) for e in ast.stmts] ] elif isinstance(ast, c_ast.Cast): # [to_type*, expr*] return node.Cast(a2t(ast), projectAST(ast.to_type, s), projectAST(ast.expr, s)) elif isinstance(ast, c_ast.Compound): # [block_items**] if ast.block_items is None: return node.Block(a2t(ast), []) else: return node.Block(a2t(ast), [projectAST(e, s + 1) for e in ast.block_items]) elif isinstance(ast, c_ast.CompoundLiteral): #TODO [type*, init*] pass elif isinstance(ast, c_ast.Constant): # [type, value] if (ast.type == 'int'): return node.NumberI(a2t(ast), ast.value) elif (ast.type == 'float'): return node.NumberF(a2t(ast), ast.value) elif (ast.type == 'char'): ast.value = escapeString(ast.value) return node.NumberI( a2t(ast), int.from_bytes(ast.value[1].encode('utf-32be'), byteorder='big')) elif (ast.type == 'string'): ast.value = escapeString(ast.value) return node.String(a2t(ast), ast.value[1:-1]) g.r.addReport( m.Report( 'fatal', a2t(ast), f"unsupported constant type '{ast.type}' for value '{ast.value}'" )) elif isinstance(ast, c_ast.Continue): # [] return node.Continue(a2t(ast)) elif isinstance( ast, c_ast.Decl ): # [name, quals, storage, funcspec, type*, init*, bitsize*] if type(ast.type) in (c_ast.TypeDecl, c_ast.PtrDecl, c_ast.ArrayDecl): init = projectAST(ast.init, s) if isinstance(init, node.String): # 初期化がstirngだった場合、リストに展開 string = init.eval() li = list( map( lambda a: node.NumberI( a2t(ast), int.from_bytes(a.encode('utf-32be'), byteorder='big')), string)) li.append(node.NumberI(a2t(ast), 0)) init = li if (s == 0): return node.GlobalVar(a2t(ast), ast.name, projectAST(ast.type, s), init) else: return node.LocalVar(a2t(ast), ast.name, projectAST(ast.type, s), init) elif isinstance(ast.type, c_ast.FuncDecl): # 関数定義 decl = projectAST(ast.type, s) return node.Func(a2t(ast), decl['type'].name, decl['type'], decl['args'], None) else: return projectAST(ast.type, s) elif isinstance(ast, c_ast.DeclList): #TODO [decls**] pass elif isinstance(ast, c_ast.Default): # [stmts**] return ['default', [projectAST(e, s + 1) for e in ast.stmts]] elif isinstance(ast, c_ast.DoWhile): # [cond*, stmt*] return node.DoWhile(a2t(ast), projectAST(ast.stmt, s), projectAST(ast.cond, s)) elif isinstance(ast, c_ast.EllipsisParam): #TODO [] pass elif isinstance(ast, c_ast.EmptyStatement): #TODO [] pass elif isinstance(ast, c_ast.Enum): # [name, values*] if ast.values is None: # is type define return m.Type(ast.name).setHint('enum') else: # is enum define return node.Enum(a2t(ast), ast.name, projectAST(ast.values, s)) elif isinstance(ast, c_ast.Enumerator): # [name, value*] if ast.value is None: return (ast.name, None) else: if isinstance(ast.value, c_ast.Constant): return (ast.name, int(ast.value.value)) elif isinstance(ast.value, c_ast.UnaryOp): return (ast.name, -int(ast.value.expr.value)) else: g.r.addReport( m.Report('fatal', a2t(ast), f"enum must be \'int\'")) elif isinstance(ast, c_ast.EnumeratorList): # [enumerators**] itr = 0 typ = m.Type('enum') for elem in ast.enumerators: tmp = projectAST(elem, s) if tmp[1] is None: typ.addMember((tmp[0], itr)) itr += 1 else: typ.addMember(tmp) itr = tmp[1] + 1 return typ elif isinstance(ast, c_ast.ExprList): #[exprs**] return [projectAST(e, s) for e in ast.exprs] elif isinstance(ast, c_ast.FileAST): return node.Program(a2t(ast), [projectAST(e, s) for e in ast.ext]) elif isinstance(ast, c_ast.For): # [init*, cond*, next*, stmt*] return node.For(a2t(ast), projectAST(ast.init, s), projectAST(ast.cond, s), projectAST(ast.next, s), projectAST(ast.stmt, s)) elif isinstance(ast, c_ast.FuncCall): # [name*, args*] return node.Funccall(a2t(ast), ast.name.name, projectAST(ast.args, s)) elif isinstance(ast, c_ast.FuncDecl): # [args*, type*] return { "args": projectAST(ast.args, s) if ast.args is not None else [], "type": projectAST(ast.type, s) } elif isinstance(ast, c_ast.FuncDef): # [args*, type*] return projectAST(ast.decl, s).setBody(projectAST(ast.body, s)) elif isinstance(ast, c_ast.Goto): # [name] return node.Goto(a2t(ast), ast.name) elif isinstance(ast, c_ast.ID): # [name] return node.Symbol(a2t(ast), ast.name) elif isinstance(ast, c_ast.IdentifierType): if len(ast.names) == 1: return m.Type(ast.names[0]) g.r.addReport( m.Report('fatal', a2t(ast), f"program error while processing IdentifierType")) elif isinstance(ast, c_ast.If): # [cond*, iftrue*, iffalse*] if ast.iffalse is None: return node.If(a2t(ast), projectAST(ast.cond, s), projectAST(ast.iftrue, s)) else: return node.Ifelse(a2t(ast), projectAST(ast.cond, s), projectAST(ast.iftrue, s), projectAST(ast.iffalse, s)) elif isinstance(ast, c_ast.InitList): # [exprs**] return [projectAST(e, s) for e in ast.exprs] #XXX elif isinstance(ast, c_ast.Label): # [name, stmt*] return node.Label(a2t(ast), ast.name, projectAST(ast.stmt)) elif isinstance(ast, c_ast.NamedInitializer): #TODO [name**, expr*] pass elif isinstance(ast, c_ast.ParamList): # [params**] tmp = [] for elem in ast.params: typ = projectAST(elem.type, s) tmp.append(m.Symbol(typ.name, typ)) return tmp elif isinstance(ast, c_ast.PtrDecl): return projectAST(ast.type, s).addQuals(ast.quals).addRefcount(1) elif isinstance(ast, c_ast.Raw): # [type*, opc, arg, exprs**] return node.Raw(a2t(ast), projectAST(ast.type, s), ast.opc[1:-1], int(ast.arg.value), [projectAST(e, s) for e in ast.exprs]) elif isinstance(ast, c_ast.Return): # [expr*] return node.Return(a2t(ast), projectAST(ast.expr, s)) elif isinstance(ast, c_ast.Struct): # [name, decls**] if ast.decls is None: return m.Type(ast.name).setHint('struct') else: typ = m.Type('struct') for elem in ast.decls: typ.addMember((elem.name, projectAST(elem.type))) return node.Struct(a2t(ast), ast.name, typ) elif isinstance(ast, c_ast.StructRef): # [name*, type, filed*] type unused if ast.type == '.': return node.Indirect( a2t(ast), node.FieldAccess( a2t(ast), node.Address(a2t(ast), projectAST(ast.name, s)), ast.field.name)) elif ast.type == '->': return node.Indirect( a2t(ast), node.FieldAccess(a2t(ast), projectAST(ast.name, s), ast.field.name)) else: g.r.addReport( m.Report('fatal', a2t(ast), f"unsupported field access type '{ast.type}'")) elif isinstance(ast, c_ast.Switch): # [cond*, stmt*] return node.Switch(a2t(ast), projectAST( ast.cond, s), [projectAST(e, s + 1) for e in ast.stmt.block_items]) elif isinstance(ast, c_ast.TernaryOp): # [cond*, ifture*, iffalse*] return node.Ternary(a2t(ast), projectAST(ast.cond, s), projectAST(ast.iftrue, s), projectAST(ast.iffalse, s)) elif isinstance(ast, c_ast.TypeDecl): typ = projectAST(ast.type, s) if isinstance(typ, m.Type): return typ.addQuals(ast.quals).setName(ast.declname) elif type(typ) in (node.Struct, node.Enum): return typ.typ else: return typ elif isinstance(ast, c_ast.Typedef): # [name, quals, storage, type*] typ = projectAST(ast.type, s) if isinstance(typ, node.Struct) or isinstance(typ, node.Enum): return node.Typedef(a2t(ast), ast.name, typ.typ.addQuals(ast.quals)) else: return node.Typedef(a2t(ast), ast.name, typ.addQuals(ast.quals)) elif isinstance(ast, c_ast.Typename): # [name, quals, type*] return projectAST(ast.type, s).addQuals(ast.quals) elif isinstance(ast, c_ast.UnaryOp): # [op, expr*] if ast.op == '!': return node.Inv(a2t(ast), projectAST(ast.expr, s)) elif ast.op == '+': return projectAST(ast.expr, s) elif ast.op == '-': return node.Minus(a2t(ast), projectAST(ast.expr, s)) elif ast.op == '++': return node.Pre_inc(a2t(ast), projectAST(ast.expr, s)) elif ast.op == '--': return node.Pre_dec(a2t(ast), projectAST(ast.expr, s)) elif ast.op == 'p++': return node.Post_inc(a2t(ast), projectAST(ast.expr, s)) elif ast.op == 'p--': return node.Post_dec(a2t(ast), projectAST(ast.expr, s)) elif ast.op == '*': return node.Indirect(a2t(ast), projectAST(ast.expr, s)) elif ast.op == '&': return node.Address(a2t(ast), projectAST(ast.expr, s)) elif ast.op == 'sizeof': return node.Sizeof(a2t(ast), projectAST(ast.expr, s)) else: g.r.addReport( m.Report('fatal', a2t(ast), f"unsupported unary op '{ast.op}'")) return elif isinstance(ast, c_ast.Union): #TODO [name, decls**] pass elif isinstance(ast, c_ast.While): # [cond*, stmt*] return node.While(a2t(ast), projectAST(ast.cond, s), projectAST(ast.stmt, s)) elif isinstance(ast, c_ast.Pragma): #TODO [string] pass else: g.r.addReport( m.Report('fatal', a2t(ast), f"{type(ast)} is not listed!")) return g.r.addReport( m.Report('fatal', a2t(ast), f"{type(ast)} is not yet implemented!"))
if (result := self.assertOnlyRValue(env, opt)) is not None: return result if (result := self.assertOnlyPop1(env, opt)) is not None: return result left = self.left.gencode(env, newopt(opt, 1)) right = self.right.gencode(env, newopt(opt, 1)) code = right.bytecodes code.extend(left.bytecodes) if self.isCompOP: # 比較演算子ならポインタ同士の演算が可能 if left.typ.isPointer() or right.typ.isPointer(): code.append(m.Inst(self.opI, self.nullarg)) return m.Insts(m.Type('int'), code) else: # そうでないならスカラーしか演算できない if not (left.typ.isScalar() and right.typ.isScalar()): g.r.addReport( m.Report( 'error', self.tok, f"invalid operands to binary expression('{left.typ}' and '{right.typ}')" )) return m.Insts() if (not left.typ.isBasetype()): left.typ = env.getType(left.typ.basetype) if (not right.typ.isBasetype()): right.typ = env.getType(right.typ.basetype)