diff --git a/examples/test.vlp b/examples/test.vlp index 437a50d..d525def 100644 --- a/examples/test.vlp +++ b/examples/test.vlp @@ -1,21 +1,15 @@ -# a jungle of random tests +f = (x, [y, z]) => [&x..10, y..z] +a = f(0, [0, 10]) +[b, c] = a + +# functions +# :> f -# testing compound assignment operators -a = 3 -a += 2 -a /= 5 +# tuples +# :> [1 > 0, [1, 0.0], f, b, c] -b = 2.5 -b *= 4.0 -b -= a.5 # conversion +# iterators +# :> c :: i => [i, i.0, f, f(i-5, [0, 2])] -f = () => ~b # conversion - -c = [1.0, 2, [3.0, 4]] # tuples - -[d, _, e] = c # tuple decomposition - -g = (-2)..2 # ranges - -# printing various types, float precision -:> [b, 1 > 0, !(5 == ~5.0), [1.0, 2, [3.0, 4]], 1.0 / 3.0, f(), f, [f], g[1]] +# lists +:> b diff --git a/volpe/builder.py b/volpe/builder.py index 1d96f5e..037dfd7 100644 --- a/volpe/builder.py +++ b/volpe/builder.py @@ -113,6 +113,8 @@ def number_iter(self, tree: TypeTree): start = read_environment(b, args[0], env_types)[0] b.ret(b.add(start, args[1])) + # TODO going in reverse + env_ptr = write_environment(self.builder, [values[0]]) list_value = tree.return_type(ir.Undefined) list_value = self.builder.insert_value(list_value, self.builder.insert_value(closure, env_ptr, 3), 0) diff --git a/volpe/compile.py b/volpe/compile.py index 0c88623..b872d7c 100644 --- a/volpe/compile.py +++ b/volpe/compile.py @@ -4,7 +4,16 @@ # All these initializations are required for code generation! -from volpe_types import int1, int32, flt32, flt64, VolpeTuple, VolpeClosure +from volpe_types import ( + int1, + int32, + flt32, + flt64, + VolpeTuple, + VolpeClosure, + VolpeIterator, + VolpeList +) llvm.initialize() llvm.initialize_native_target() @@ -38,28 +47,91 @@ def compile_and_run(llvm_ir, result_type): def determine_c_type(volpe_type, depth=0): - # Interpret result type. + """Interpret the volpe type and return a corresponding C type.""" + # Simple types: + if volpe_type == int1: + return c_bool + if volpe_type == int32: + return c_int32 + if volpe_type == flt32: + return c_float + if volpe_type == flt64: + return c_double + + # Aggregate types: if isinstance(volpe_type, VolpeTuple): elems = volpe_type.elements class CTuple(Structure): _fields_ = [(f"elem{i}", determine_c_type(elem, depth+1)) for i, elem in enumerate(elems)] def __repr__(self): return "[" + ", ".join([str(getattr(self, tup[0])) for tup in self._fields_]) + "]" - return POINTER(CTuple) if depth == 0 else CTuple + + if isinstance(volpe_type, VolpeList): + element_type = determine_c_type(volpe_type.element_type, depth+1) + class CList(Structure): + _fields_ = [("elems", POINTER(element_type)), ("length", c_int32)] + def __repr__(self): + if depth == 0: + elems = getattr(self, "elems") + length = getattr(self, "length") + return "&<" + ", ".join([str(elem) for elem in elems[:length]]) + ">" + return get_type_name(volpe_type) + return POINTER(CList) if depth == 0 else CList + if isinstance(volpe_type, VolpeClosure): + elems = volpe_type.elements class CFunc(Structure): _fields_ = [("func", POINTER(None)), ("c_func", POINTER(None)), ("f_func", POINTER(None)), ("env", POINTER(None))] def __repr__(self): - return "*function*" + if depth == 0: + func = elems[0].pointee + input_type = ", ".join([get_type_name(i) for i in func.args[1:]]) + return_type = get_type_name(func.return_type) + return f"function ({input_type}) => {return_type}" + return get_type_name(volpe_type) return CFunc - elif volpe_type == int1: - return c_bool - elif volpe_type == int32: - return c_int32 - elif volpe_type == flt32: - return c_float - elif volpe_type == flt64: - return c_double - else: - return None + + if isinstance(volpe_type, VolpeIterator): + class CFunc(Structure): + _fields_ = [("func", POINTER(None)), ("c_func", POINTER(None)), ("f_func", POINTER(None)), ("env", POINTER(None))] + class CIterator(Structure): + _fields_ = [("func", CFunc), ("length", c_int32)] + def __repr__(self): + if depth == 0: + # TODO maybe include length? + func = volpe_type.elements[0].elements[0].pointee + return_type = get_type_name(func.return_type) + return f"iterator of {return_type}" + return get_type_name(volpe_type) + return CIterator + + # Unknown type + return None + + +def get_type_name(volpe_type): + """Get short Volpe names for types.""" + # Simple types: + if volpe_type == int1: + return "bool" + if volpe_type == int32: + return "int32" + if volpe_type == flt32: + return "flt32" + if volpe_type == flt64: + return "flt64" + + # Aggregate types: + if isinstance(volpe_type, VolpeTuple): + type_reprs = ", ".join([get_type_name(elem) for elem in volpe_type.elements]) + return f"[{type_reprs}]" + if isinstance(volpe_type, VolpeList): + return "*list*" + if isinstance(volpe_type, VolpeClosure): + return "*function*" + if isinstance(volpe_type, VolpeIterator): + return "*iterator*" + + # Unknown type + return None diff --git a/volpe/run_volpe.py b/volpe/run_volpe.py index 6bb37ba..6c9f1fb 100644 --- a/volpe/run_volpe.py +++ b/volpe/run_volpe.py @@ -10,7 +10,7 @@ from builder_utils import build_func from compile import compile_and_run from tree import TypeTree -from volpe_types import pint8, int32, VolpeTuple, target_data, VolpeClosure, copy_func, free_func +from volpe_types import pint8, int32, VolpeTuple, VolpeList, target_data, VolpeClosure, copy_func, free_func def volpe_llvm(tree: TypeTree, verbose=False, fast=False): @@ -55,17 +55,18 @@ def scope(name): b.ret_void() return_type = func_type.func.return_type - if isinstance(return_type, VolpeTuple): + if isinstance(return_type, (VolpeTuple, VolpeList)): return_type = return_type.as_pointer() main_func = ir.Function(module, ir.FunctionType(return_type, []), "main") with build_func(main_func) as (b, _): b: ir.IRBuilder res = b.call(func, [pint8(ir.Undefined)]) - if isinstance(res.type, VolpeTuple): + if isinstance(res.type, (VolpeTuple, VolpeList)): ptr = b.bitcast(b.call(module.malloc, [int32(res.type.get_abi_size(target_data))]), return_type) b.store(res, ptr) res = ptr + # TODO return list and vector as pointer b.ret(res) if verbose: