forked from M-Labs/artiq
Add support for string literals.
This commit is contained in:
parent
64d2604aa8
commit
49ece6a12a
|
@ -50,6 +50,10 @@ class TFloat(types.TMono):
|
|||
def one():
|
||||
return 1.0
|
||||
|
||||
class TStr(types.TMono):
|
||||
def __init__(self):
|
||||
super().__init__("str")
|
||||
|
||||
class TList(types.TMono):
|
||||
def __init__(self, elt=None):
|
||||
if elt is None:
|
||||
|
@ -88,6 +92,9 @@ def fn_int():
|
|||
def fn_float():
|
||||
return types.TConstructor("float")
|
||||
|
||||
def fn_str():
|
||||
return types.TConstructor("str")
|
||||
|
||||
def fn_list():
|
||||
return types.TConstructor("list")
|
||||
|
||||
|
@ -133,6 +140,9 @@ def get_int_width(typ):
|
|||
def is_float(typ):
|
||||
return types.is_mono(typ, "float")
|
||||
|
||||
def is_str(typ):
|
||||
return types.is_mono(typ, "str")
|
||||
|
||||
def is_numeric(typ):
|
||||
typ = typ.find()
|
||||
return isinstance(typ, types.TMono) and \
|
||||
|
@ -167,6 +177,6 @@ def is_collection(typ):
|
|||
return isinstance(typ, types.TTuple) or \
|
||||
types.is_mono(typ, "list")
|
||||
|
||||
def is_mutable(typ):
|
||||
def is_allocated(typ):
|
||||
return typ.fold(False, lambda accum, typ:
|
||||
is_list(typ) or types.is_function(typ))
|
||||
is_list(typ) or is_str(typ) or types.is_function(typ))
|
||||
|
|
|
@ -565,6 +565,9 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
|||
def visit_NumT(self, node):
|
||||
return ir.Constant(node.n, node.type)
|
||||
|
||||
def visit_StrT(self, node):
|
||||
return ir.Constant(node.s, node.type)
|
||||
|
||||
def visit_NameConstantT(self, node):
|
||||
return ir.Constant(node.value, node.type)
|
||||
|
||||
|
@ -1038,7 +1041,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
|||
return result
|
||||
|
||||
def _compare_pair_identity(self, op, lhs, rhs):
|
||||
if builtins.is_mutable(lhs) and builtins.is_mutable(rhs):
|
||||
if builtins.is_allocated(lhs) and builtins.is_allocated(rhs):
|
||||
# These are actually pointers, compare directly.
|
||||
return self.append(ir.Compare(op, lhs, rhs))
|
||||
else:
|
||||
|
|
|
@ -252,6 +252,11 @@ class ASTTypedRewriter(algorithm.Transformer):
|
|||
return asttyped.NumT(type=typ,
|
||||
n=node.n, loc=node.loc)
|
||||
|
||||
def visit_Str(self, node):
|
||||
return asttyped.StrT(type=builtins.TStr(),
|
||||
s=node.s,
|
||||
begin_loc=node.begin_loc, end_loc=node.end_loc, loc=node.loc)
|
||||
|
||||
def visit_Name(self, node):
|
||||
return asttyped.NameT(type=self._find_name(node.id, node.loc),
|
||||
id=node.id, ctx=node.ctx, loc=node.loc)
|
||||
|
@ -411,7 +416,6 @@ class ASTTypedRewriter(algorithm.Transformer):
|
|||
visit_GeneratorExp = visit_unsupported
|
||||
visit_Set = visit_unsupported
|
||||
visit_SetComp = visit_unsupported
|
||||
visit_Str = visit_unsupported
|
||||
visit_Starred = visit_unsupported
|
||||
visit_Yield = visit_unsupported
|
||||
visit_YieldFrom = visit_unsupported
|
||||
|
|
|
@ -18,7 +18,7 @@ class LLVMIRGenerator:
|
|||
|
||||
def llty_of_type(self, typ, bare=False, for_return=False):
|
||||
if types.is_tuple(typ):
|
||||
return ll.LiteralStructType([self.llty_of_type(eltty) for eltty in typ.elts])
|
||||
return ll.LiteralStructType([self.llty_of_type(eltty) for eltty in typ.find().elts])
|
||||
elif types.is_function(typ):
|
||||
envarg = ll.IntType(8).as_pointer()
|
||||
llty = ll.FunctionType(args=[envarg] +
|
||||
|
@ -42,6 +42,8 @@ class LLVMIRGenerator:
|
|||
return ll.IntType(builtins.get_int_width(typ))
|
||||
elif builtins.is_float(typ):
|
||||
return ll.DoubleType()
|
||||
elif builtins.is_str(typ):
|
||||
return ll.IntType(8).as_pointer()
|
||||
elif builtins.is_list(typ):
|
||||
lleltty = self.llty_of_type(builtins.get_iterable_elt(typ))
|
||||
return ll.LiteralStructType([ll.IntType(32), lleltty.as_pointer()])
|
||||
|
@ -75,6 +77,14 @@ class LLVMIRGenerator:
|
|||
return ll.Constant(llty, False)
|
||||
elif isinstance(const.value, (int, float)):
|
||||
return ll.Constant(llty, const.value)
|
||||
elif isinstance(const.value, str):
|
||||
as_bytes = const.value.encode('utf-8')
|
||||
llstrty = ll.ArrayType(ll.IntType(8), len(as_bytes))
|
||||
llconst = ll.GlobalVariable(self.llmodule, llstrty,
|
||||
name=self.llmodule.get_unique_name("str"))
|
||||
llconst.global_constant = True
|
||||
llconst.initializer = ll.Constant(llstrty, bytearray(as_bytes))
|
||||
return llconst.bitcast(ll.IntType(8).as_pointer())
|
||||
else:
|
||||
assert False
|
||||
|
||||
|
@ -157,7 +167,7 @@ class LLVMIRGenerator:
|
|||
size=llsize)
|
||||
llvalue = self.llbuilder.insert_value(llvalue, llalloc, 1, name=insn.name)
|
||||
return llvalue
|
||||
elif builtins.is_mutable(insn.type):
|
||||
elif builtins.is_allocated(insn.type):
|
||||
assert False
|
||||
else: # immutable
|
||||
llvalue = ll.Constant(self.llty_of_type(insn.type), ll.Undefined)
|
||||
|
@ -203,7 +213,7 @@ class LLVMIRGenerator:
|
|||
if types.is_tuple(insn.object().type):
|
||||
return self.llbuilder.extract_value(self.map(insn.object()), self.attr_index(insn),
|
||||
name=insn.name)
|
||||
elif not builtins.is_mutable(insn.object().type):
|
||||
elif not builtins.is_allocated(insn.object().type):
|
||||
return self.llbuilder.extract_value(self.map(insn.object()), self.attr_index(insn),
|
||||
name=insn.name)
|
||||
else:
|
||||
|
@ -213,7 +223,7 @@ class LLVMIRGenerator:
|
|||
return self.llbuilder.load(llptr)
|
||||
|
||||
def process_SetAttr(self, insn):
|
||||
assert builtins.is_mutable(insns.object().type)
|
||||
assert builtins.is_allocated(insns.object().type)
|
||||
llptr = self.llbuilder.gep(self.map(insn.object()),
|
||||
[self.llindex(0), self.llindex(self.attr_index(insn))],
|
||||
name=insn.name)
|
||||
|
|
|
@ -78,7 +78,7 @@ class RegionOf(algorithm.Visitor):
|
|||
# Value lives as long as the current scope, if it's mutable,
|
||||
# or else forever
|
||||
def visit_BinOpT(self, node):
|
||||
if builtins.is_mutable(node.type):
|
||||
if builtins.is_allocated(node.type):
|
||||
return self.youngest_region
|
||||
else:
|
||||
return None
|
||||
|
@ -86,7 +86,7 @@ class RegionOf(algorithm.Visitor):
|
|||
# Value lives as long as the object/container, if it's mutable,
|
||||
# or else forever
|
||||
def visit_accessor(self, node):
|
||||
if builtins.is_mutable(node.type):
|
||||
if builtins.is_allocated(node.type):
|
||||
return self.visit(node.value)
|
||||
else:
|
||||
return None
|
||||
|
@ -125,20 +125,23 @@ class RegionOf(algorithm.Visitor):
|
|||
visit_ListCompT = visit_allocating
|
||||
visit_SetT = visit_allocating
|
||||
visit_SetCompT = visit_allocating
|
||||
visit_StrT = visit_allocating
|
||||
|
||||
# Value lives forever
|
||||
def visit_immutable(self, node):
|
||||
assert not builtins.is_mutable(node.type)
|
||||
assert not builtins.is_allocated(node.type)
|
||||
return None
|
||||
|
||||
visit_CompareT = visit_immutable
|
||||
visit_EllipsisT = visit_immutable
|
||||
visit_NameConstantT = visit_immutable
|
||||
visit_NumT = visit_immutable
|
||||
visit_EllipsisT = visit_immutable
|
||||
visit_UnaryOpT = visit_immutable
|
||||
visit_CompareT = visit_immutable
|
||||
visit_CallT = visit_immutable
|
||||
|
||||
# Value is mutable, but still lives forever
|
||||
def visit_StrT(self, node):
|
||||
return None
|
||||
|
||||
# Not implemented
|
||||
def visit_unimplemented(self, node):
|
||||
assert False
|
||||
|
@ -212,7 +215,7 @@ class EscapeValidator(algorithm.Visitor):
|
|||
self.youngest_env = {}
|
||||
|
||||
for name in node.typing_env:
|
||||
if builtins.is_mutable(node.typing_env[name]):
|
||||
if builtins.is_allocated(node.typing_env[name]):
|
||||
self.youngest_env[name] = Region(None) # not yet known
|
||||
else:
|
||||
self.youngest_env[name] = None # lives forever
|
||||
|
@ -277,7 +280,7 @@ class EscapeValidator(algorithm.Visitor):
|
|||
self.visit_assignment(target, node.value)
|
||||
|
||||
def visit_AugAssign(self, node):
|
||||
if builtins.is_mutable(node.target.type):
|
||||
if builtins.is_allocated(node.target.type):
|
||||
# If the target is mutable, op-assignment will allocate
|
||||
# in the youngest region.
|
||||
self.visit_assignment(node.target, node.value, is_aug_assign=True)
|
||||
|
@ -295,7 +298,7 @@ class EscapeValidator(algorithm.Visitor):
|
|||
self.engine.process(diag)
|
||||
|
||||
def visit_Raise(self, node):
|
||||
if builtins.is_mutable(node.exc.type):
|
||||
if builtins.is_allocated(node.exc.type):
|
||||
note = diagnostic.Diagnostic("note",
|
||||
"this expression has type {type}",
|
||||
{"type": types.TypePrinter().name(node.exc.type)},
|
||||
|
|
|
@ -54,3 +54,5 @@ not 1
|
|||
lambda x, y=1: x
|
||||
# CHECK-L: lambda x:'k, y:int(width='l)=1:int(width='l): x:'k:(x:'k, ?y:int(width='l))->'k
|
||||
|
||||
k = "x"
|
||||
# CHECK-L: k:str
|
||||
|
|
Loading…
Reference in New Issue