Example #1
0
    def test_recursive_cons(self):
        a = cons(1, 2, 3, recursive=True)

        self.assertTrue(a.is_proper())
        self.assertTrue(a.is_recursive())

        self.assertTrue(is_pair(a))
        self.assertTrue(is_proper(a))

        self.assertEqual(a.length(), 3)

        self.assertEqual(car(a), car(cdr(cdr(cdr(a)))))

        self.assertEqual(str(a), "(1 2 3 ...)")
        self.assertEqual(repr(a), "cons(1, 2, 3, recursive=True)")

        b = pair(0, a)
        c = pair(0, a)
        self.assertEqual(b, c)
        self.assertNotEqual(a, b)
        self.assertNotEqual(a, c)

        z = cons(1, cons(2, cons(3, nil)))
        setcdr(cdr(cdr(z)), z)

        self.assertEqual(a, z)
        self.assertEqual(z, a)
Example #2
0
    def test_nil(self):
        # singleton nil check
        Nil = type(nil)

        self.assertEqual(id(nil), id(Nil()))
        self.assertEqual(id(Nil()), id(Nil()))
        self.assertTrue(nil is Nil())

        # behavior
        self.assertIsInstance(nil, pair)
        self.assertTrue(is_pair(nil))
        self.assertTrue(is_nil(nil))
        self.assertTrue(is_proper(nil))
        self.assertFalse(nil)
        self.assertTrue(not nil)
        self.assertEqual(str(nil), "nil")
        self.assertEqual(repr(nil), "nil")

        self.assertEqual(nil, nil)
        self.assertNotEqual(nil, cons(1, nil))
        self.assertNotEqual(cons(1, nil), nil)

        with self.assertRaises(TypeError):
            car(nil)

        with self.assertRaises(TypeError):
            cdr(nil)

        self.assertEqual(list(nil), list())
        self.assertEqual(tuple(nil), tuple())
Example #3
0
    def test_recursive_cons(self):
        a = cons(1, 2, 3, recursive=True)

        self.assertTrue(a.is_proper())
        self.assertTrue(a.is_recursive())

        self.assertTrue(is_pair(a))
        self.assertTrue(is_proper(a))

        self.assertEqual(a.length(), 3)

        self.assertEqual(car(a), car(cdr(cdr(cdr(a)))))

        self.assertEqual(str(a), "(1 2 3 ...)")
        self.assertEqual(repr(a), "cons(1, 2, 3, recursive=True)")

        b = pair(0, a)
        c = pair(0, a)
        self.assertEqual(b, c)
        self.assertNotEqual(a, b)
        self.assertNotEqual(a, c)

        z = cons(1, cons(2, cons(3, nil)))
        setcdr(cdr(cdr(z)), z)

        self.assertEqual(a, z)
        self.assertEqual(z, a)
Example #4
0
    def test_nil(self):
        # singleton nil check
        Nil = type(nil)

        self.assertEqual(id(nil), id(Nil()))
        self.assertEqual(id(Nil()), id(Nil()))
        self.assertTrue(nil is Nil())

        # behavior
        self.assertIsInstance(nil, pair)
        self.assertTrue(is_pair(nil))
        self.assertTrue(is_nil(nil))
        self.assertTrue(is_proper(nil))
        self.assertFalse(nil)
        self.assertTrue(not nil)
        self.assertEqual(str(nil), "nil")
        self.assertEqual(repr(nil), "nil")

        self.assertEqual(nil, nil)
        self.assertNotEqual(nil, cons(1, nil))
        self.assertNotEqual(cons(1, nil), nil)

        with self.assertRaises(TypeError):
            car(nil)

        with self.assertRaises(TypeError):
            cdr(nil)

        self.assertEqual(list(nil), list())
        self.assertEqual(tuple(nil), tuple())
Example #5
0
    def test_improper_cons(self):
        z = cons(1, 2)
        self.assertEqual(z.length(), 2)
        self.assertFalse(z.is_proper())
        self.assertEqual(car(z), 1)
        self.assertEqual(cdr(z), 2)
        self.assertEqual(str(z), "(1 . 2)")
        self.assertEqual(repr(z), "cons(1, 2)")

        self.assertTrue(is_pair(z))
        self.assertFalse(is_proper(z))

        self.assertNotEqual(z, None)
        self.assertNotEqual(z, nil)
        self.assertNotEqual(z, cons(1, nil))
        self.assertNotEqual(z, cons(1, 3))
        self.assertNotEqual(z, cons(1, 3, nil))
