forked from M-Labs/artiq
1
0
Fork 0

Add support for string literals.

This commit is contained in:
whitequark 2015-07-21 14:27:48 +03:00
parent 64d2604aa8
commit 49ece6a12a
6 changed files with 49 additions and 17 deletions

View File

@ -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))

View File

@ -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:

View File

@ -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

View File

@ -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)

View File

@ -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)},

View File

@ -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