ad971d8c6f66 — Leonard Ritter 1 year, 4 months ago
* initial work on replacing cons cells with symbolic lists
18 files changed, 142 insertions(+), 1603 deletions(-)

M genie.lua
M include/scopes/scopes.h
M src/boot.cpp
R src/expander.cpp => 
R src/expander.hpp => 
M src/globals.cpp
M src/lexerparser.cpp
M src/lexerparser.hpp
R src/list.cpp => 
R src/list.hpp => 
M src/prover.cpp
M src/prover.hpp
M src/stream_expr.cpp
M src/type.cpp
M src/type.hpp
M src/value.cpp
M src/value.hpp
M src/value_kind.hpp
M genie.lua +0 -2
@@ 159,7 159,6 @@ project "scopesrt"
         "src/qualifier/key_qualifier.cpp",
         "src/qualifier/refer_qualifier.cpp",
         "src/scope.cpp",
-        "src/list.cpp",
         "src/lexerparser.cpp",
         "src/stream_anchors.cpp",
         "src/stream_expr.cpp",

          
@@ 170,7 169,6 @@ project "scopesrt"
         "src/platform_abi.cpp",
         "src/gen_spirv.cpp",
         "src/gen_llvm.cpp",
-        "src/expander.cpp",
         "src/globals.cpp",
         "src/hash.cpp",
         "src/cache.cpp",

          
M include/scopes/scopes.h +16 -26
@@ 66,7 66,6 @@ typedef scopes::Type sc_type_t;
 typedef scopes::Scope sc_scope_t;
 typedef scopes::Symbol sc_symbol_t;
 typedef scopes::String sc_string_t;
-typedef scopes::List sc_list_t;
 typedef scopes::Error sc_error_t;
 typedef scopes::Anchor sc_anchor_t;
 typedef scopes::Parameter sc_parameter_t;

          
@@ 85,7 84,6 @@ typedef scopes::ValueRef sc_valueref_t;
 typedef struct sc_type_ sc_type_t;
 typedef struct sc_scope_ sc_scope_t;
 typedef struct sc_string_ sc_string_t;
-typedef struct sc_list_ sc_list_t;
 typedef struct sc_error_ sc_error_t;
 typedef struct sc_anchor_ sc_anchor_t;
 typedef struct sc_parameter_ sc_parameter_t;

          