Example #6
0
    def test_improper_cons(self):
        z = cons(1, 2)
        self.assertEqual(z.length(), 2)
        self.assertFalse(z.is_proper())
        self.assertEqual(car(z), 1)
        self.assertEqual(cdr(z), 2)
        self.assertEqual(str(z), "(1 . 2)")
        self.assertEqual(repr(z), "cons(1, 2)")

        self.assertTrue(is_pair(z))
        self.assertFalse(is_proper(z))

        self.assertNotEqual(z, None)
        self.assertNotEqual(z, nil)
        self.assertNotEqual(z, cons(1, nil))
        self.assertNotEqual(z, cons(1, 3))
        self.assertNotEqual(z, cons(1, 3, nil))
Example #7
0
    def find_expander(self, source_obj, env=None):
        """
        Find an expander function for the given source obj in the
        specified environment.
        """

        env = self.env if env is None else env
        if not isinstance(env, Mapping):
            env = vars(env)

        expander = None

        if source_obj is nil:
            return None

        elif is_symbol(source_obj):
            namesym = source_obj
            found = self.find_compiled(namesym, env)
            if is_alias(found):
                expander = found.expand

        elif is_proper(source_obj):
            namesym, params = source_obj

            if is_symbol(namesym):
                found = self.find_compiled(namesym, env)
                if is_alias(found):

                    def expander():
                        expanded = cons(found.expand(), params)
                        expanded.set_position(source_obj.get_position())
                        return expanded

                elif is_macro(found):
                    if found._proper:
                        # FIXME: this is some garbage right here. we need
                        # to make sure macros aren't being invoked this
                        # way with a variadic.
                        position = params.get_position()
                        args, kwargs = simple_parameters(params, position)
                        expander = partial(found.expand, *args, **kwargs)
                    else:
                        expander = partial(found.expand, *params.unpack())

        return expander
Example #8
0
    def find_expander(self, source_obj, env=None):
        """
        Find an expander function for the given source obj in the
        specified environment.
        """

        env = self.env if env is None else env
        if not isinstance(env, Mapping):
            env = vars(env)

        expander = None

        if source_obj is nil:
            return None

        elif is_symbol(source_obj):
            namesym = source_obj
            found = self.find_compiled(namesym, env)
            if is_alias(found):
                expander = found.expand

        elif is_proper(source_obj):
            namesym, params = source_obj

            if is_symbol(namesym):
                found = self.find_compiled(namesym, env)
                if is_alias(found):
                    def expander():
                        expanded = cons(found.expand(), params)
                        expanded.set_position(source_obj.get_position())
                        return expanded

                elif is_macro(found):
                    if found._proper:
                        # FIXME: this is some garbage right here. we need
                        # to make sure macros aren't being invoked this
                        # way with a variadic.
                        position = params.get_position()
                        args, kwargs = simple_parameters(params, position)
                        expander = partial(found.expand, *args, **kwargs)
                    else:
                        expander = partial(found.expand, *params.unpack())

        return expander
Example #9
0
    def compile_pair(self, source_obj: pair, tc, cont):
        """
        Compile a pair expression. This will become either a literal nil,
        a macro expansion, a special invocation, or a runtime function
        application.
        """

        if is_nil(source_obj):
            return tcf(self.compile_nil, source_obj, tc, cont)

        if not is_proper(source_obj):
            # print("** WUT", self, source_obj, tc, cont)
            msg = "cannot evaluate improper lists as expressions"
            raise self.error(msg, source_obj)

        self.pseudop_position_of(source_obj)

        head, tail = source_obj

        if is_symbol(head) or is_lazygensym(head):
            comp = self.find_compiled(head)
            if comp:
                # the head of the pair is a symbolic reference which
                # resolved to a compile-time object. Invoke that.
                return tcf(comp.compile, self, source_obj, tc, cont)

            else:
                return tcf(self.compile_apply, source_obj, tc, cont)

        elif is_pair(head):
            return tcf(self.compile_apply, source_obj, tc, cont)

        else:
            # TODO: should this be a compile-time error? If we have
            # something that isn't a symbolic reference or isn't a
            # pair, then WTF else would it be? Let's just let it break
            # at runtime, for now.
            return tcf(self.compile_apply, source_obj, tc, cont)
