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