@@ 102,9 100,6 @@ typedef struct sc_valueref_ { sc_value_t
 typedef struct sc_bool_string_tuple_ { bool _0; const sc_string_t *_1; } sc_bool_string_tuple_t;
 typedef struct sc_bool_valueref_tuple_ { bool _0; sc_valueref_t _1; } sc_bool_valueref_tuple_t;
 
-typedef struct sc_valueref_list_tuple_ { sc_valueref_t _0; const sc_list_t *_1; } sc_valueref_list_tuple_t;
-typedef struct sc_valueref_list_scope_tuple_ { sc_valueref_t _0; const sc_list_t *_1; sc_scope_t *_2; } sc_valueref_list_scope_tuple_t;
-
 typedef struct sc_symbol_valueref_tuple_ { sc_symbol_t _0; sc_valueref_t _1; } sc_symbol_valueref_tuple_t;
 typedef struct sc_symbol_type_tuple_ { sc_symbol_t _0; const sc_type_t *_1; } sc_symbol_type_tuple_t;
 

          
@@ 116,7 111,9 @@ typedef struct sc_rawstring_i32_array_tu
 
 typedef struct sc_type_type_tuple_ { const sc_type_t *_0; const sc_type_t *_1; } sc_type_type_tuple_t;
 
-typedef struct sc_list_scope_tuple_ { const sc_list_t *_0; sc_scope_t *_1; } sc_list_scope_tuple_t;
+typedef struct sc_valueref_scope_tuple_ { sc_valueref_t _0; sc_scope_t *_1; } sc_valueref_scope_tuple_t;
+
+typedef struct sc_valueref_valueref_tuple_ { sc_valueref_t _0; sc_valueref_t _1; } sc_valueref_valueref_tuple_t;
 
 // raising types
 

          
@@ 133,13 130,9 @@ SCOPES_TYPEDEF_RESULT_RAISES(sc_symbol_r
 SCOPES_TYPEDEF_RESULT_RAISES(sc_type_raises, const sc_type_t *);
 SCOPES_TYPEDEF_RESULT_RAISES(sc_bool_raises, bool);
 
-SCOPES_TYPEDEF_RESULT_RAISES(sc_valueref_list_scope_raises, sc_valueref_list_scope_tuple_t);
-SCOPES_TYPEDEF_RESULT_RAISES(sc_list_scope_raises, sc_list_scope_tuple_t);
-
 // prototypes
 
 typedef sc_valueref_raises_t (*sc_ast_macro_func_t)(sc_valueref_t);
-typedef sc_list_scope_raises_t (*sc_syntax_wildcard_func_t)(const sc_list_t *, sc_scope_t *);
 
 // booting
 

          
@@ 153,8 146,6 @@ SCOPES_LIBEXPORT int sc_cache_misses();
 
 // compiler
 
-SCOPES_LIBEXPORT sc_valueref_list_scope_raises_t sc_expand(sc_valueref_t expr, const sc_list_t *next, sc_scope_t *scope);
-SCOPES_LIBEXPORT sc_valueref_raises_t sc_eval(const sc_anchor_t *anchor, const sc_list_t *expr, sc_scope_t *scope);
 SCOPES_LIBEXPORT sc_valueref_raises_t sc_prove(sc_valueref_t expr);
 SCOPES_LIBEXPORT sc_valueref_raises_t sc_typify(const sc_closure_t *f, int numtypes, const sc_type_t **typeargs);
 SCOPES_LIBEXPORT sc_valueref_raises_t sc_typify_template(sc_valueref_t f, int numtypes, const sc_type_t **typeargs);

          
@@ 165,7 156,6 @@ SCOPES_LIBEXPORT const sc_string_t *sc_d
 SCOPES_LIBEXPORT sc_void_raises_t sc_compile_object(const sc_string_t *target_triple, int file_kind, const sc_string_t *path, sc_scope_t *table, uint64_t flags);
 SCOPES_LIBEXPORT void sc_enter_solver_cli ();
 SCOPES_LIBEXPORT sc_size_raises_t sc_verify_stack ();
-SCOPES_LIBEXPORT sc_valueref_raises_t sc_eval_inline(const sc_anchor_t *anchor, const sc_list_t *expr, sc_scope_t *scope);
 SCOPES_LIBEXPORT sc_rawstring_i32_array_tuple_t sc_launch_args();
 
 // value

          
@@ 319,7 309,7 @@ SCOPES_LIBEXPORT uint64_t sc_hashbytes (
 // C bridge
 
 SCOPES_LIBEXPORT sc_scope_raises_t sc_import_c(const sc_string_t *path,
-    const sc_string_t *content, const sc_list_t *arglist);
+    const sc_string_t *content, sc_valueref_t arglist);
 SCOPES_LIBEXPORT sc_void_raises_t sc_load_library(const sc_string_t *name);
 SCOPES_LIBEXPORT sc_void_raises_t sc_load_object(const sc_string_t *path);
 

          
@@ 360,19 350,19 @@ SCOPES_LIBEXPORT const sc_string_t *sc_s
 SCOPES_LIBEXPORT const sc_string_t *sc_string_rslice(const sc_string_t *str, size_t offset);
 SCOPES_LIBEXPORT int sc_string_compare(const sc_string_t *a, const sc_string_t *b);
 
-// lists
+// symbolic lists
 
-SCOPES_LIBEXPORT const sc_list_t *sc_list_cons(sc_valueref_t at, const sc_list_t *next);
-SCOPES_LIBEXPORT const sc_list_t *sc_list_join(const sc_list_t *a, const sc_list_t *b);
-SCOPES_LIBEXPORT const sc_list_t *sc_list_dump(const sc_list_t *l);
-SCOPES_LIBEXPORT const sc_string_t *sc_list_repr(const sc_list_t *l);
-SCOPES_LIBEXPORT const sc_string_t *sc_list_serialize(const sc_list_t *l);
-SCOPES_LIBEXPORT sc_valueref_list_tuple_t sc_list_decons(const sc_list_t *l);
-SCOPES_LIBEXPORT int sc_list_count(const sc_list_t *l);
-SCOPES_LIBEXPORT sc_valueref_t sc_list_at(const sc_list_t *l);
-SCOPES_LIBEXPORT const sc_list_t *sc_list_next(const sc_list_t *l);
-SCOPES_LIBEXPORT const sc_list_t *sc_list_reverse(const sc_list_t *l);
-SCOPES_LIBEXPORT bool sc_list_compare(const sc_list_t *a, const sc_list_t *b);
+SCOPES_LIBEXPORT sc_valueref_t sc_symlist_cons(sc_valueref_t at, sc_valueref_t next);
+SCOPES_LIBEXPORT sc_valueref_t sc_symlist_join(sc_valueref_t a, sc_valueref_t b);
+SCOPES_LIBEXPORT sc_valueref_t sc_symlist_dump(sc_valueref_t l);
+SCOPES_LIBEXPORT const sc_string_t *sc_symlist_repr(sc_valueref_t l);
+SCOPES_LIBEXPORT const sc_string_t *sc_symlist_serialize(sc_valueref_t l);
+SCOPES_LIBEXPORT sc_valueref_valueref_tuple_t sc_symlist_decons(sc_valueref_t l);
+SCOPES_LIBEXPORT int sc_symlist_count(sc_valueref_t l);
+SCOPES_LIBEXPORT sc_valueref_t sc_symlist_at(sc_valueref_t l);
+SCOPES_LIBEXPORT sc_valueref_t sc_symlist_next(sc_valueref_t l);
+SCOPES_LIBEXPORT sc_valueref_t sc_symlist_reverse(sc_valueref_t l);
+SCOPES_LIBEXPORT bool sc_symlist_compare(sc_valueref_t a, sc_valueref_t b);
 
 // anchors
 

          
M src/boot.cpp +4 -6
@@ 11,11 11,9 @@ 
 #include "lexerparser.hpp"
 #include "source_file.hpp"
 #include "prover.hpp"
-#include "list.hpp"
 #include "execution.hpp"
 #include "globals.hpp"
 #include "scope.hpp"
-#include "expander.hpp"
 #include "types.hpp"
 #include "gen_llvm.hpp"
 #include "compiler_flags.hpp"

          
@@ 100,12 98,12 @@ SCOPES_RESULT(ValueRef) load_custom_core
     while ((cursor >= ptr) && (*cursor != '('))
         cursor--;
     LexerParser footerParser(std::move(file), cursor - ptr);
-    auto expr = SCOPES_GET_RESULT(extract_list_constant(SCOPES_GET_RESULT(footerParser.parse())));
-    if (expr == EOL) {
+    auto expr = SCOPES_GET_RESULT(extract_symlist_constant(SCOPES_GET_RESULT(footerParser.parse())));
+    if (expr->empty()) {
         SCOPES_ERROR(InvalidFooter);
     }
-    auto it = SCOPES_GET_RESULT(extract_list_constant(expr->at));
-    if (it == EOL) {
+    auto it = SCOPES_GET_RESULT(extract_symlist_constant(expr->at));
+    if (it->empty()) {
         SCOPES_ERROR(InvalidFooter);
     }
     auto head = it->at;

          
R src/expander.cpp =>  +0 -1263
@@ 1,1263 0,0 @@ 
-/*
-    The Scopes Compiler Infrastructure
-    This file is distributed under the MIT License.
-    See LICENSE.md for details.
-*/
-
-#include "expander.hpp"
-#include "list.hpp"
-#include "error.hpp"
-#include "type.hpp"
-#include "type/arguments_type.hpp"
-#include "type/pointer_type.hpp"
-#include "type/function_type.hpp"
-#include "scope.hpp"
-#include "stream_expr.hpp"
-#include "anchor.hpp"
-#include "value.hpp"
-#include "prover.hpp"
-#include "timer.hpp"
-#include "stream_expr.hpp"
-#include "gc.hpp"
-#include "dyn_cast.inc"
-#include "scopes/scopes.h"
-
-#include <assert.h>
-
-namespace scopes {
-
-//------------------------------------------------------------------------------
-// MACRO EXPANDER
-//------------------------------------------------------------------------------
-// expands macros and generates the AST
-
-static SCOPES_RESULT(void) verify_list_parameter_count(const char *context, const List *expr, int mincount, int maxcount, int starti = 1) {
-    SCOPES_RESULT_TYPE(void);
-    if (!expr) {
-        SCOPES_ERROR(SyntaxCallExpressionEmpty);
-    }
-    if ((mincount <= 0) && (maxcount == -1)) {
-        return {};
-    }
-    int argcount = (int)List::count(expr) - starti;
-
-    if ((maxcount >= 0) && (argcount > maxcount)) {
-        SCOPES_ERROR(SyntaxTooManyArguments, maxcount);
-    }
-    if ((mincount >= 0) && (argcount < mincount)) {
-        SCOPES_ERROR(SyntaxNotEnoughArguments, mincount, argcount);
-    }
-    return {};
-}
-
-//------------------------------------------------------------------------------
-
-static Symbol try_extract_symbol(const ValueRef &node) {
-    auto ptr = node.dyn_cast<ConstInt>();
-    if (ptr && (ptr->get_type() == TYPE_Symbol))
-        return Symbol::wrap(ptr->value);
-    return SYM_Unnamed;
-}
-
-//------------------------------------------------------------------------------
-
-struct Expander {
-    Scope *env;
-    TemplateRef astscope;
-    const List *next;
-    static bool verbose;
-
-    static const Type *list_expander_func_type;
-
-    Expander(Scope *_env, const TemplateRef &_astscope, const List *_next = EOL) :
-        env(_env),
-        astscope(_astscope),
-        next(_next) {
-        if (!list_expander_func_type) {
-            list_expander_func_type = pointer_type(raising_function_type(
-                arguments_type({TYPE_List, TYPE_Scope}),
-                {TYPE_List, TYPE_Scope}), PTF_NonWritable, SYM_Unnamed);
-        }
-    }
-
-    ~Expander() {}
-
-    SCOPES_RESULT(ValueRef) expand_expression(const ListRef &src, bool scoped) {
-        SCOPES_RESULT_TYPE(ValueRef);
-        ExpressionRef expr;
-        const List *it = src.unref();
-        while (it) {
-            next = it->next;
-            if (!last_expression()) {
-                const String *doc = try_extract_string(it->at);
-                if (doc) {
-                    env->set_doc(doc);
-                }
-            }
-            if (!expr) {
-                if (scoped)
-                    expr = ref(src.anchor(), Expression::scoped_from());
-                else
-                    expr = ref(src.anchor(), Expression::unscoped_from());
-            }
-            expr->append(SCOPES_GET_RESULT(expand(it->at)));
-            it = next;
-        }
-        if (expr) {
-            if (expr->body.empty() && !expr->scoped)
-                return expr->value;
-            return ValueRef(expr);
-        }
-        return ref(src.anchor(), ArgumentListTemplate::from());
-    }
-
-    SCOPES_RESULT(ValueRef) expand_run_stage(const List *it) {
-        SCOPES_RESULT_TYPE(ValueRef);
-        SCOPES_CHECK_RESULT(verify_list_parameter_count("run-stage", it, 0, 0));
-        assert(it);
-
-        auto anchor = it->at.anchor();
-        auto node = ref(anchor, CompileStage::from(anchor, next, env));
-        next = EOL;
-        return ValueRef(node);
-    }
-
-    SCOPES_RESULT(ParameterTemplateRef) expand_parameter(
-        const ValueRef &value, const ValueRef &node = ValueRef()) {
-        SCOPES_RESULT_TYPE(ParameterTemplateRef);
-        if (value.isa<ParameterTemplate>()) {
-            return value.cast<ParameterTemplate>();
-        } else {
-            Symbol sym = SCOPES_GET_RESULT(extract_symbol_constant(value));
-            if (node && node.isa<Pure>()) {
-                env->bind(sym, node);
-                return ParameterTemplateRef();
-            } else {
-                ParameterTemplateRef param;
-                if (ends_with_parenthesis(sym)) {
-                    param = ref(value.anchor(), ParameterTemplate::variadic_from(sym));
-                } else {
-                    param = ref(value.anchor(), ParameterTemplate::from(sym));
-                }
-                env->bind(sym, param);
-                return param;
-            }
-        }
-    }
-
-    struct ExpandFnSetup {
-        bool inlined;
-
-        ExpandFnSetup() {
-            inlined = false;
-        };
-    };
-
-    SCOPES_RESULT(ValueRef) expand_fn(const List *it, const ExpandFnSetup &setup) {
-        SCOPES_RESULT_TYPE(ValueRef);
-        SCOPES_CHECK_RESULT(verify_list_parameter_count("fn", it, 1, -1));
-
-        auto anchor = it->at.anchor();
-
-        // skip head
-        it = it->next;
-
-        assert(it != EOL);
-
-        bool continuing = false;
-        Symbol bind_name = SYM_Unnamed;
-        TemplateRef func;
-        ValueRef result;
-        //Any tryfunc_name = SCOPES_GET_RESULT(unsyntax(it->at));
-        const Type *T = try_get_const_type(it->at);
-        if (T == TYPE_Symbol) {
-            auto sym = SCOPES_GET_RESULT(extract_symbol_constant(it->at));
-            // named self-binding
-            // see if we can find a forward declaration in the local scope
-            if (env->lookup_local(sym, result)
-                && result.isa<Template>()
-                && result.cast<Template>()->is_forward_decl()) {
-                func = result.cast<Template>();
-                func = ref(anchor, func);
-                continuing = true;
-            } else {
-                func = ref(anchor, Template::from(sym));
-                result = func;
-                bind_name = sym;
-            }
-            it = it->next;
-        } else if (T == TYPE_String) {
-            auto str = try_extract_string(it->at);
-            assert(str);
-            // named lambda
-            func = ref(anchor, Template::from(Symbol(str)));
-            result = func;
-            it = it->next;
-        } else {
-            // unnamed lambda
-            func = ref(anchor, Template::from(Symbol(SYM_Unnamed)));
-            result = func;
-        }
-        if (setup.inlined)
-            func->set_inline();
-        //func->set_def_anchor(anchor);
-        /*
-        if (setup.quoted)
-            result = ast_quote(func);
-        */
-
-        if (it == EOL) {
-            // forward declaration
-            if (bind_name == SYM_Unnamed) {
-                SCOPES_ERROR(SyntaxUnnamedForwardDeclaration);
-            }
-            env->bind(bind_name, func);
-            return result;
-        }
-
-        const List *params = SCOPES_GET_RESULT(extract_list_constant(it->at));
-
-        it = it->next;
-
-        Scope *subenv = Scope::from(env);
-        if (!func->is_hidden()) {
-            subenv->bind(KW_Recur, func);
-            // ensure the local scope does not contain special symbols
-            subenv = Scope::from(subenv);
-        }
-
-        Expander subexpr(subenv, func);
-
-        while (params != EOL) {
-            func->append_param(SCOPES_GET_RESULT(subexpr.expand_parameter(params->at)));
-            params = params->next;
-        }
-
-        if ((it != EOL) && (it->next != EOL)) {
-            auto str = try_extract_string(it->at);
-            if (str) {
-                func->docstring = str;
-                it = it->next;
-            }
-        }
-
-        func->value = SCOPES_GET_RESULT(subexpr.expand_expression(
-            ref(anchor, it), false));
-        if (bind_name != SYM_Unnamed) {
-            env->bind(bind_name, func);
-        }
-
-        return result;
-    }
-
-    bool last_expression() {
-        return next == EOL;
-    }
-
-    SCOPES_RESULT(ValueRef) expand_label(const List *it) {
-        SCOPES_RESULT_TYPE(ValueRef);
-        it = it->next;
-
-        auto name = SCOPES_GET_RESULT(extract_symbol_constant(it->at));
-        auto anchor = it->at.anchor();
-        it = it->next;
-
-        Scope *subenv = Scope::from(env);
-        auto label = ref(anchor, LabelTemplate::from(LK_User, name));
-        subenv->bind(name, label);
-        Expander subexpr(subenv, astscope);
-        label->value = SCOPES_GET_RESULT(subexpr.expand_expression(
-            ref(anchor, it), false));
-        return ValueRef(label);
-    }
-
-    SCOPES_RESULT(ValueRef) expand_do(const List *it) {
-        //SCOPES_RESULT_TYPE(ValueRef);
-        assert(it);
-        auto anchor = it->at.anchor();
-        it = it->next;
-
-        Scope *subenv = Scope::from(env);
-        Expander subexpr(subenv, astscope);
-        return subexpr.expand_expression(ref(anchor, it), true);
-    }
-
-    SCOPES_RESULT(ValueRef) expand_inline_do(const List *it) {
-        SCOPES_RESULT_TYPE(ValueRef);
-        auto anchor = it->at.anchor();
-        it = it->next;
-
-        Expander subexpr(env, astscope);
-        auto expr = SCOPES_GET_RESULT(
-            subexpr.expand_expression(ref(anchor, it), false));
-        env = subexpr.env;
-        return expr;
-    }
-
-    bool is_then_token(const ValueRef &name) {
-        auto tok = try_extract_symbol(name);
-        return tok == KW_Then;
-    }
-
-    bool is_equal_token(const ValueRef &name) {
-        auto tok = try_extract_symbol(name);
-        return tok == OP_Set;
-    }
-
-    bool is_except_token(const ValueRef &name) {
-        auto tok = try_extract_symbol(name);
-        return tok == KW_Except;
-    }
-
-    // (loop ([x...] [= init...]) body...)
-    SCOPES_RESULT(ValueRef) expand_loop(const List *it) {
-        SCOPES_RESULT_TYPE(ValueRef);
-
-        /*
-        we're building this structure
-
-        label break
-            loop x... (init...)
-                body...
-
-        break labels never type themselves from their body
-        */
-
-        SCOPES_CHECK_RESULT(verify_list_parameter_count("loop", it, 1, -1));
-        auto anchor = it->at.anchor();
-        it = it->next;
-
-        const List *params = SCOPES_GET_RESULT(extract_list_constant(it->at));
-        auto param_anchor = it->at.anchor();
-        const List *values = nullptr;
-        const List *body = it->next;
-        auto endit = params;
-
-        while (endit) {
-            if (is_equal_token(endit->at))
-                break;
-            endit = endit->next;
-        }
-        if (endit != EOL)
-            values = endit->next;
-
-        it = values;
-
-        Values initargs;
-        if (it) {
-            Expander subexp(env, astscope, it->next);
-            SCOPES_CHECK_RESULT(subexp.expand_arguments(initargs, it));
-        }
-
-        LoopRef loop = ref(anchor, Loop::from(ref(param_anchor,
-            ArgumentListTemplate::from(initargs))));
-        LabelTemplateRef break_label = ref(anchor,
-            LabelTemplate::from(LK_Break, KW_Break, loop));
-
-        Expander bodyexp(Scope::from(env), astscope);
-
-        auto expr = Expression::unscoped_from();
-        {
-            int index = 0;
-            it = params;
-            // read parameter names
-            while (it != endit) {
-                auto paramval = it->at;
-                Symbol sym = SCOPES_GET_RESULT(extract_symbol_constant(paramval));
-                ValueRef node;
-                if (!ends_with_parenthesis(sym)) {
-                    node = ref(paramval.anchor(), extract_argument(loop->args, index));
-                } else {
-                    if (it->next != endit) {
-                        SCOPES_ERROR(SyntaxVariadicSymbolNotLast);
-                    }
-                    node = ref(paramval.anchor(), extract_argument(loop->args, index, true));
-                }
-                bodyexp.env->bind(sym, node);
-                expr->append(node);
-                it = it->next;
-                index++;
-            }
-        }
-
-        auto value = SCOPES_GET_RESULT(bodyexp.expand_expression(
-            ref(anchor, body), false));
-        expr->append(value);
-        loop->value = ref(anchor, expr);
-        return ValueRef(break_label);
-    }
-
-    static ValueRef extract_argument(const ValueRef &node, int index, bool vararg = false) {
-        if (node.isa<Const>()) {
-            assert(!is_arguments_type(node.cast<Const>()->get_type()));
-            if (index == 0) {
-                return node;
-            } else {
-                return ref(node.anchor(), ConstAggregate::none_from());
-            }
-        }
-        auto result = ExtractArgumentTemplate::from(node, index, vararg);
-        if (!vararg) {
-            result = KeyedTemplate::from(SYM_Unnamed, result);
-        }
-        return result;
-    }
-
-    // (let x ... [= args ...])
-    // (let (x ... = args ...) ...
-    // ...
-    SCOPES_RESULT(ValueRef) expand_let(const List *it) {
-        SCOPES_RESULT_TYPE(ValueRef);
-
-        SCOPES_CHECK_RESULT(verify_list_parameter_count("let", it, 1, -1));
-        auto anchor = it->at.anchor();
-        it = it->next;
-
-        Values exprs;
-        Values args;
-
-        const Type *T = try_get_const_type(it->at);
-        if (T == TYPE_List) {
-            // alternative format where the symbols are only bound
-            // after all expressions have been evaluated.
-            std::vector< std::pair<Symbol, ValueRef> > late_bound;
-            late_bound.reserve(List::count(it));
-            const List *equit = it;
-            while (equit) {
-                it = SCOPES_GET_RESULT(extract_list_constant(equit->at));
-                SCOPES_CHECK_RESULT(verify_list_parameter_count("=", it, 3, -1, 0));
-                auto paramval = it->at;
-                it = it->next;
-                if (!is_equal_token(it->at)) {
-                    SCOPES_ERROR(SyntaxAssignmentTokenExpected);
-                }
-                it = it->next;
-                // read init values
-                Expander subexp(env, astscope);
-                subexp.next = it->next;
-                auto node = SCOPES_GET_RESULT(subexp.expand(it->at));
-                it = subexp.next;
-                env = subexp.env;
-                if (it) {
-                    SCOPES_ERROR(SyntaxUnexpectedExtraToken);
-                }
-                exprs.push_back(node);
-                Symbol sym = SCOPES_GET_RESULT(extract_symbol_constant(paramval));
-                if (!ends_with_parenthesis(sym)) {
-                    node = extract_argument(node, 0);
-                }
-                args.push_back(node);
-                late_bound.push_back({sym, node});
-                equit = equit->next;
-            }
-            for (auto entry : late_bound) {
-                env->bind(entry.first, entry.second);
-            }
-        } else {
-            const List *values = nullptr;
-            auto endit = it;
-            // read parameter names
-            while (endit) {
-                if (is_equal_token(endit->at))
-                    break;
-                endit = endit->next;
-            }
-            if (endit != EOL)
-                values = endit;
-
-            if (!values) {
-                // no assignments, reimport parameter names into local scope
-                ValueRef last_entry;
-                while (it != endit) {
-                    auto name = SCOPES_GET_RESULT(extract_symbol_constant(it->at));
-                    ScopeEntry entry;
-                    if (!env->lookup(name, entry)) {
-                        SCOPES_ERROR(SyntaxUndeclaredIdentifier, name, env);
-                    }
-                    if (!entry.doc) {
-                        env->bind(name, entry.expr);
-                    } else {
-                        env->bind_with_doc(name, entry);
-                    }
-                    last_entry = entry.expr;
-                    it = it->next;
-                }
-                if (!last_entry) {
-                    last_entry = ref(anchor, ConstAggregate::none_from());
-                }
-                return ref(anchor, last_entry);
-            }
-
-            const List *params = it;
-
-            it = values;
-            it = it->next;
-            // read init values
-            Expander subexp(env, astscope);
-            while (it) {
-                subexp.next = it->next;
-                auto node = SCOPES_GET_RESULT(subexp.expand(it->at));
-                exprs.push_back(node);
-                it = subexp.next;
-            }
-            env = subexp.env;
-
-            ValueRef srcval = ref(anchor, ArgumentListTemplate::from(exprs));
-
-            int index = 0;
-            bool variadic = false;
-            //int lastarg = (int)args.size() - 1;
-            it = params;
-            // read parameter names
-            while (it != endit) {
-                auto paramval = it->at;
-                Symbol sym = SCOPES_GET_RESULT(extract_symbol_constant(paramval));
-                ValueRef node;
-                if (!ends_with_parenthesis(sym)) {
-                    node = ref(paramval.anchor(), extract_argument(srcval, index));
-                } else {
-                    if (it->next != endit) {
-                        SCOPES_ERROR(SyntaxVariadicSymbolNotLast);
-                    }
-                    node = ref(paramval.anchor(), extract_argument(srcval, index, true));
-                    variadic = true;
-                }
-                args.push_back(node);
-                env->bind(sym, node);
-                it = it->next;
-                index++;
-            }
-
-            if (!variadic && (index < exprs.size())) {
-                SCOPES_TRACE_EXPANDER(exprs[index]);
-                SCOPES_ERROR(SyntaxExcessBindingArgument);
-            }
-
-        }
-
-        return ValueRef(ref(anchor, Expression::unscoped_from(exprs,
-            ref(anchor, ArgumentListTemplate::from(args)))));
-    }
-
-    // quote <value> ...
-    SCOPES_RESULT(ValueRef) expand_syntax_quote(const List *it) {
-        SCOPES_RESULT_TYPE(ValueRef);
-        SCOPES_CHECK_RESULT(verify_list_parameter_count("syntax-quote", it, 1, -1));
-        auto anchor = it->at.anchor();
-        it = it->next;
-
-        if (List::count(it) == 1) {
-            return it->at;
-        } else {
-            return ValueRef(ref(anchor, ConstPointer::list_from(it)));
-        }
-    }
-
-    SCOPES_RESULT(ValueRef) expand_syntax_log(const List *it) {
-        SCOPES_RESULT_TYPE(ValueRef);
-        SCOPES_CHECK_RESULT(verify_list_parameter_count("syntax-log", it, 1, 1));
-        auto anchor = it->at.anchor();
-        it = it->next;
-
-        auto sym = SCOPES_GET_RESULT(extract_symbol_constant(it->at));
-        if (sym == KW_True) {
-            this->verbose = true;
-        } else if (sym == KW_False) {
-            this->verbose = false;
-        } else {
-            // ignore
-        }
-
-        return ValueRef(ref(anchor, ArgumentList::from({})));
-    }
-
-    // (try [x ...]) (except (param ...) [expr ...])
-    SCOPES_RESULT(ValueRef) expand_try(const List *it) {
-        SCOPES_RESULT_TYPE(ValueRef);
-
-        /*
-        # we're building this structure
-        label try
-            let except-param ... =
-                label except
-                    merge try
-                        do
-                            try-body ...
-                            (any raise merges to except)
-            except-body ...
-        */
-
-        SCOPES_CHECK_RESULT(verify_list_parameter_count("try", it, 0, -1));
-        auto try_anchor = it->at.anchor();
-        //ValueRef src = it->at;
-        it = it->next;
-
-        Expander subexp(Scope::from(env), astscope);
-
-        ValueRef try_value = SCOPES_GET_RESULT(subexp.expand_expression(
-            ref(try_anchor, it), false));
-        LabelTemplateRef try_label = ref(try_anchor, LabelTemplate::try_from());
-        LabelTemplateRef except_label = ref(try_anchor, LabelTemplate::except_from(
-            ref(try_anchor, MergeTemplate::from(try_label, try_value))));
-
-        if (next != EOL) {
-            //auto _next_def = next->at;
-            it = SCOPES_GET_RESULT(extract_list_constant(next->at));
-            if (it != EOL) {
-                if (is_except_token(it->at)) {
-                    SCOPES_CHECK_RESULT(verify_list_parameter_count("except", it, 1, -1));
-                    auto except_anchor = it->at.anchor();
-                    except_label = ref(except_anchor, except_label);
-                    it = it->next;
-                    next = next->next;
-
-                    const List *params = SCOPES_GET_RESULT(extract_list_constant(it->at));
-                    const List *body = it->next;
-
-                    Expander subexp(Scope::from(env), astscope);
-                    auto expr = Expression::unscoped_from();
-                    expr->append(except_label);
-                    {
-                        int index = 0;
-                        it = params;
-                        // read parameter names
-                        while (it != EOL) {
-                            auto paramval = it->at;
-                            Symbol sym = SCOPES_GET_RESULT(extract_symbol_constant(paramval));
-                            ValueRef node;
-                            if (!ends_with_parenthesis(sym)) {
-                                node = ref(paramval.anchor(), extract_argument(except_label, index));
-                            } else {
-                                if (it->next != EOL) {
-                                    SCOPES_ERROR(SyntaxVariadicSymbolNotLast);
-                                }
-                                node = ref(paramval.anchor(), extract_argument(except_label, index, true));
-                            }
-                            subexp.env->bind(sym, node);
-                            expr->append(node);
-                            it = it->next;
-                            index++;
-                        }
-                    }
-
-                    it = body;
-                    ValueRef except_value = SCOPES_GET_RESULT(
-                        subexp.expand_expression(ref(except_anchor, it), false));
-                    expr->append(except_value);
-                    try_label->value = ref(except_anchor, expr);
-                    return ValueRef(try_label);
-                }
-            }
-        }
-        SCOPES_ERROR(SyntaxExceptBlockExpected);
-    }
-
-    // (switch cond)
-    // [(case literal body ...)]
-    // (default body ...)
-    SCOPES_RESULT(ValueRef) expand_switch(const List *it) {
-        SCOPES_RESULT_TYPE(ValueRef);
-        SCOPES_CHECK_RESULT(verify_list_parameter_count("switch", it, 1, -1));
-        auto anchor = it->at.anchor();
-        it = it->next;
-
-        Expander subexp(env, astscope);
-        assert(it);
-        subexp.next = it->next;
-        auto expr = SCOPES_GET_RESULT(subexp.expand(it->at));
-        it = subexp.next;
-
-        SwitchTemplate::Cases cases;
-
-        it = next;
-    collect_case:
-        if ((it == EOL) || (try_get_const_type(it->at) != TYPE_List)) {
-            SCOPES_ERROR(SyntaxMissingDefaultCase);
-        }
-        next = it->next;
-        auto _case = SwitchTemplate::Case();
-        //_case.anchor = it->at->anchor();
-        it = SCOPES_GET_RESULT(extract_list_constant(it->at));
-        SCOPES_CHECK_RESULT(verify_list_parameter_count("case", it, 1, -1));
-        auto case_anchor = it->at.anchor();
-        auto head = try_extract_symbol(it->at);
-        if ((head == KW_Case) || (head == KW_Pass)) {
-            if (head == KW_Pass) {
-                _case.kind = CK_Pass;
-            }
-
-            it = it->next;
-            subexp.next = it->next;
-            _case.literal = SCOPES_GET_RESULT(subexp.expand(it->at));
-            it = subexp.next;
-
-            Expander nativeexp(Scope::from(env), astscope);
-            _case.value = SCOPES_GET_RESULT(
-                nativeexp.expand_expression(ref(case_anchor, it), false));
-            cases.push_back(_case);
-
-            it = next;
-            goto collect_case;
-        } else if (head == KW_Default) {
-            it = it->next;
-
-            _case.kind = CK_Default;
-
-            Expander nativeexp(Scope::from(env), astscope);
-            _case.value = SCOPES_GET_RESULT(
-                nativeexp.expand_expression(ref(case_anchor, it), false));
-            cases.push_back(_case);
-        }
-
-        return ValueRef(ref(anchor, SwitchTemplate::from(expr, cases)));
-    }
-
-    // (if cond body ...)
-    // [(elseif cond body ...)]
-    // [(else body ...)]
-    SCOPES_RESULT(ValueRef) expand_if(const List *it) {
-        SCOPES_RESULT_TYPE(ValueRef);
-        std::vector<const List *> branches;
-
-        assert(it);
-        auto anchor = it->at.anchor();
-
-    collect_branch:
-        SCOPES_CHECK_RESULT(verify_list_parameter_count("if", it, 1, -1));
-        branches.push_back(it);
-
-        it = next;
-        if (it != EOL) {
-            auto itnext = it->next;
-            auto T = try_get_const_type(it->at);
-            if (T == TYPE_List) {
-                it = SCOPES_GET_RESULT(extract_list_constant(it->at));
-                if (it != EOL) {
-                    auto head = try_extract_symbol(it->at);
-                    if (head == KW_ElseIf) {
-                        next = itnext;
-                        goto collect_branch;
-                    } else if (head == KW_Else) {
-                        next = itnext;
-                        branches.push_back(it);
-                    } else {
-                        branches.push_back(EOL);
-                    }
-                } else {
-                    branches.push_back(EOL);
-                }
-            } else {
-                branches.push_back(EOL);
-            }
-        } else {
-            branches.push_back(EOL);
-        }
-
-        auto ifexpr = If::from();
-
-        int lastidx = (int)branches.size() - 1;
-        for (int idx = 0; idx < lastidx; ++idx) {
-            it = branches[idx];
-            //const Anchor *anchor = it->at->anchor();
-            SCOPES_CHECK_RESULT(verify_list_parameter_count("branch", it, 1, -1));
-            auto branch_anchor = it->at.anchor();
-
-            #if 0
-            // check for new form
-            auto new_form = false;
-            {
-                auto subit = it->next;
-                while (subit != EOL) {
-                    if (is_then_token(subit->at)) {
-                        SCOPES_CHECK_RESULT(verify_list_parameter_count(
-                            "branch", it, 2, -1));
-                        new_form = true;
-                        break;
-                    }
-                    subit = subit->next;
-                }
-            }
-            #endif
-            it = it->next;
-
-            #if 0
-            if (new_form) {
-                Values condvals;
-                assert(it);
-                condvals.reserve(it->count);
-                auto cond_anchor = it->at.anchor();
-                while (it != EOL) {
-                    if (is_then_token(it->at)) {
-                        it = it->next;
-                        break;
-                    }
-                    condvals.push_back(it->at);
-                    it = it->next;
-                }
-                ValueRef condexpr;
-                if (condvals.size() == 1) {
-                    condexpr = condvals[0];
-                } else {
-                    condexpr = ref(cond_anchor,
-                        ConstPointer::list_from(
-                            List::from(&condvals[0], condvals.size())));
-                }
-                Expander subexp(env, astscope);
-                subexp.next = EOL;
-                ValueRef cond = SCOPES_GET_RESULT(subexp.expand(condexpr));
-                subexp.env = Scope::from(env);
-                ifexpr->append_then(cond,
-                    SCOPES_GET_RESULT(
-                        subexp.expand_expression(ref(branch_anchor, it), false)));
-            } else
-            #endif
-            {
-                Expander subexp(env, astscope);
-                assert(it);
-                subexp.next = it->next;
-                ValueRef cond = SCOPES_GET_RESULT(subexp.expand(it->at));
-                it = subexp.next;
-
-                subexp.env = Scope::from(env);
-                ifexpr->append_then(cond,
-                    SCOPES_GET_RESULT(
-                        subexp.expand_expression(ref(branch_anchor, it), false)));
-            }
-        }
-
-        it = branches[lastidx];
-        if (it != EOL) {
-            auto else_anchor = it->at.anchor();
-            it = it->next;
-            Expander subexp(Scope::from(env), astscope);
-
-            ifexpr->append_else(
-                SCOPES_GET_RESULT(
-                    subexp.expand_expression(ref(else_anchor, it), false)));
-        }
-
-        return ValueRef(ref(anchor, ifexpr));
-    }
-
-    static SCOPES_RESULT(bool) get_kwargs(
-        ValueRef it, Symbol &key, ValueRef &value) {
-        SCOPES_RESULT_TYPE(bool);
-        auto T = try_get_const_type(it);
-        if (T != TYPE_List) return false;
-        auto l = SCOPES_GET_RESULT(extract_list_constant(it));
-        if (l == EOL) return false;
-        it = l->at;
-        T = try_get_const_type(it);
-        if (T != TYPE_Symbol) return false;
-        key = SCOPES_GET_RESULT(extract_symbol_constant(it));
-        l = l->next;
-        if (l == EOL) return false;
-        it = l->at;
-        T = try_get_const_type(it);
-        if (T != TYPE_Symbol) return false;
-        auto sym = SCOPES_GET_RESULT(extract_symbol_constant(it));
-        if (sym != OP_Set) return false;
-        l = l->next;
-        if (l == EOL) return false;
-        if (List::count(l) > 1) {
-            SCOPES_TRACE_EXPANDER(it);
-            SCOPES_ERROR(SyntaxKeyedArgumentMismatch);
-        }
-        value = l->at;
-        return true;
-    }
-
-    SCOPES_RESULT(void) expand_arguments(Values &args, const List *it) {
-        SCOPES_RESULT_TYPE(void);
-        while (it) {
-            next = it->next;
-            Symbol key = SYM_Unnamed;
-            ValueRef value;
-            //SCOPES_ANCHOR(it->at->anchor());
-            if (SCOPES_GET_RESULT(get_kwargs(it->at, key, value))) {
-                args.push_back(
-                    KeyedTemplate::from(key,
-                        SCOPES_GET_RESULT(expand(value))));
-            } else {
-                args.push_back(SCOPES_GET_RESULT(expand(it->at)));
-            }
-            it = next;
-        }
-        return {};
-    }
-
-    ValueRef ast_quote(const ValueRef &expr) {
-        if (expr.isa<Expression>()) {
-            auto ex = expr.cast<Expression>();
-            ex->scoped = false;
-        }
-        return ref(expr.anchor(), Quote::from(expr));
-    }
-
-    SCOPES_RESULT(ValueRef) expand_ast_quote(const List *it) {
-        SCOPES_RESULT_TYPE(ValueRef);
-        auto anchor = it->at.anchor();
-        it = it->next;
-
-        Expander subexpr(env, astscope);
-        auto expr = SCOPES_GET_RESULT(subexpr.expand_expression(
-            ref(anchor, it), false));
-        return ref(anchor, ast_quote(expr));
-    }
-
-    SCOPES_RESULT(ValueRef) expand_ast_unquote(const List *it) {
-        SCOPES_RESULT_TYPE(ValueRef);
-        SCOPES_CHECK_RESULT(verify_list_parameter_count("ast-unquote", it, 0, -1));
-        auto anchor = it->at.anchor();
-        it = it->next;
-        Expander subexp(env, astscope);
-        return ValueRef(ref(anchor, Unquote::from(
-            SCOPES_GET_RESULT(subexp.expand_expression(
-                ref(anchor, it), false)))));
-    }
-
-    SCOPES_RESULT(ValueRef) expand_ast_unquote_arguments(const List *it) {
-        SCOPES_RESULT_TYPE(ValueRef);
-        SCOPES_CHECK_RESULT(verify_list_parameter_count("ast-unquote-arguments", it, 0, -1));
-        auto anchor = it->at.anchor();
-        it = it->next;
-        Values args;
-        if (it) {
-            Expander subexp(env, astscope, it->next);
-            SCOPES_CHECK_RESULT(subexp.expand_arguments(args, it));
-        }
-        return ValueRef(ref(anchor, Unquote::from(
-            ref(anchor, ArgumentListTemplate::from(args)))));
-    }
-
-    template<typename T>
-    SCOPES_RESULT(ValueRef) build_terminator(const ListRef &src) {
-        SCOPES_RESULT_TYPE(ValueRef);
-        auto it = src.unref();
-        Values args;
-        if (it) {
-            Expander subexp(env, astscope, it->next);
-            SCOPES_CHECK_RESULT(subexp.expand_arguments(args, it));
-        }
-        return ValueRef(ref(src.anchor(), T::from(ref(src.anchor(),
-            ArgumentListTemplate::from(args)))));
-    }
-
-    template<typename T>
-    SCOPES_RESULT(ValueRef) build_terminator(const ListRef &src,
-        const LabelTemplateRef &label) {
-        SCOPES_RESULT_TYPE(ValueRef);
-        auto it = src.unref();
-        Values args;
-        if (it) {
-            Expander subexp(env, astscope, it->next);
-            SCOPES_CHECK_RESULT(subexp.expand_arguments(args, it));
-        }
-        return ValueRef(ref(src.anchor(), T::from(label, ref(src.anchor(),
-                ArgumentListTemplate::from(args)))));
-    }
-
-    SCOPES_RESULT(ValueRef) expand_return(const List *it) {
-        SCOPES_RESULT_TYPE(ValueRef);
-        SCOPES_CHECK_RESULT(verify_list_parameter_count("return", it, 0, -1));
-        auto anchor = it->at.anchor();
-        it = it->next;
-        return build_terminator<ReturnTemplate>(ref(anchor, it));
-    }
-
-    SCOPES_RESULT(ValueRef) expand_raise(const List *it) {
-        SCOPES_RESULT_TYPE(ValueRef);
-        SCOPES_CHECK_RESULT(verify_list_parameter_count("raise", it, 0, -1));
-        auto anchor = it->at.anchor();
-        it = it->next;
-        return build_terminator<RaiseTemplate>(ref(anchor, it));
-    }
-
-    SCOPES_RESULT(ValueRef) expand_break(const List *it) {
-        SCOPES_RESULT_TYPE(ValueRef);
-        SCOPES_CHECK_RESULT(verify_list_parameter_count("break", it, 0, -1));
-        auto anchor = it->at.anchor();
-        it = it->next;
-        return build_terminator<Break>(ref(anchor, it));
-    }
-
-    SCOPES_RESULT(ValueRef) expand_repeat(const List *it) {
-        SCOPES_RESULT_TYPE(ValueRef);
-        SCOPES_CHECK_RESULT(verify_list_parameter_count("repeat", it, 0, -1));
-        auto anchor = it->at.anchor();
-        it = it->next;
-        return build_terminator<RepeatTemplate>(ref(anchor, it));
-    }
-
-    SCOPES_RESULT(ValueRef) expand_merge(const List *it) {
-        SCOPES_RESULT_TYPE(ValueRef);
-        SCOPES_CHECK_RESULT(verify_list_parameter_count("merge", it, 1, -1));
-        auto anchor = it->at.anchor();
-        it = it->next;
-
-        Expander subexp(Scope::from(env), astscope, it->next);
-        ValueRef label = SCOPES_GET_RESULT(subexp.expand(it->at));
-        it = subexp.next;
-
-        if (!label.isa<LabelTemplate>()) {
-            SCOPES_ERROR(SyntaxLabelExpected, label->kind());
-        }
-        return build_terminator<MergeTemplate>(ref(anchor, it),
-            label.cast<LabelTemplate>());
-    }
-
-    SCOPES_RESULT(ValueRef) expand_forward(const List *it) {
-        SCOPES_RESULT_TYPE(ValueRef);
-        SCOPES_CHECK_RESULT(verify_list_parameter_count("_", it, 0, -1));
-        auto anchor = it->at.anchor();
-        it = it->next;
-        Values args;
-        if (it) {
-            Expander subexp(env, astscope, it->next);
-            SCOPES_CHECK_RESULT(subexp.expand_arguments(args, it));
-        }
-        return ref(anchor, ArgumentListTemplate::from(args));
-    }
-
-    SCOPES_RESULT(ValueRef) expand_call(const List *it, uint32_t flags = 0) {
-        SCOPES_RESULT_TYPE(ValueRef);
-
-        SCOPES_CHECK_RESULT(verify_list_parameter_count("call", it, 0, -1));
-        auto anchor = it->at.anchor();
-        Expander subexp(env, astscope, it->next);
-        ValueRef enter = SCOPES_GET_RESULT(subexp.expand(it->at));
-
-        auto call = CallTemplate::from(enter);
-        call->flags = flags;
-        //call->set_def_anchor(anchor);
-
-        it = subexp.next;
-        SCOPES_CHECK_RESULT(subexp.expand_arguments(call->args, it));
-        return ValueRef(ref(anchor, call));
-    }
-
-    SCOPES_RESULT(sc_list_scope_tuple_t) expand_symbol(const ConstRef &node) {
-        SCOPES_RESULT_TYPE(sc_list_scope_tuple_t);
-        ValueRef symbol_handler_node;
-        if (env->lookup(Symbol(SYM_SymbolWildcard), symbol_handler_node)) {
-            auto T = try_get_const_type(symbol_handler_node);
-            if (T != list_expander_func_type) {
-                SCOPES_TRACE_HOOK(symbol_handler_node);
-                // symbol_handler_node.cast<TypedValue>()->get_type()
-                SCOPES_ERROR(SyntaxSymbolExpanderTypeMismatch, T,
-                    list_expander_func_type);
-            }
-            sc_syntax_wildcard_func_t f =
-                (sc_syntax_wildcard_func_t)symbol_handler_node.cast<ConstPointer>()->value;
-            auto ok_result = f(List::from(node, next), env);
-            if (!ok_result.ok) {
-                SCOPES_RETURN_ERROR(ok_result.except);
-            }
-            return ok_result._0;
-        }
-        sc_list_scope_tuple_t result = { nullptr, nullptr };
-        return result;
-    }
-
-    SCOPES_RESULT(ValueRef) expand(ValueRef anynode) {
-        SCOPES_RESULT_TYPE(ValueRef);
-        SCOPES_TRACE_EXPANDER(anynode);
-    expand_again:
-        SCOPES_CHECK_RESULT(verify_stack());
-        const Anchor *anchor = anynode.anchor();
-        if (!anynode.isa<Const>()) {
-            if (verbose) {
-                StyledStream ss(SCOPES_CERR);
-                ss << "ignoring " << anynode << std::endl;
-            }
-            // return as-is
-            return anynode;
-        }
-        ConstRef node = anynode.cast<Const>();
-        auto T = node->get_type();
-        if (T == TYPE_List) {
-            if (verbose) {
-                StyledStream ss(SCOPES_CERR);
-                ss << "expanding list " << node << std::endl;
-            }
-
-            const List *list = SCOPES_GET_RESULT(extract_list_constant(node));
-            if (list == EOL) {
-                // zero arguments
-                return ref(anchor, ArgumentListTemplate::from());
-            }
-
-            ValueRef head = list->at;
-
-            auto headT = try_get_const_type(head);
-            // resolve symbol
-            if (headT == TYPE_Symbol) {
-                ValueRef headnode;
-                if (env->lookup(
-                    SCOPES_GET_RESULT(extract_symbol_constant(head)), headnode)) {
-                    head = ref(head.anchor(), headnode);
-                    headT = try_get_const_type(head);
-                }
-            }
-
-            if (headT == TYPE_Builtin) {
-                Builtin func = SCOPES_GET_RESULT(extract_builtin_constant(head));
-                switch(func.value()) {
-                case FN_GetSyntaxScope:
-                    SCOPES_CHECK_RESULT(verify_list_parameter_count("this-scope", list, 0, 0));
-                    return ValueRef(ref(anchor, ConstPointer::scope_from(env)));
-                case KW_SyntaxLog: return SCOPES_GET_RESULT(expand_syntax_log(list));
-                case KW_Fn: return SCOPES_GET_RESULT(expand_fn(list, ExpandFnSetup()));
-                case KW_Inline: {
-                    ExpandFnSetup setup;
-                    setup.inlined = true;
-                    return SCOPES_GET_RESULT(expand_fn(list, setup));
-                }
-                case KW_RunStage: return SCOPES_GET_RESULT(expand_run_stage(list));
-                case KW_Let: return SCOPES_GET_RESULT(expand_let(list));
-                case KW_Loop: return SCOPES_GET_RESULT(expand_loop(list));
-                case KW_Try: return SCOPES_GET_RESULT(expand_try(list));
-                case KW_If: return SCOPES_GET_RESULT(expand_if(list));
-                case KW_Switch: return SCOPES_GET_RESULT(expand_switch(list));
-                case KW_SyntaxQuote: return SCOPES_GET_RESULT(expand_syntax_quote(list));
-                case KW_ASTQuote: return SCOPES_GET_RESULT(expand_ast_quote(list));
-                case KW_ASTUnquote: return SCOPES_GET_RESULT(expand_ast_unquote(list));
-                case KW_ASTUnquoteArguments: return SCOPES_GET_RESULT(expand_ast_unquote_arguments(list));
-                case KW_Return: return SCOPES_GET_RESULT(expand_return(list));
-                case KW_Raise: return SCOPES_GET_RESULT(expand_raise(list));
-                case KW_Break: return SCOPES_GET_RESULT(expand_break(list));
-                case KW_Repeat: return SCOPES_GET_RESULT(expand_repeat(list));
-                case KW_Merge: return SCOPES_GET_RESULT(expand_merge(list));
-                case KW_Forward: return SCOPES_GET_RESULT(expand_forward(list));
-                //case KW_Defer: return expand_defer(list);
-                case KW_Do: return SCOPES_GET_RESULT(expand_do(list));
-                case KW_DoIn: return SCOPES_GET_RESULT(expand_inline_do(list));
-                case KW_Label: return SCOPES_GET_RESULT(expand_label(list));
-                case KW_RawCall:
-                case KW_Call: {
-                    SCOPES_CHECK_RESULT(verify_list_parameter_count("special call", list, 1, -1));
-                    list = list->next;
-                    assert(list != EOL);
-                    uint32_t flags = 0;
-                    switch(func.value()) {
-                    case KW_RawCall: flags |= CF_RawCall; break;
-                    default: break;
-                    }
-                    return ValueRef(ref(anchor,
-                        SCOPES_GET_RESULT(expand_call(list, flags))));
-                } break;
-                default: break;
-                }
-            }
-
-            ValueRef list_handler_node;
-            if (env->lookup(Symbol(SYM_ListWildcard), list_handler_node)) {
-                auto T = try_get_const_type(list_handler_node);
-                if (T != list_expander_func_type) {
-                    SCOPES_TRACE_HOOK(list_handler_node);
-                    //list_handler_node.cast<TypedValue>()->get_type(),
-                    SCOPES_ERROR(SyntaxListExpanderTypeMismatch, T,
-                        list_expander_func_type);
-                }
-                sc_syntax_wildcard_func_t f =
-                    (sc_syntax_wildcard_func_t)list_handler_node.cast<ConstPointer>()->value;
-                auto ok_result = f(List::from(node, next), env);
-                if (!ok_result.ok) {
-                    SCOPES_RETURN_ERROR(ok_result.except);
-                }
-                auto result = ok_result._0;
-                if (result._0) {
-                    ValueRef newnode = result._0->at;
-                    if (newnode != node) {
-                        anynode = newnode;
-                        next = result._0->next;
-                        env = result._1;
-                        goto expand_again;
-                    } else if (verbose) {
-                        StyledStream ss(SCOPES_CERR);
-                        ss << "ignored by list handler" << std::endl;
-                    }
-                }
-            }
-            return ValueRef(ref(anchor, SCOPES_GET_RESULT(expand_call(list))));
-        } else if (T == TYPE_Symbol) {
-            if (verbose) {
-                StyledStream ss(SCOPES_CERR);
-                ss << "expanding symbol " << node << std::endl;
-            }
-
-            Symbol name = SCOPES_GET_RESULT(extract_symbol_constant(node));
-
-            ValueRef result;
-            if (!env->lookup(name, result)) {
-                sc_list_scope_tuple_t result = SCOPES_GET_RESULT(expand_symbol(node));
-                if (result._0) {
-                    ValueRef newnode = result._0->at;
-                    if (newnode != node) {
-                        anynode = newnode;
-                        next = result._0->next;
-                        env = result._1;
-                        goto expand_again;
-                    }
-                }
-
-                SCOPES_ERROR(SyntaxUndeclaredIdentifier, name, env);
-            }
-            return ref(anchor, result);
-        } else {
-            if (verbose) {
-                StyledStream ss(SCOPES_CERR);
-                ss << "ignoring " << node << std::endl;
-            }
-            return ValueRef(node);
-        }
-    }
-
-};
-
-bool Expander::verbose = false;
-const Type *Expander::list_expander_func_type = nullptr;
-
-SCOPES_RESULT(sc_valueref_list_scope_tuple_t) expand(const ValueRef &expr, const List *next, Scope *scope) {
-    SCOPES_RESULT_TYPE(sc_valueref_list_scope_tuple_t);
-    Scope *subenv = scope?scope:sc_get_globals();
-    Expander subexpr(subenv, TemplateRef(), next);
-    ValueRef value = SCOPES_GET_RESULT(subexpr.expand(expr));
-    sc_valueref_list_scope_tuple_t result = { value, subexpr.next, subexpr.env };
-    return result;
-}
-
-SCOPES_RESULT(TemplateRef) expand_inline(const Anchor *anchor, const TemplateRef &astscope, const List *expr, Scope *scope) {
-    SCOPES_RESULT_TYPE(TemplateRef);
-    Timer sum_expand_time(TIMER_Expand);
-    //const Anchor *anchor = expr->anchor();
-    //auto list = SCOPES_GET_RESULT(extract_list_constant(expr));
-    assert(anchor);
-    TemplateRef mainfunc = ref(anchor, Template::from(SYM_Unnamed));
-    mainfunc->set_inline();
-
-    Scope *subenv = scope?scope:sc_get_globals();
-    Expander subexpr(subenv, astscope);
-    mainfunc->value = SCOPES_GET_RESULT(subexpr.expand_expression(ref(anchor, expr), false));
-
-    return mainfunc;
-}
-
-SCOPES_RESULT(TemplateRef) expand_module(const Anchor *anchor, const List *expr, Scope *scope) {
-    SCOPES_RESULT_TYPE(TemplateRef);
-    Timer sum_expand_time(TIMER_Expand);
-    //const Anchor *anchor = expr->anchor();
-    //auto list = SCOPES_GET_RESULT(extract_list_constant(expr));
-    assert(anchor);
-    StyledString ss = StyledString::plain();
-    ss.out << anchor->path.name()->data << ":" << anchor->lineno;
-    TemplateRef mainfunc = ref(anchor, Template::from(Symbol(ss.str())));
-
-    Scope *subenv = scope?scope:sc_get_globals();
-    Expander subexpr(subenv, mainfunc);
-    mainfunc->value = SCOPES_GET_RESULT(subexpr.expand_expression(ref(anchor, expr), false));
-
-    return mainfunc;
-}
-
-} // namespace scopes

          
R src/expander.hpp =>  +0 -29
@@ 1,29 0,0 @@ 
-/*
-    The Scopes Compiler Infrastructure
-    This file is distributed under the MIT License.
-    See LICENSE.md for details.
-*/
-
-#ifndef SCOPES_EXPANDER_HPP
-#define SCOPES_EXPANDER_HPP
-
-#include "result.hpp"
-#include "symbol.hpp"
-#include "valueref.inc"
-#include "scopes/scopes.h"
-
-namespace scopes {
-
-struct Value;
-struct Scope;
-struct Anchor;
-struct Template;
-struct List;
-
-SCOPES_RESULT(sc_valueref_list_scope_tuple_t) expand(const ValueRef &expr, const List *next, Scope *scope = nullptr);
-SCOPES_RESULT(TemplateRef) expand_module(const Anchor *anchor, const List *expr, Scope *scope = nullptr);
-SCOPES_RESULT(TemplateRef) expand_inline(const Anchor *anchor, const TemplateRef &astscope, const List *expr, Scope *scope = nullptr);
-
-} // namespace scopes
-
-#endif // SCOPES_EXPANDER_HPP
  No newline at end of file

          
M src/globals.cpp +0 -2
@@ 6,7 6,6 @@ 
 
 #include "globals.hpp"
 #include "string.hpp"
-#include "list.hpp"
 #include "types.hpp"
 #include "qualifiers.hpp"
 #include "qualifier.inc"

          
@@ 18,7 17,6 @@ 
 #include "platform_abi.hpp"
 #include "source_file.hpp"
 #include "lexerparser.hpp"
-#include "expander.hpp"
 #include "gen_llvm.hpp"
 #include "gen_spirv.hpp"
 #include "anchor.hpp"

          
M src/lexerparser.cpp +12 -20
@@ 9,7 9,6 @@ 
 #include "source_file.hpp"
 #include "anchor.hpp"
 #include "type.hpp"
-#include "list.hpp"
 #include "value.hpp"
 #include "dyn_cast.inc"
 #include "globals.hpp"

          
@@ 711,36 710,29 @@ Any LexerParser::get() {
 //////////////////////////////
 
 LexerParser::ListBuilder::ListBuilder(LexerParser &_lexer) :
-    lexer(_lexer),
-    prev(EOL),
-    eol(EOL) {}
+    lexer(_lexer) {
+}
 
 void LexerParser::ListBuilder::append(ValueRef value) {
-    prev = List::from(value, prev);
+    current.push_back(value);
 }
 
 bool LexerParser::ListBuilder::is_empty() const {
-    return (prev == EOL);
-}
-
-bool LexerParser::ListBuilder::is_expression_empty() const {
-    return (prev == EOL);
-}
-
-void LexerParser::ListBuilder::reset_start() {
-    eol = prev;
+    return current.empty() && values.empty();
 }
 
 void LexerParser::ListBuilder::split(const Anchor *anchor) {
-    // reverse what we have, up to last split point and wrap result
-    // in cell
-    prev = List::from(ref(anchor,
-        ConstPointer::list_from(reverse_list(prev, eol))), eol);
-    reset_start();
+    // wrap from last split point into cell
+    values.push_back(ref(anchor, SymList::from(current)));
+    current.clear();
 }
 
 const List *LexerParser::ListBuilder::get_result() {
-    return reverse_list(prev);
+    for (auto &&val : current) {
+        values.push_back(current);
+    }
+    current.clear();
+    return SymList::from(values);
 }
 
 //////////////////////////////

          
M src/lexerparser.hpp +5 -4
@@ 11,6 11,7 @@ 
 #include "valueref.inc"
 
 #include <stddef.h>
+#include <vector>
 
 namespace scopes {
 

          
@@ 60,8 61,8 @@ const char TOKEN_TERMINATORS[] = "()[]{}
 struct LexerParser {
     struct ListBuilder {
         LexerParser &lexer;
-        const List *prev;
-        const List *eol;
+        std::vector<ValueRef> current;
+        std::vector<ValueRef> values;
 
         ListBuilder(LexerParser &_lexer);
 

          
@@ 69,9 70,9 @@ struct LexerParser {
 
         bool is_empty() const;
 
-        bool is_expression_empty() const;
+        //bool is_expression_empty() const;
 
-        void reset_start();
+        //void reset_start();
 
         void split(const Anchor *anchor);
 

          
R src/list.cpp =>  +0 -117
@@ 1,117 0,0 @@ 
-/*
-    The Scopes Compiler Infrastructure
-    This file is distributed under the MIT License.
-    See LICENSE.md for details.
-*/
-
-#include "list.hpp"
-#include "hash.hpp"
-#include "value.hpp"
-#include "error.hpp"
-#include "globals.hpp"
-
-#include <unordered_set>
-
-namespace scopes {
-
-//------------------------------------------------------------------------------
-// LIST
-//------------------------------------------------------------------------------
-
-bool List::KeyEqual::operator()( const List *lhs, const List *rhs ) const {
-    if (lhs->next != rhs->next)
-        return false;
-    return lhs->at == rhs->at;
-}
-
-std::size_t List::Hash::operator()(const List *l) const {
-    return hash2(
-        hash2(
-            std::hash<const Anchor *>{}(l->at.anchor()),
-            std::hash<Value *>{}(l->at.unref())
-        ), std::hash<const List *>{}(l->next));
-}
-
-static std::unordered_set<const List *, List::Hash, List::KeyEqual> list_map;
-
-List::List(const ValueRef &_at, const List *_next, size_t count) :
-    at(_at),
-    next(_next),
-    _count(count) {}
-
-ValueRef List::first() const {
-    if (this == EOL) {
-        return g_none;
-    } else {
-        return at;
-    }
-}
-
-const List *List::from(const ValueRef &_at, const List *_next) {
-    List list(_at, _next, 0);
-    auto it = list_map.find(&list);
-    if (it != list_map.end()) {
-        return *it;
-    }
-    const List *l = new List(_at, _next, (_next != EOL)?(List::count(_next) + 1):1);
-    list_map.insert(l);
-    return l;
-}
-
-size_t List::count(const List *l) {
-    return l?l->_count:0;
-}
-
-const List *List::from(ValueRef const *values, int N) {
-    const List *list = EOL;
-    for (int i = N - 1; i >= 0; --i) {
-        list = from(values[i], list);
-    }
-    return list;
-}
-
-const List *List::join(const List *la, const List *lb) {
-    const List *l = lb;
-    while (la != EOL) {
-        l = List::from(la->at, l);
-        la = la->next;
-    }
-    //return reverse_list_inplace(l, lb, lb);
-    return reverse_list(l, lb, lb);
-}
-
-//------------------------------------------------------------------------------
-
-#if 0
-// (a . (b . (c . (d . NIL)))) -> (d . (c . (b . (a . NIL))))
-// this is the mutating version; input lists are modified, direction is inverted
-const List *reverse_list_inplace(
-    const List *l, const List *eol, const List *cat_to) {
-    const List *next = cat_to;
-    size_t count = 0;
-    if (cat_to != EOL) {
-        count = cat_to->count;
-    }
-    while (l != eol) {
-        count = count + 1;
-        const List *iternext = l->next;
-        const_cast<List *>(l)->next = next;
-        const_cast<List *>(l)->count = count;
-        next = l;
-        l = iternext;
-    }
-    return next;
-}
-#endif
-
-const List *reverse_list(
-    const List *l, const List *eol, const List *cat_to) {
-    const List *next = cat_to;
-    while (l != eol) {
-        next = List::from(l->at, next);
-        l = l->next;
-    }
-    return next;
-}
-
-} // namespace scopes

          
R src/list.hpp =>  +0 -90
@@ 1,90 0,0 @@ 
-/*
-    The Scopes Compiler Infrastructure
-    This file is distributed under the MIT License.
-    See LICENSE.md for details.
-*/
-
-#ifndef SCOPES_LIST_HPP
-#define SCOPES_LIST_HPP
-
-#include "valueref.inc"
-
-#include <stddef.h>
-#include <cstddef>
-
-namespace scopes {
-
-struct Value;
-
-//------------------------------------------------------------------------------
-// LIST
-//------------------------------------------------------------------------------
-
-struct List {
-protected:
-    List(const ValueRef &_at, const List *_next, size_t _count);
-
-public:
-    static size_t count(const List *l);
-
-    ValueRef first() const;
-
-    static const List *from(const ValueRef &_at, const List *_next);
-
-    static const List *from(ValueRef const *values, int N);
-
-
-    static inline const List *from(const ValueRef &v0, const ValueRef &v1) {
-        ValueRef values[] = { v0, v1 }; return from(values, 2); }
-
-    template<unsigned N>
-    static const List *from(ValueRef const (&values)[N]) {
-        return from(values, N);
-    }
-
-    static const List *from_arglist() {
-        return nullptr;
-    }
-
-    static const List *from_arglist(const ValueRef &last) {
-        return from(last, nullptr);
-    }
-
-    template<class ... Args>
-    static const List *from_arglist(const ValueRef &first, Args ... args) {
-        return from(first, from_arglist(args ...));
-    }
-
-    static const List *join(const List *a, const List *b);
-
-    // these only work with lists that aren't EOL
-
-    struct KeyEqual {
-        bool operator()( const List *lhs, const List *rhs ) const;
-    };
-
-    struct Hash {
-        std::size_t operator()(const List *l) const;
-    };
-
-public:
-    ValueRef at;
-    const List *next;
-protected:
-    size_t _count;
-};
-
-const List * const EOL = nullptr;
-
-#if 0
-// (a . (b . (c . (d . NIL)))) -> (d . (c . (b . (a . NIL))))
-// this is the mutating version; input lists are modified, direction is inverted
-const List *reverse_list_inplace(
-    const List *l, const List *eol = EOL, const List *cat_to = EOL);
-#endif
-const List *reverse_list(
-    const List *l, const List *eol = EOL, const List *cat_to = EOL);
-
-} // namespace scopes
-
-#endif // SCOPES_LIST_HPP
  No newline at end of file

          
M src/prover.cpp +2 -6
@@ 18,8 18,6 @@ 
 #include "dyn_cast.inc"
 #include "compiler_flags.hpp"
 #include "gen_llvm.hpp"
-#include "list.hpp"
-#include "expander.hpp"
 #include "globals.hpp"
 #include "quote.hpp"
 #include "anchor.hpp"

          
@@ 1442,10 1440,8 @@ SCOPES_RESULT(sc_ast_macro_func_t) extra
     return (sc_ast_macro_func_t)x->value;
 }
 
-SCOPES_RESULT(const List *) extract_list_constant(const ValueRef &value) {
-    SCOPES_RESULT_TYPE(const List *);
-    ConstPointerRef x = SCOPES_GET_RESULT(extract_typed_constant<ConstPointer>(TYPE_List, value));
-    return (const List *)x->value;
+SCOPES_RESULT(SymListRef) extract_symlist_constant(const ValueRef &value) {
+    return extract_constant<SymList, VK_SymList>(value);
 }
 
 SCOPES_RESULT(const String *) extract_string_constant(const ValueRef &value) {

          
M src/prover.hpp +1 -1
@@ 56,7 56,7 @@ struct ASTContext {
 
 SCOPES_RESULT(const Type *) extract_type_constant(const ValueRef &value);
 SCOPES_RESULT(const Closure *) extract_closure_constant(const ValueRef &value);
-SCOPES_RESULT(const List *) extract_list_constant(const ValueRef &value);
+SCOPES_RESULT(SymListRef) extract_symlist_constant(const ValueRef &value);
 SCOPES_RESULT(const String *) extract_string_constant(const ValueRef &value);
 SCOPES_RESULT(Builtin) extract_builtin_constant(const ValueRef &value);
 SCOPES_RESULT(Symbol) extract_symbol_constant(const ValueRef &value);

          
M src/stream_expr.cpp +0 -1
@@ 5,7 5,6 @@ 
 */
 
 #include "stream_expr.hpp"
-#include "list.hpp"
 #include "anchor.hpp"
 #include "value.hpp"
 #include "prover.hpp"

          
M src/type.cpp +0 -1
@@ 8,7 8,6 @@ 
 #include "error.hpp"
 #include "gc.hpp"
 #include "anchor.hpp"
-#include "list.hpp"
 #include "hash.hpp"
 #include "type/qualify_type.hpp"
 #include "dyn_cast.inc"

          
M src/type.hpp +0 -1
@@ 131,7 131,6 @@ typedef std::vector<const Type *> Types;
     T(TYPE_F64, "f64") \
     T(TYPE_F80, "f80") \
     \
-    T(TYPE_List, "list") \
     T(TYPE_Anchor, "Anchor") \
     T(TYPE_String, "string") \
     \

          
M src/value.cpp +79 -34
@@ 56,6 56,37 @@ SCOPES_DEFINED_VALUES()
 
 //------------------------------------------------------------------------------
 
+template<typename T>
+struct ConstSet {
+    struct Hash {
+        std::size_t operator()(const T *k) const {
+            return k->hash();
+        }
+    };
+
+    struct Equal {
+        std::size_t operator()(const T *self, const T *other) const {
+            return self->key_equal(other);
+        }
+    };
+
+    std::unordered_set<T *, Hash, Equal> map;
+
+    template<typename ... Args>
+    TValueRef<T> from(Args ... args) {
+        T key(args ...);
+        auto it = map.find(&key);
+        if (it != map.end()) {
+            return ref(unknown_anchor(), *it);
+        }
+        auto val = new T(args ...);
+        map.insert(val);
+        return ref(unknown_anchor(), val);
+    }
+};
+
+//------------------------------------------------------------------------------
+
 std::size_t ValueIndex::Hash::operator()(const ValueIndex & s) const {
     return hash2(std::hash<Value *>{}(s.value.unref()), s.index);
 }

          
@@ 144,6 175,51 @@ TypedValueRef Keyed::from(Symbol key, Ty
 
 //------------------------------------------------------------------------------
 
+ConstSet<SymList> symbolic_lists;
+
+SymList::SymList(const Values &values)
+    : UntypedValue(VK_SymList), _values(values) {
+}
+
+bool SymList::key_equal(const SymList *other) const {
+    auto sz = _values.size();
+    if (sz != other->_values.size())
+        return false;
+    for (int i = 0; i < sz; ++i) {
+        auto &&a = _values[i];
+        auto &&b = other->_values[i];
+        if (a != b)
+            return false;
+    }
+    return true;
+}
+
+std::size_t SymList::hash() const {
+    uint64_t h = 0;
+    for (auto &&value : _values) {
+        if (value.isa<Pure>()) {
+            h = hash2(h, value.cast<Pure>()->hash());
+        } else {
+            h = hash2(h,
+                    hash2(
+                        std::hash<const Anchor *>{}(value.anchor()),
+                        std::hash<Value *>{}(value.unref())
+                    ));
+        }
+    }
+    return h;
+}
+
+bool SymList::empty() const {
+    return _values.empty();
+}
+
+SymListRef SymList::from(const Values &values) {
+    return symbolic_lists.from(type, value);
+}
+
+//------------------------------------------------------------------------------
+
 // when joining two argument lists, all but the last argument can be flattened
 
 ArgumentListTemplate::ArgumentListTemplate(const Values &values)

          
@@ 265,7 341,7 @@ bool ArgumentList::is_constant() const {
 TypedValueRef ArgumentList::from(const TypedValues &values) {
     if (values.size() == 0) {
         if (!_empty_argument_list)
-            _empty_argument_list = ref(unknown_anchor(), new ArgumentList(values)); 
+            _empty_argument_list = ref(unknown_anchor(), new ArgumentList(values));
         return _empty_argument_list;
     } else if (values.size() == 1) {
         return values[0];

          
@@ 315,7 391,7 @@ ValueRef ExtractArgumentTemplate::from(
                 goto repeat;
             }
         }
-    } else if (!vararg && value.isa<ExtractArgumentTemplate>()) {      
+    } else if (!vararg && value.isa<ExtractArgumentTemplate>()) {
         auto eat = value.cast<ExtractArgumentTemplate>();
         if (eat->vararg) {
             value = eat->value;

          
@@ 327,7 403,7 @@ ValueRef ExtractArgumentTemplate::from(
             return ref(value.anchor(), ConstAggregate::none_from());
         }
     }
-    */ 
+    */
     return ref(value.anchor(),
         new ExtractArgumentTemplate(value, index, vararg));
 }

          
@@ 1217,37 1293,6 @@ Const::Const(ValueKind _kind, const Type
 
 //------------------------------------------------------------------------------
 
-template<typename T>
-struct ConstSet {
-    struct Hash {
-        std::size_t operator()(const T *k) const {
-            return k->hash();
-        }
-    };
-
-    struct Equal {
-        std::size_t operator()(const T *self, const T *other) const {
-            return self->key_equal(other);
-        }
-    };
-
-    std::unordered_set<T *, Hash, Equal> map;
-
-    template<typename ... Args>
-    TValueRef<T> from(Args ... args) {
-        T key(args ...);
-        auto it = map.find(&key);
-        if (it != map.end()) {
-            return ref(unknown_anchor(), *it);
-        }
-        auto val = new T(args ...);
-        map.insert(val);
-        return ref(unknown_anchor(), val);
-    }
-};
-
-//------------------------------------------------------------------------------
-
 static ConstSet<ConstInt> constints;
 
 ConstInt::ConstInt(const Type *type, uint64_t _value)

          
M src/value.hpp +22 -0
@@ 194,6 194,28 @@ struct Keyed : TypedValue {
 
 //------------------------------------------------------------------------------
 
+struct SymList : UntypedValue {
+    static bool classof(const Value *T);
+
+    SymList(const Values &values);
+
+    //bool is_constant() const;
+    bool empty() const;
+
+    bool key_equal(const SymList *other) const;
+    std::size_t hash() const;
+
+    //static ValueRef empty_from();
+    static SymListRef from(const Values &values = {});
+
+    const Values &values() const;
+
+protected:
+    Values _values;
+};
+
+//------------------------------------------------------------------------------
+
 struct ArgumentListTemplate : UntypedValue {
     static bool classof(const Value *T);
 

          
M src/value_kind.hpp +1 -0
@@ 27,6 27,7 @@ namespace scopes {
     T(VK_ReturnTemplate, "value-kind-return-template", ReturnTemplate) \
     T(VK_RaiseTemplate, "value-kind-raise-template", RaiseTemplate) \
     T(VK_Break, "value-kind-break", Break) \
+    T(VK_SymList, "value-kind-symbolic-list", SymList) \
     T(VK_ArgumentListTemplate, "value-kind-argument-list-template", ArgumentListTemplate) \
     T(VK_ExtractArgumentTemplate, "value-kind-extract-argument-template", ExtractArgumentTemplate) \
     T(VK_ParameterTemplate, "value-kind-parameter-template", ParameterTemplate) \