Example #10
0
    def compile_pair(self, source_obj: pair, tc, cont):
        """
        Compile a pair expression. This will become either a literal nil,
        a macro expansion, a special invocation, or a runtime function
        application.
        """

        if is_nil(source_obj):
            return tcf(self.compile_nil, source_obj, tc, cont)

        if not is_proper(source_obj):
            # print("** WUT", self, source_obj, tc, cont)
            msg = "cannot evaluate improper lists as expressions"
            raise self.error(msg, source_obj)

        self.pseudop_position_of(source_obj)

        head, tail = source_obj

        if is_symbol(head) or is_lazygensym(head):
            comp = self.find_compiled(head)
            if comp:
                # the head of the pair is a symbolic reference which
                # resolved to a compile-time object. Invoke that.
                return tcf(comp.compile, self, source_obj, tc, cont)

            else:
                return tcf(self.compile_apply, source_obj, tc, cont)

        elif is_pair(head):
            return tcf(self.compile_apply, source_obj, tc, cont)

        else:
            # TODO: should this be a compile-time error? If we have
            # something that isn't a symbolic reference or isn't a
            # pair, then WTF else would it be? Let's just let it break
            # at runtime, for now.
            return tcf(self.compile_apply, source_obj, tc, cont)
Example #11
0
def gather_formals(args, declared_at=None, filename=None):
    """
    parses formals pair args into five values:
    (positional, keywords, defaults, stararg, starstararg)

    - positional is a list of symbols defining positional arguments

    - defaults is a list of keywords and expr pairs defining keyword
      arguments and their default value expression

    - kwonly is a list of keywords and expr pairs which are
      keyword-only arguments and theid default value expression

    - stararg is a symbol for variadic positional arguments

    - starstararg is a symbol for variadic keyword arguments
    """

    undefined = object()

    err = partial(SibilantSyntaxError, location=declared_at, filename=filename)

    if is_symbol(args):
        return ((), (), (), args, None)

    elif isinstance(args, (list, tuple)):
        improper = False
        args = cons(*args, nil)

    elif is_proper(args):
        improper = False

    elif is_pair(args):
        improper = True

    else:
        raise err("formals must be symbol or pair, not %r" % args)

    positional = []

    iargs = iter(args.unpack())
    for arg in iargs:
        if is_keyword(arg):
            if improper:
                raise err("cannot mix improper formal with keywords")
            else:
                break
        elif is_symbol(arg) or is_lazygensym(arg):
            positional.append(arg)
        else:
            raise err("positional formals must be symbols, not %r" % arg)
    else:
        # handled all of args, done deal.
        if improper:
            return (positional[:-1], (), (), positional[-1], None)
        else:
            return (positional, (), (), None, None)

    defaults = []
    kwonly = []

    while arg not in (_keyword_star, _keyword_starstar):
        value = next(iargs, undefined)
        if value is undefined:
            raise err("missing value for keyword formal %s" % args)
        else:
            defaults.append((arg, value))

        arg = next(iargs, undefined)

        if arg is undefined:
            break
        elif is_keyword(arg):
            continue
        else:
            raise err("keyword formals must be alternating keywords and"
                      " values, not %r" % arg)

    star = None
    starstar = None

    if arg is undefined:
        return (positional, defaults, kwonly, None, None)

    if arg is _keyword_star:
        star = next(iargs, undefined)
        if star is undefined:
            raise err("* keyword requires symbol binding")
        elif star is nil:
            # nil means an ignored star arg, this is allowed.
            pass
        elif not (is_symbol(star) or is_lazygensym(star)):
            raise err("* keyword requires symbol binding, not %r" % star)
        arg = next(iargs, undefined)

    if arg is undefined:
        return (positional, defaults, kwonly, star, starstar)

    # while is_symbol(arg):
    #     kwonly.append(arg)
    #     arg = next(iargs, undefined)
    #
    # if arg is undefined:
    #     return (positional, defaults, kwonly, star, starstar)

    if not is_keyword(arg):
        raise err("expected keyword in formals, got %r" % arg)

    # keyword formals after *: are considered keyword-only
    while arg not in (_keyword_star, _keyword_starstar):
        value = next(iargs, undefined)
        if value is undefined:
            raise err("missing value for keyword-only formal %s" % arg)
        else:
            kwonly.append((arg, value))

        arg = next(iargs, undefined)
        if arg is undefined:
            break
        elif is_keyword(arg):
            continue
        else:
            raise err("keyword-only formals must be alternating keywords"
                      " and values, not %r" % arg)

    if arg is _keyword_starstar:
        starstar = next(iargs, undefined)
        if starstar is undefined:
            raise err("** keyword requires symbol binding")
        elif not (is_symbol(starstar) or is_lazygensym(starstar)):
            raise err("** keyword requires symbol binding, not %r" % star)
        arg = next(iargs, undefined)

    if arg is not undefined:
        raise err("leftover formals %r" % arg)

    return (positional, defaults, kwonly, star, starstar)
Example #12
0
def gather_parameters(args, declared_at=None, filename=None):
    """
    parses parameter args into five values:
    (positional, keywords, values, stararg, starstararg)

    - positional is a list of expressions for positional arguments
    - keywords is a list of keywords defining keyword arguments
    - values is a list of expressions defining values for keywords
    - stararg is a symbol for variadic positional expression
    - starstararg is a symbol for variadic keyword expression
    """

    undefined = object()

    def err(msg):
        return SibilantSyntaxError(msg,
                                   location=declared_at,
                                   filename=filename)

    if is_symbol(args) or is_lazygensym(args):
        return ((), (), (), args, None)

    elif isinstance(args, (list, tuple)):
        improper = False
        args = cons(*args, nil) if args else nil

    elif is_proper(args):
        improper = False

    elif is_pair(args):
        improper = True

    else:
        raise err("parameters must be symbol or pair, not %r" % args)

    positional = []

    iargs = iter(args.unpack())
    for arg in iargs:
        if is_keyword(arg):
            break
        else:
            positional.append(arg)
    else:
        # handled all of args, done deal.
        if improper:
            return (positional[:-1], (), (), positional[-1], None)
        else:
            return (positional, (), (), None, None)

    keywords = []
    defaults = []

    while arg not in (_keyword_star, _keyword_starstar):
        keywords.append(arg)

        value = next(iargs, undefined)
        if value is undefined:
            raise err("missing value for keyword parameter %s" % arg)
        else:
            defaults.append(value)

        arg = next(iargs, undefined)
        if arg is undefined:
            break
        elif is_keyword(arg):
            continue
        else:
            raise err("keyword parameters must be alternating keywords and"
                      " values, not %r" % arg)

    star = None
    starstar = None

    if arg is undefined:
        return (positional, keywords, defaults, None, None)

    if arg is _keyword_star:
        star = next(iargs, undefined)
        if star is undefined:
            raise err("* keyword parameter needs value")
        arg = next(iargs, undefined)

    if arg is _keyword_starstar:
        starstar = next(iargs, undefined)
        if starstar is undefined:
            raise err("** keyword parameter needs value")
        arg = next(iargs, undefined)

    if arg is not undefined:
        raise err("leftover parameters %r" % arg)

    return (positional, keywords, defaults, star, starstar)
Example #13
0
def gather_formals(args, declared_at=None, filename=None):
    """
    parses formals pair args into five values:
    (positional, keywords, defaults, stararg, starstararg)

    - positional is a list of symbols defining positional arguments

    - defaults is a list of keywords and expr pairs defining keyword
      arguments and their default value expression

    - kwonly is a list of keywords and expr pairs which are
      keyword-only arguments and theid default value expression

    - stararg is a symbol for variadic positional arguments

    - starstararg is a symbol for variadic keyword arguments
    """

    undefined = object()

    err = partial(SibilantSyntaxError,
                  location=declared_at,
                  filename=filename)

    if is_symbol(args):
        return ((), (), (), args, None)

    elif isinstance(args, (list, tuple)):
        improper = False
        args = cons(*args, nil)

    elif is_proper(args):
        improper = False

    elif is_pair(args):
        improper = True

    else:
        raise err("formals must be symbol or pair, not %r" % args)

    positional = []

    iargs = iter(args.unpack())
    for arg in iargs:
        if is_keyword(arg):
            if improper:
                raise err("cannot mix improper formal with keywords")
            else:
                break
        elif is_symbol(arg) or is_lazygensym(arg):
            positional.append(arg)
        else:
            raise err("positional formals must be symbols, nor %r" % arg)
    else:
        # handled all of args, done deal.
        if improper:
            return (positional[:-1], (), (), positional[-1], None)
        else:
            return (positional, (), (), None, None)

    defaults = []
    kwonly = []

    while arg not in (_keyword_star, _keyword_starstar):
        value = next(iargs, undefined)
        if value is undefined:
            raise err("missing value for keyword formal %s" % args)
        else:
            defaults.append((arg, value))

        arg = next(iargs, undefined)

        if arg is undefined:
            break
        elif is_keyword(arg):
            continue
        else:
            raise err("keyword formals must be alternating keywords and"
                      " values, not %r" % arg)

    star = None
    starstar = None

    if arg is undefined:
        return (positional, defaults, kwonly, None, None)

    if arg is _keyword_star:
        star = next(iargs, undefined)
        if star is undefined:
            raise err("* keyword requires symbol binding")
        elif star is nil:
            # nil means an ignored star arg, this is allowed.
            pass
        elif not (is_symbol(star) or is_lazygensym(star)):
            raise err("* keyword requires symbol binding, not %r" % star)
        arg = next(iargs, undefined)

    if arg is undefined:
        return (positional, defaults, kwonly, star, starstar)

    # while is_symbol(arg):
    #     kwonly.append(arg)
    #     arg = next(iargs, undefined)
    #
    # if arg is undefined:
    #     return (positional, defaults, kwonly, star, starstar)

    if not is_keyword(arg):
        raise err("expected keyword in formals, got %r" % arg)

    # keyword formals after *: are considered keyword-only
    while arg not in (_keyword_star, _keyword_starstar):
        value = next(iargs, undefined)
        if value is undefined:
            raise err("missing value for keyword-only formal %s" % arg)
        else:
            kwonly.append((arg, value))

        arg = next(iargs, undefined)
        if arg is undefined:
            break
        elif is_keyword(arg):
            continue
        else:
            raise err("keyword-only formals must be alternating keywords"
                      " and values, not %r" % arg)

    if arg is _keyword_starstar:
        starstar = next(iargs, undefined)
        if starstar is undefined:
            raise err("** keyword requires symbol binding")
        elif not (is_symbol(starstar) or is_lazygensym(starstar)):
            raise err("** keyword requires symbol binding, not %r" % star)
        arg = next(iargs, undefined)

    if arg is not undefined:
        raise err("leftover formals %r" % arg)

    return (positional, defaults, kwonly, star, starstar)
Example #14
0
def gather_parameters(args, declared_at=None, filename=None):
    """
    parses parameter args into five values:
    (positional, keywords, values, stararg, starstararg)

    - positional is a list of expressions for positional arguments
    - keywords is a list of keywords defining keyword arguments
    - values is a list of expressions defining values for keywords
    - stararg is a symbol for variadic positional expression
    - starstararg is a symbol for variadic keyword expression
    """

    undefined = object()

    def err(msg):
        return SibilantSyntaxError(msg, location=declared_at,
                                   filename=filename)

    if is_symbol(args) or is_lazygensym(args):
        return ((), (), (), args, None)

    elif isinstance(args, (list, tuple)):
        improper = False
        args = cons(*args, nil) if args else nil

    elif is_proper(args):
        improper = False

    elif is_pair(args):
        improper = True

    else:
        raise err("parameters must be symbol or pair, not %r" % args)

    positional = []

    iargs = iter(args.unpack())
    for arg in iargs:
        if is_keyword(arg):
            break
        else:
            positional.append(arg)
    else:
        # handled all of args, done deal.
        if improper:
            return (positional[:-1], (), (), positional[-1], None)
        else:
            return (positional, (), (), None, None)

    keywords = []
    defaults = []

    while arg not in (_keyword_star, _keyword_starstar):
        keywords.append(arg)

        value = next(iargs, undefined)
        if value is undefined:
            raise err("missing value for keyword parameter %s" % arg)
        else:
            defaults.append(value)

        arg = next(iargs, undefined)
        if arg is undefined:
            break
        elif is_keyword(arg):
            continue
        else:
            raise err("keyword parameters must be alternating keywords and"
                      " values, not %r" % arg)

    star = None
    starstar = None

    if arg is undefined:
        return (positional, keywords, defaults, None, None)

    if arg is _keyword_star:
        star = next(iargs, undefined)
        if star is undefined:
            raise err("* keyword parameter needs value")
        arg = next(iargs, undefined)

    if arg is _keyword_starstar:
        starstar = next(iargs, undefined)
        if starstar is undefined:
            raise err("** keyword parameter needs value")
        arg = next(iargs, undefined)

    if arg is not undefined:
        raise err("leftover parameters %r" % arg)

    return (positional, keywords, defaults, star, starstar)