Index: doc/theses/andrew_beach_MMath/features.tex
===================================================================
--- doc/theses/andrew_beach_MMath/features.tex	(revision 21255675538be8803fefa8e055131729c60a99ab)
+++ doc/theses/andrew_beach_MMath/features.tex	(revision 21255675538be8803fefa8e055131729c60a99ab)
@@ -0,0 +1,307 @@
+\chapter{Features}
+
+This chapter covers the design and user interface of the \CFA exception
+handling mechanism.
+
+\section{Virtual Casts}
+
+Virtual casts and virtual types are not truly part of the exception system but
+they did not exist in \CFA and are useful in exceptions. So a minimal version
+of they virtual system was designed and implemented.
+
+Virtual types are organizied in simple hierarchies. Each virtual type may have
+a parent and can have any number of children. A type's descendants are its
+children and its children's descendants. A type may not be its own descendant.
+
+Each virtual type has an associated virtual table type. A virtual table is a
+structure that has fields for all the virtual members of a type. A virtual
+type has all the virtual members of its parent and can add more. It may also
+update the values of the virtual members.
+
+Except for virtual casts, this is only used internally in the exception
+system. There is no general purpose interface for the other features. A
+a virtual cast has the following syntax:
+
+\begin{lstlisting}
+(virtual TYPE)EXPRESSION
+\end{lstlisting}
+
+This has the same precidence as a traditional C-cast and can be used in the
+same places. This will convert the result of EXPRESSION to the type TYPE. Both
+the type of EXPRESSION and TYPE must be pointers to virtual types.
+
+The cast is checked and will either return the original value or null, based
+on the result of the check. The check is does the object pointed at have a
+type that is a descendant of the target type. If it is the result is the
+pointer, otherwise the result is null.
+
+\section{Exceptions}
+% Leaving until later, hopefully it can talk about actual syntax instead
+% of my many strange macros. Syntax aside I will also have to talk about the
+% features all exceptions support.
+
+\section{Termination}
+
+Termination exception throws are likely the most framilar kind, as they are
+used in several popular programming languages. A termination will throw an
+exception, search the stack for a handler, unwind the stack to where the
+handler is defined, execute the handler and then continue execution after
+the handler. They are used when execution cannot continue here.
+
+Termination has two pieces of syntax it uses. The first is the throw:
+\begin{lstlisting}
+throw EXPRESSION;
+\end{lstlisting}
+
+The expression must evaluate to a reference to a termination exception. A
+termination exception is any exception with a
+\codeCFA{void defaultTerminationHandler(T &);} (the default handler) defined
+on it. The handler is taken from the call sight with \CFA's trait system and
+passed into the exception system along with the exception itself.
+
+The exception passed into the system is then copied into managed memory.
+This is to ensure it remains in scope during unwinding. It is the user's
+responsibility to make sure the original exception is freed when it goes out
+of scope. Being allocated on the stack is sufficient for this.
+
+Then the exception system will search the stack starting from the throw and
+proceding towards the base of the stack, from callee to caller. As it goes
+it will check any termination handlers it finds:
+
+\begin{lstlisting}
+try {
+    TRY_BLOCK
+} catch (EXCEPTION_TYPE * NAME) {
+    HANDLER
+}
+\end{lstlisting}
+
+This shows a try statement with a single termination handler. The statements
+in TRY\_BLOCK will be executed when control reaches this statement. While
+those statements are being executed if a termination exception is thrown and
+it is not handled by a try statement further up the stack the EHM will check
+all of the terminations handlers attached to the try block, top to bottom.
+
+At each handler the EHM will check to see if the thrown exception is a
+descendant of EXCEPTION\_TYPE. If it is the pointer to the exception is
+bound to NAME and the statements in HANDLER are executed. If control reaches
+the end of the handler then it exits the block, the exception is freed and
+control continues after the try statement.
+
+The default handler is only used if no handler for the exception is found
+after the entire stack is searched. When that happens the default handler
+is called with a reference to the exception as its only argument. If the
+handler returns control continues from after the throw statement.
+
+\paragraph{Conditional Catches}
+
+Catch clauses may also be written as:
+\begin{lstlisting}
+catch (EXCEPTION_TYPE * NAME ; CONDITION)
+\end{lstlisting}
+This has the same behaviour as a regular catch clause except that if the
+exception matches the given type the condition is also run. If the result is
+true only then is this considered a matching handler. If the result is false
+then the handler does not match and the search continues with the next clause
+in the try block.
+
+The condition considers all names in scope at the beginning of the try block
+to be in scope along with the name introduce in the catch clause itself.
+
+\paragraph{Re-Throwing}
+
+You can also rethrow the most recent termination exception with
+\codeCFA{throw;}. % This is terrible and you should never do it.
+This can be done in a handler or any function that could be called from a
+handler.
+
+This will start another termination throw reusing the exception, meaning it
+does not copy the exception or allocated any more memory for it. However the
+default handler is still at the original through and could refer to data that
+was on the unwound section of the stack. So instead a new default handler that
+does a program level abort is used.
+
+\section{Resumption}
+
+Resumption exceptions are less popular then termination but in many
+regards are simpler and easier to understand. A resumption throws an exception,
+searches for a handler on the stack, executes that handler on top of the stack
+and then continues execution from the throw. These are used when a problem
+needs to be fixed before execution continues.
+
+A resumption is thrown with a throw resume statement:
+\begin{lstlisting}
+throwResume EXPRESSION;
+\end{lstlisting}
+The result of EXPRESSION must be a resumption exception type. A resumption
+exception type is any type that satifies the assertion
+\codeCFA{void defaultResumptionHandler(T &);} (the default handler). When the
+statement is executed the expression is evaluated and the result is thrown.
+
+Handlers are declared using clauses in try statements:
+\begin{lstlisting}
+try {
+    TRY_BLOCK
+} catchResume (EXCEPTION_TYPE * NAME) {
+    HANDLER
+}
+\end{lstlisting}
+This is a simple example with the try block and a single resumption handler.
+Multiple resumption handlers can be put in a try statement and they can be
+mixed with termination handlers.
+
+When a resumption begins it will start searching the stack starting from
+the throw statement and working its way to the callers. In each try statement
+handlers will be tried top to bottom. Each handler is checked by seeing if
+the thrown exception is a descendant of EXCEPTION\_TYPE. If not the search
+continues. Otherwise NAME is bound to a pointer to the exception and the
+HANDLER statements are executed. After they are finished executing control
+continues from the throw statement.
+
+If no approprate handler is found then the default handler is called. The
+throw statement acts as a regular function call passing the exception to
+the default handler and after the handler finishes executing control continues
+from the throw statement.
+
+The exception system also tracks the position of a search on the stack. If
+another resumption exception is thrown while a resumption handler is running
+it will first check handlers pushed to the stack by the handler and any
+functions it called, then it will continue from the try statement that the
+handler is a part of; except for the default handler where it continues from
+the throw the default handler was passed to.
+
+This makes the search pattern for resumption reflect the one for termination,
+which is what most users expect.
+
+% This might need a diagram. But it is an important part of the justifaction
+% of the design of the traversal order.
+It also avoids the recursive resumption problem. If the entire stack is
+searched loops of resumption can form. Consider a handler that handles an
+exception of type A by resuming an exception of type B and on the same stack,
+later in the search path, is a second handler that handles B by resuming A.
+
+Assuming no other handlers on the stack handle A or B then in either traversal
+system an A resumed from the top of the stack will be handled by the first
+handler. A B resumed from the top or from the first handler it will be handled
+by the second hander. The only difference is when A is thrown from the second
+handler. The entire stack search will call the first handler again, creating a
+loop. Starting from the position in the stack though will break this loop.
+
+\paragraph{Conditional Catches}
+
+Resumption supports conditional catch clauses like termination does. They
+use the same syntax except the keyword is changed:
+\begin{lstlisting}
+catchResume (EXCEPTION_TYPE * NAME ; CONDITION)  
+\end{lstlisting}
+
+It also has the same behaviour, after the exception type has been matched
+with the EXCEPTION\_TYPE the CONDITION is evaluated with NAME in scope. If
+the result is true then the hander is run, otherwise the search continues
+just as if there had been a type mismatch.
+
+\paragraph{Re-Throwing}
+
+You may also re-throw resumptions with a \codeCFA{throwResume;} statement.
+This can only be done from inside of a \codeCFA{catchResume} block.
+
+Outside of any side effects of any code already run in the handler this will
+have the same effect as if the exception had not been caught in the first
+place.
+
+\section{Finally Clauses}
+
+A \codeCFA{finally} clause may be placed at the end of a try statement after
+all the handler clauses. In the simply case, with no handlers, it looks like
+this:
+
+\begin{lstlisting}
+try {
+    TRY_BLOCK
+} finally {
+    FINAL_STATEMENTS
+}
+\end{lstlisting}
+
+Any number of termination handlers and resumption handlers may proceed the
+finally clause.
+
+The FINAL\_STATEMENTS, the finally block, are executed whenever the try
+statement is removed from the stack. This includes: the TRY\_BLOCK finishes
+executing, a termination exception finishes executing and the stack unwinds.
+
+Execution of the finally block should finish by letting control run off
+the end of the block. This is because after the finally block is complete
+control will continue to where ever it would if the finally clause was not
+present.
+
+Because of this local control flow out of the finally block is forbidden.
+The compiler rejects uses of \codeCFA{break}, \codeCFA{continue},
+\codeCFA{fallthru} and \codeCFA{return} that would cause control to leave
+the finally block. Other ways to leave the finally block - such as a long
+jump or termination - are much harder to check, at best requiring additional
+runtime overhead, and so are merely discouraged.
+
+\section{Cancellation}
+
+Cancellation can be thought of as a stack-level abort or as an uncatchable
+termination. It unwinds the entirety of the current exception and if possible
+passes an exception to a different stack as a message.
+
+There is no special statement for starting a cancellation, instead you call
+the standard libary function \codeCFA{cancel\_stack} which takes an exception.
+Unlike in a throw this exception is not used in control flow but is just there
+to pass information about why the cancellation happened.
+
+The handler is decided entirely by which stack is being cancelled. There are
+three handlers that apply to three different groups of stacks:
+\begin{itemize}
+\item Main Stack:
+The main stack is the one on which the program main is called at the beginning
+of your program. It is also the only stack you have without the libcfathreads.
+
+Because of this there is no other stack ``above" (or possibly at all) for main
+to notify when a cancellation occurs. So after the stack is unwound we do a
+program level abort.
+
+\item Thread Stack:
+Thread stacks are those created \codeCFA{thread} or otherwise satify the
+\codeCFA{is\_thread} trait.
+
+Threads only have two structural points of communication that must happen,
+start and join. As the thread must be running to preform a cancellation it
+will be after start and before join, so join is one cancellation uses.
+
+After the stack is unwound the thread will halt as if had completed normally
+and wait for another thread to join with it. The other thread, when it joins,
+checks for a cancellation. If so it will throw the resumption exception
+\codeCFA{ThreadCancelled}.
+
+There is a difference here in how explicate joins (with the \codeCFA{join}
+function) and implicate joins (from a destructor call). Explicate joins will
+take the default handler (\codeCFA{defaultResumptionHandler}) from the context
+and use like a regular through does if the exception is not caught. The
+implicate join does a program abort instead.
+
+This is for safety. One of the big problems in exceptions is you cannot handle
+two terminations or cancellations on the same stack as either can destroy the
+context required for the other. This can happen with join but as the
+destructors will always be run when the stack is being unwound and one
+termination/cancellation is already active. Also since they are implicite they
+are easier to forget about.
+
+\item Coroutine Stack:
+Coroutine stacks are those created with \codeCFA{coroutine} or otherwise
+satify the \codeCFA{is\_coroutine} trait.
+
+A coroutine knows of two other coroutines, its starter and its last resumer.
+The last resumer is ``closer" so that is the one notified.
+
+After the stack is unwound control goes to the last resumer.
+Resume will resume throw a \codeCFA{CoroutineCancelled} exception, which is
+polymorphic over the coroutine type and has a pointer to the coroutine being
+cancelled and the cancelling exception. The resume function also has an
+assertion that the \codeCFA{defaultResumptionHandler} for the exception. So it
+will use the default handler like a regular throw.
+
+\end{itemize}
Index: libcfa/src/concurrency/kernel/fwd.hfa
===================================================================
--- libcfa/src/concurrency/kernel/fwd.hfa	(revision 6a8882c5d95c78ede2d214a855c752147cb22cd9)
+++ libcfa/src/concurrency/kernel/fwd.hfa	(revision 21255675538be8803fefa8e055131729c60a99ab)
@@ -65,8 +65,5 @@
 
 		extern uintptr_t __cfatls_get( unsigned long int member );
-		// #define publicTLS_get( member ) ((typeof(__cfaabi_tls.member))__cfatls_get( __builtin_offsetof(KernelThreadData, member) ))
-		#define publicTLS_get( member ) (__cfaabi_tls.member)
-		// extern forall(otype T) T __cfatls_get( T * member, T value );
-		// #define publicTLS_set( member, value ) __cfatls_set( (typeof(member)*)__builtin_offsetof(KernelThreadData, member), value );
+		#define publicTLS_get( member ) ((typeof(__cfaabi_tls.member))__cfatls_get( __builtin_offsetof(KernelThreadData, member) ))
 
 		static inline uint64_t __tls_rand() {
Index: libcfa/src/concurrency/preemption.cfa
===================================================================
--- libcfa/src/concurrency/preemption.cfa	(revision 6a8882c5d95c78ede2d214a855c752147cb22cd9)
+++ libcfa/src/concurrency/preemption.cfa	(revision 21255675538be8803fefa8e055131729c60a99ab)
@@ -231,8 +231,21 @@
 }
 
+struct asm_region {
+	void * before;
+	void * after;
+};
+
+static inline bool __cfaasm_in( void * ip, struct asm_region & region ) {
+	return ip >= region.before && ip <= region.after;
+}
+
+
 //----------
 // Get data from the TLS block
+// struct asm_region __cfaasm_get;
 uintptr_t __cfatls_get( unsigned long int offset ) __attribute__((__noinline__)); //no inline to avoid problems
 uintptr_t __cfatls_get( unsigned long int offset ) {
+	// __cfaasm_get.before = ({ void * value; asm("movq $__cfaasm_get_before, %[v]\n\t" : [v]"=r"(value) ); value; });
+	// __cfaasm_get.after  = ({ void * value; asm("movq $__cfaasm_get_after , %[v]\n\t" : [v]"=r"(value) ); value; });
 	// create a assembler label before
 	// marked as clobber all to avoid movement
@@ -253,5 +266,5 @@
 		// create a assembler label before
 		// marked as clobber all to avoid movement
-		asm volatile("__cfaasm_disable_before:":::"memory");
+		asm volatile("__cfaasm_dsable_before:":::"memory");
 
 		with( __cfaabi_tls.preemption_state ) {
@@ -275,5 +288,5 @@
 		// create a assembler label after
 		// marked as clobber all to avoid movement
-		asm volatile("__cfaasm_disable_after:":::"memory");
+		asm volatile("__cfaasm_dsable_after:":::"memory");
 	}
 
@@ -283,5 +296,5 @@
 		// create a assembler label before
 		// marked as clobber all to avoid movement
-		asm volatile("__cfaasm_enable_before:":::"memory");
+		asm volatile("__cfaasm_enble_before:":::"memory");
 
 		processor   * proc = __cfaabi_tls.this_processor; // Cache the processor now since interrupts can start happening after the atomic store
@@ -318,5 +331,5 @@
 		// create a assembler label after
 		// marked as clobber all to avoid movement
-		asm volatile("__cfaasm_enable_after:":::"memory");
+		asm volatile("__cfaasm_enble_after:":::"memory");
 	}
 
@@ -386,12 +399,92 @@
 }
 
+//-----------------------------------------------------------------------------
+// Some assembly required
+#if defined( __i386 )
+	#ifdef __PIC__
+		#define RELOC_PRELUDE( label ) \
+			"calll   .Lcfaasm_prelude_" #label "$pb\n\t" \
+			".Lcfaasm_prelude_" #label "$pb:\n\t" \
+			"popl    %%eax\n\t" \
+			".Lcfaasm_prelude_" #label "_end:\n\t" \
+			"addl    $_GLOBAL_OFFSET_TABLE_+(.Lcfaasm_prelude_" #label "_end-.Lcfaasm_prelude_" #label "$pb), %%eax\n\t"
+		#define RELOC_PREFIX ""
+		#define RELOC_SUFFIX "@GOT(%%eax)"
+	#else
+		#define RELOC_PREFIX "$"
+		#define RELOC_SUFFIX ""
+	#endif
+	#define __cfaasm_label( label ) static struct asm_region label = \
+		({ \
+			struct asm_region region; \
+			asm( \
+				RELOC_PRELUDE( label ) \
+				"movl " RELOC_PREFIX "__cfaasm_" #label "_before" RELOC_SUFFIX ", %[vb]\n\t" \
+				"movl " RELOC_PREFIX "__cfaasm_" #label "_after"  RELOC_SUFFIX ", %[va]\n\t" \
+				 : [vb]"=r"(region.before), [va]"=r"(region.after) \
+			); \
+			region; \
+		});
+#elif defined( __x86_64 )
+	#ifdef __PIC__
+		#define RELOC_PREFIX ""
+		#define RELOC_SUFFIX "@GOTPCREL(%%rip)"
+	#else
+		#define RELOC_PREFIX "$"
+		#define RELOC_SUFFIX ""
+	#endif
+	#define __cfaasm_label( label ) static struct asm_region label = \
+		({ \
+			struct asm_region region; \
+			asm( \
+				"movq " RELOC_PREFIX "__cfaasm_" #label "_before" RELOC_SUFFIX ", %[vb]\n\t" \
+				"movq " RELOC_PREFIX "__cfaasm_" #label "_after"  RELOC_SUFFIX ", %[va]\n\t" \
+				 : [vb]"=r"(region.before), [va]"=r"(region.after) \
+			); \
+			region; \
+		});
+#elif defined( __aarch64__ )
+	#ifdef __PIC__
+		#define RELOC_TAG "@PLT"
+	#else
+		#define RELOC_TAG ""
+	#endif
+	#define __cfaasm_label( label ) \
+		({ \
+			struct asm_region region; \
+			asm( \
+				"mov %[vb], __cfaasm_" #label "_before@GOTPCREL(%%rip)"  "\n\t" \
+				"mov %[va], __cfaasm_" #label "_after@GOTPCREL(%%rip)"   "\n\t" \
+				 : [vb]"=r"(region.before), [va]"=r"(region.after) \
+			); \
+			region; \
+		});
+#else
+	#error unknown hardware architecture
+#endif
+
 // KERNEL ONLY
 // Check if a __cfactx_switch signal handler shoud defer
 // If true  : preemption is safe
 // If false : preemption is unsafe and marked as pending
-static inline bool preemption_ready() {
+static inline bool preemption_ready( void * ip ) {
+	// Get all the region for which it is not safe to preempt
+	__cfaasm_label( get    );
+	__cfaasm_label( check  );
+	__cfaasm_label( dsable );
+	__cfaasm_label( enble );
+	__cfaasm_label( nopoll );
+
 	// Check if preemption is safe
-	bool ready = __cfaabi_tls.preemption_state.enabled && ! __cfaabi_tls.preemption_state.in_progress;
-
+	bool ready = true;
+	if( __cfaasm_in( ip, get    ) ) { ready = false; goto EXIT; };
+	if( __cfaasm_in( ip, check  ) ) { ready = false; goto EXIT; };
+	if( __cfaasm_in( ip, dsable ) ) { ready = false; goto EXIT; };
+	if( __cfaasm_in( ip, enble  ) ) { ready = false; goto EXIT; };
+	if( __cfaasm_in( ip, nopoll ) ) { ready = false; goto EXIT; };
+	if( !__cfaabi_tls.preemption_state.enabled) { ready = false; goto EXIT; };
+	if( __cfaabi_tls.preemption_state.in_progress ) { ready = false; goto EXIT; };
+
+EXIT:
 	// Adjust the pending flag accordingly
 	__cfaabi_tls.this_processor->pending_preemption = !ready;
@@ -468,44 +561,4 @@
 // Kernel Signal Handlers
 //=============================================================================================
-struct asm_region {
-	void * before;
-	void * after;
-};
-
-//-----------------------------------------------------------------------------
-// Some assembly required
-#if defined( __i386 )
-	#define __cfaasm_label( label ) \
-		({ \
-			struct asm_region region; \
-			asm( \
-				"movl $__cfaasm_" #label "_before, %[vb]\n\t" \
-				"movl $__cfaasm_" #label "_after , %[va]\n\t" \
-				 : [vb]"=r"(region.before), [vb]"=r"(region.before) \
-			); \
-			region; \
-		});
-#elif defined( __x86_64 )
-	#ifdef __PIC__
-		#define PLT "@PLT"
-	#else
-		#define PLT ""
-	#endif
-	#define __cfaasm_label( label ) \
-		({ \
-			struct asm_region region; \
-			asm( \
-				"movq $__cfaasm_" #label "_before" PLT ", %[vb]\n\t" \
-				"movq $__cfaasm_" #label "_after"  PLT ", %[va]\n\t" \
-				 : [vb]"=r"(region.before), [va]"=r"(region.after) \
-			); \
-			region; \
-		});
-#elif defined( __aarch64__ )
-	#error __cfaasm_label undefined for arm
-#else
-	#error unknown hardware architecture
-#endif
-
 __cfaabi_dbg_debug_do( static thread_local void * last_interrupt = 0; )
 
@@ -530,12 +583,5 @@
 
 	// Check if it is safe to preempt here
-	if( !preemption_ready() ) { return; }
-
-	struct asm_region region;
-	region = __cfaasm_label( get     ); if( ip >= region.before && ip <= region.after ) return;
-	region = __cfaasm_label( check   ); if( ip >= region.before && ip <= region.after ) return;
-	region = __cfaasm_label( disable ); if( ip >= region.before && ip <= region.after ) return;
-	region = __cfaasm_label( enable  ); if( ip >= region.before && ip <= region.after ) return;
-	region = __cfaasm_label( nopoll  ); if( ip >= region.before && ip <= region.after ) return;
+	if( !preemption_ready( ip ) ) { return; }
 
 	__cfaabi_dbg_print_buffer_decl( " KERNEL: preempting core %p (%p @ %p).\n", __cfaabi_tls.this_processor, __cfaabi_tls.this_thread, (void *)(cxt->uc_mcontext.CFA_REG_IP) );
Index: libcfa/src/stdlib.hfa
===================================================================
--- libcfa/src/stdlib.hfa	(revision 6a8882c5d95c78ede2d214a855c752147cb22cd9)
+++ libcfa/src/stdlib.hfa	(revision 21255675538be8803fefa8e055131729c60a99ab)
@@ -101,4 +101,23 @@
 		return (T *)pvalloc( sizeof(T) );				// C pvalloc
 	} // pvalloc
+
+	void free( T * addr ) {
+		free( (void *) addr ); 							// C free
+	} // free
+} // distribution
+
+static inline forall( ttype TT | { void free( TT ); } ) {
+	// T* does not take void* and vice-versa
+
+	void free( void * addr, TT rest ) {
+		free( addr );
+		free( rest );
+	} // free
+
+	forall( dtype T | sized(T) )
+	void free( T * addr, TT rest ) {
+		free( addr );
+		free( rest );
+	} // free
 } // distribution
 
@@ -110,5 +129,5 @@
 		forall( dtype T | sized(T) ) {
 			union  U_fill 		{ char c; T * a; T t; };
-			struct S_fill 		{ char tag; char c; size_t size; T * at; char t[50]; };
+			struct S_fill 		{ char tag; U_fill(T) fill; };
 			struct S_realloc	{ inline T *; };
 		}
Index: src/AST/Convert.cpp
===================================================================
--- src/AST/Convert.cpp	(revision 6a8882c5d95c78ede2d214a855c752147cb22cd9)
+++ src/AST/Convert.cpp	(revision 21255675538be8803fefa8e055131729c60a99ab)
@@ -2764,5 +2764,5 @@
 			old->location,
 			GET_ACCEPT_1(value, Expr),
-			(old->get_maybeConstructed()) ? ast::MaybeConstruct : ast::DoConstruct
+			(old->get_maybeConstructed()) ? ast::MaybeConstruct : ast::NoConstruct
 		);
 	}
@@ -2773,5 +2773,5 @@
 			GET_ACCEPT_V(initializers, Init),
 			GET_ACCEPT_V(designations, Designation),
-			(old->get_maybeConstructed()) ? ast::MaybeConstruct : ast::DoConstruct
+			(old->get_maybeConstructed()) ? ast::MaybeConstruct : ast::NoConstruct
 		);
 	}
Index: src/AST/Decl.hpp
===================================================================
--- src/AST/Decl.hpp	(revision 6a8882c5d95c78ede2d214a855c752147cb22cd9)
+++ src/AST/Decl.hpp	(revision 21255675538be8803fefa8e055131729c60a99ab)
@@ -79,4 +79,5 @@
 	ptr<Expr> asmName;
 	bool isDeleted = false;
+	bool isTypeFixed = false;
 
 	DeclWithType( const CodeLocation& loc, const std::string& name, Storage::Classes storage,
Index: src/AST/Init.hpp
===================================================================
--- src/AST/Init.hpp	(revision 6a8882c5d95c78ede2d214a855c752147cb22cd9)
+++ src/AST/Init.hpp	(revision 21255675538be8803fefa8e055131729c60a99ab)
@@ -50,5 +50,5 @@
 
 /// Flag for whether to construct from initialzier
-enum ConstructFlag { DoConstruct, MaybeConstruct };
+enum ConstructFlag { NoConstruct, MaybeConstruct };
 
 /// Object initializer base class
@@ -71,5 +71,5 @@
 	ptr<Expr> value;
 
-	SingleInit( const CodeLocation & loc, const Expr * val, ConstructFlag mc = DoConstruct )
+	SingleInit( const CodeLocation & loc, const Expr * val, ConstructFlag mc = NoConstruct )
 	: Init( loc, mc ), value( val ) {}
 
@@ -90,5 +90,5 @@
 
 	ListInit( const CodeLocation & loc, std::vector<ptr<Init>> && is,
-		std::vector<ptr<Designation>> && ds = {}, ConstructFlag mc = DoConstruct );
+		std::vector<ptr<Designation>> && ds = {}, ConstructFlag mc = NoConstruct );
 
 	using iterator = std::vector<ptr<Init>>::iterator;
@@ -118,5 +118,5 @@
 	ConstructorInit( 
 		const CodeLocation & loc, const Stmt * ctor, const Stmt * dtor, const Init * init )
-	: Init( loc, DoConstruct ), ctor( ctor ), dtor( dtor ), init( init ) {}
+	: Init( loc, MaybeConstruct ), ctor( ctor ), dtor( dtor ), init( init ) {}
 
 	const Init * accept( Visitor & v ) const override { return v.visit( this ); }
Index: src/AST/Pass.impl.hpp
===================================================================
--- src/AST/Pass.impl.hpp	(revision 6a8882c5d95c78ede2d214a855c752147cb22cd9)
+++ src/AST/Pass.impl.hpp	(revision 21255675538be8803fefa8e055131729c60a99ab)
@@ -423,5 +423,6 @@
 		}
 		catch( SemanticErrorException &e ) {
-			errors.append( e );
+			if (__pass::on_error (visitor.core, *i, 0))
+				errors.append( e );
 		}
 
@@ -683,7 +684,13 @@
 		// Do not enter (or leave) a new scope if atFunctionTop. Remember to save the result.
 		auto guard1 = makeFuncGuard( [this, enterScope = !this->atFunctionTop]() {
-			if ( enterScope ) __pass::symtab::enter(core, 0);
+			if ( enterScope ) {
+				__pass::symtab::enter(core, 0);
+				__pass::scope::enter(core, 0);
+			}
 		}, [this, leaveScope = !this->atFunctionTop]() {
-			if ( leaveScope ) __pass::symtab::leave(core, 0);
+			if ( leaveScope ) {
+				__pass::symtab::leave(core, 0);
+				__pass::scope::leave(core, 0);
+			}
 		});
 		ValueGuard< bool > guard2( atFunctionTop );
Index: src/AST/Pass.proto.hpp
===================================================================
--- src/AST/Pass.proto.hpp	(revision 6a8882c5d95c78ede2d214a855c752147cb22cd9)
+++ src/AST/Pass.proto.hpp	(revision 21255675538be8803fefa8e055131729c60a99ab)
@@ -266,4 +266,15 @@
 	static void endTrace(core_t &, long) {}
 
+	// Allows visitor to handle an error on top-level declarations, and possibly suppress the error.
+	// If onError() returns false, the error will be ignored. By default, it returns true.
+
+	template< typename core_t >
+	static bool on_error (core_t &, ptr<Decl> &, long) { return true; }
+
+	template< typename core_t >
+	static auto on_error (core_t & core, ptr<Decl> & decl, int) -> decltype(core.on_error(decl)) {
+		return core.on_error(decl); 
+	}
+
 	// Another feature of the templated visitor is that it calls beginScope()/endScope() for compound statement.
 	// All passes which have such functions are assumed desire this behaviour
Index: src/AST/Type.cpp
===================================================================
--- src/AST/Type.cpp	(revision 6a8882c5d95c78ede2d214a855c752147cb22cd9)
+++ src/AST/Type.cpp	(revision 21255675538be8803fefa8e055131729c60a99ab)
@@ -211,5 +211,5 @@
 	for ( const Type * ty : types ) {
 		members.emplace_back( new ObjectDecl{
-			CodeLocation{}, "", ty, new ListInit( CodeLocation{}, {}, {}, MaybeConstruct ),
+			CodeLocation{}, "", ty, new ListInit( CodeLocation{}, {}, {}, NoConstruct ),
 			Storage::Classes{}, Linkage::Cforall } );
 	}
Index: src/CodeGen/CodeGenerator.cc
===================================================================
--- src/CodeGen/CodeGenerator.cc	(revision 6a8882c5d95c78ede2d214a855c752147cb22cd9)
+++ src/CodeGen/CodeGenerator.cc	(revision 21255675538be8803fefa8e055131729c60a99ab)
@@ -120,5 +120,5 @@
 		// GCC builtins should always be printed unmangled
 		if ( options.pretty || decl->linkage.is_gcc_builtin ) return decl->name;
-		if ( decl->mangleName != "" ) {
+		if ( LinkageSpec::isMangled(decl->linkage) && decl->mangleName != "" ) {
 			// need to incorporate scope level in order to differentiate names for destructors
 			return decl->get_scopedMangleName();
Index: src/CodeGen/FixMain.cc
===================================================================
--- src/CodeGen/FixMain.cc	(revision 6a8882c5d95c78ede2d214a855c752147cb22cd9)
+++ src/CodeGen/FixMain.cc	(revision 21255675538be8803fefa8e055131729c60a99ab)
@@ -26,4 +26,5 @@
 #include "SynTree/Declaration.h"   // for FunctionDecl, operator<<
 #include "SynTree/Type.h"          // for FunctionType
+#include "SymTab/Mangler.h"
 
 namespace CodeGen {
@@ -47,4 +48,5 @@
 		if( main_signature ) {
 			os << "static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return ";
+			main_signature->mangleName = SymTab::Mangler::mangle(main_signature.get());
 
 			os << main_signature->get_scopedMangleName() << "(";
Index: src/CodeGen/FixNames.cc
===================================================================
--- src/CodeGen/FixNames.cc	(revision 6a8882c5d95c78ede2d214a855c752147cb22cd9)
+++ src/CodeGen/FixNames.cc	(revision 21255675538be8803fefa8e055131729c60a99ab)
@@ -31,4 +31,5 @@
 #include "SynTree/Type.h"          // for Type, BasicType, Type::Qualifiers
 #include "SynTree/Visitor.h"       // for Visitor, acceptAll
+#include "CompilationState.h"
 
 namespace CodeGen {
@@ -102,5 +103,7 @@
 		if ( dwt->get_name() != "" ) {
 			if ( LinkageSpec::isMangled( dwt->get_linkage() ) ) {
-				dwt->set_mangleName( SymTab::Mangler::mangle( dwt ) );
+				if (!useNewAST) {
+					dwt->set_mangleName( SymTab::Mangler::mangle( dwt ) );
+				}
 				dwt->set_scopeLevel( scopeLevel );
 			} // if
Index: src/InitTweak/GenInit.cc
===================================================================
--- src/InitTweak/GenInit.cc	(revision 6a8882c5d95c78ede2d214a855c752147cb22cd9)
+++ src/InitTweak/GenInit.cc	(revision 21255675538be8803fefa8e055131729c60a99ab)
@@ -26,4 +26,5 @@
 #include "AST/Node.hpp"
 #include "AST/Stmt.hpp"
+#include "CompilationState.h"
 #include "CodeGen/OperatorTable.h"
 #include "Common/PassVisitor.h"        // for PassVisitor, WithGuards, WithShort...
@@ -122,7 +123,10 @@
 
 	void genInit( std::list< Declaration * > & translationUnit ) {
+		HoistArrayDimension::hoistArrayDimension( translationUnit );
 		fixReturnStatements( translationUnit );
-		HoistArrayDimension::hoistArrayDimension( translationUnit );
-		CtorDtor::generateCtorDtor( translationUnit );
+
+		if (!useNewAST) {
+			CtorDtor::generateCtorDtor( translationUnit );
+		}
 	}
 
@@ -192,9 +196,14 @@
 
 			// need to resolve array dimensions in order to accurately determine if constexpr
-			ResolvExpr::findSingleExpression( arrayType->dimension, Validate::SizeType->clone(), indexer );
-			// array is variable-length when the dimension is not constexpr
-			arrayType->isVarLen = ! isConstExpr( arrayType->dimension );
+			if (!useNewAST) {
+				ResolvExpr::findSingleExpression( arrayType->dimension, Validate::SizeType->clone(), indexer );
+				// array is variable-length when the dimension is not constexpr
+				arrayType->isVarLen = ! isConstExpr( arrayType->dimension );
+			}
 			// don't need to hoist dimension if it's definitely pure - only need to if there's potential for side effects.
-			if ( ! Tuples::maybeImpure( arrayType->dimension ) ) return;
+			// xxx - hoisting has no side effects anyways, so don't skip since we delay resolve	
+			// only skip in the most trivial case, which does not require resolve
+			if (dynamic_cast<ConstantExpr *>(arrayType->dimension)) return;
+			// if ( ! Tuples::maybeImpure( arrayType->dimension ) ) return;
 
 			ObjectDecl * arrayDimension = new ObjectDecl( dimensionName.newName(), storageClasses, LinkageSpec::C, 0, Validate::SizeType->clone(), new SingleInit( arrayType->get_dimension() ) );
@@ -245,4 +254,5 @@
 	}
 
+	// why is this not just on FunctionDecl?
 	void ManagedTypes::handleDWT( DeclarationWithType * dwt ) {
 		// if this function is a user-defined constructor or destructor, mark down the type as "managed"
@@ -274,4 +284,63 @@
 	void ManagedTypes::beginScope() { managedTypes.beginScope(); }
 	void ManagedTypes::endScope() { managedTypes.endScope(); }
+
+	bool ManagedTypes_new::isManaged( const ast::Type * type ) const {
+		// references are never constructed
+		if ( dynamic_cast< const ast::ReferenceType * >( type ) ) return false;
+		if ( auto tupleType = dynamic_cast< const ast::TupleType * > ( type ) ) {
+			// tuple is also managed if any of its components are managed
+			for (auto & component : tupleType->types) {
+				if (isManaged(component)) return true;
+			}
+		}
+		// need to clear and reset qualifiers when determining if a type is managed
+		// ValueGuard< Type::Qualifiers > qualifiers( type->get_qualifiers() );
+		auto tmp = shallowCopy(type);
+		tmp->qualifiers = {};
+		// delete tmp at return
+		ast::ptr<ast::Type> guard = tmp;
+		// a type is managed if it appears in the map of known managed types, or if it contains any polymorphism (is a type variable or generic type containing a type variable)
+		return managedTypes.find( Mangle::mangle( tmp, {Mangle::NoOverrideable | Mangle::NoGenericParams | Mangle::Type} ) ) != managedTypes.end() || GenPoly::isPolyType( tmp );
+	}
+
+	bool ManagedTypes_new::isManaged( const ast::ObjectDecl * objDecl ) const {
+		const ast::Type * type = objDecl->type;
+		while ( auto at = dynamic_cast< const ast::ArrayType * >( type ) ) {
+			// must always construct VLAs with an initializer, since this is an error in C
+			if ( at->isVarLen && objDecl->init ) return true;
+			type = at->base;
+		}
+		return isManaged( type );
+	}
+
+	void ManagedTypes_new::handleDWT( const ast::DeclWithType * dwt ) {
+		// if this function is a user-defined constructor or destructor, mark down the type as "managed"
+		if ( ! dwt->linkage.is_overrideable && CodeGen::isCtorDtor( dwt->name ) ) {
+			auto & params = GenPoly::getFunctionType( dwt->get_type())->params;
+			assert( ! params.empty() );
+			// Type * type = InitTweak::getPointerBase( params.front() );
+			// assert( type );
+			managedTypes.insert( Mangle::mangle( params.front(), {Mangle::NoOverrideable | Mangle::NoGenericParams | Mangle::Type} ) );
+		}
+	}
+
+	void ManagedTypes_new::handleStruct( const ast::StructDecl * aggregateDecl ) {
+		// don't construct members, but need to take note if there is a managed member,
+		// because that means that this type is also managed
+		for ( auto & member : aggregateDecl->members ) {
+			if ( auto field = member.as<ast::ObjectDecl>() ) {
+				if ( isManaged( field ) ) {
+					// generic parameters should not play a role in determining whether a generic type is constructed - construct all generic types, so that
+					// polymorphic constructors make generic types managed types
+					ast::StructInstType inst( aggregateDecl );
+					managedTypes.insert( Mangle::mangle( &inst, {Mangle::NoOverrideable | Mangle::NoGenericParams | Mangle::Type} ) );
+					break;
+				}
+			}
+		}
+	}
+
+	void ManagedTypes_new::beginScope() { managedTypes.beginScope(); }
+	void ManagedTypes_new::endScope() { managedTypes.endScope(); }
 
 	ImplicitCtorDtorStmt * genCtorDtor( const std::string & fname, ObjectDecl * objDecl, Expression * arg ) {
@@ -370,9 +439,10 @@
 	// constructable object
 	InitExpander_new srcParam{ objDecl->init }, nullParam{ (const ast::Init *)nullptr };
+	ast::ptr< ast::Expr > dstParam = new ast::VariableExpr(loc, objDecl);
 	
 	ast::ptr< ast::Stmt > ctor = SymTab::genImplicitCall( 
-		srcParam, new ast::VariableExpr{ loc, objDecl }, loc, "?{}", objDecl );
+		srcParam, dstParam, loc, "?{}", objDecl );
 	ast::ptr< ast::Stmt > dtor = SymTab::genImplicitCall( 
-		nullParam, new ast::VariableExpr{ loc, objDecl }, loc, "^?{}", objDecl, 
+		nullParam, dstParam, loc, "^?{}", objDecl, 
 		SymTab::LoopBackward );
 	
Index: src/InitTweak/GenInit.h
===================================================================
--- src/InitTweak/GenInit.h	(revision 6a8882c5d95c78ede2d214a855c752147cb22cd9)
+++ src/InitTweak/GenInit.h	(revision 21255675538be8803fefa8e055131729c60a99ab)
@@ -52,4 +52,18 @@
 		GenPoly::ScopedSet< std::string > managedTypes;
 	};
+
+	class ManagedTypes_new {
+	public:
+		bool isManaged( const ast::ObjectDecl * objDecl ) const ; // determine if object is managed
+		bool isManaged( const ast::Type * type ) const; // determine if type is managed
+
+		void handleDWT( const ast::DeclWithType * dwt ); // add type to managed if ctor/dtor
+		void handleStruct( const ast::StructDecl * aggregateDecl ); // add type to managed if child is managed
+
+		void beginScope();
+		void endScope();
+	private:
+		GenPoly::ScopedSet< std::string > managedTypes;
+	};
 } // namespace
 
Index: src/InitTweak/InitTweak.cc
===================================================================
--- src/InitTweak/InitTweak.cc	(revision 6a8882c5d95c78ede2d214a855c752147cb22cd9)
+++ src/InitTweak/InitTweak.cc	(revision 21255675538be8803fefa8e055131729c60a99ab)
@@ -87,4 +87,41 @@
 		};
 
+		struct HasDesignations_new : public ast::WithShortCircuiting {
+			bool result = false;
+
+			void previsit( const ast::Node * ) {
+				// short circuit if we already know there are designations
+				if ( result ) visit_children = false;
+			}
+
+			void previsit( const ast::Designation * des ) {
+				// short circuit if we already know there are designations
+				if ( result ) visit_children = false;
+				else if ( ! des->designators.empty() ) {
+					result = true;
+					visit_children = false;
+				}
+			}
+		};
+
+		struct InitDepthChecker_new : public ast::WithGuards {
+			bool result = true;
+			const ast::Type * type;
+			int curDepth = 0, maxDepth = 0;
+			InitDepthChecker_new( const ast::Type * type ) : type( type ) {
+				const ast::Type * t = type;
+				while ( auto at = dynamic_cast< const ast::ArrayType * >( t ) ) {
+					maxDepth++;
+					t = at->base;
+				}
+				maxDepth++;
+			}
+			void previsit( ListInit * ) {
+				curDepth++;
+				GuardAction( [this]() { curDepth--; } );
+				if ( curDepth > maxDepth ) result = false;
+			}
+		};
+
 		struct InitFlattener_old : public WithShortCircuiting {
 			void previsit( SingleInit * singleInit ) {
@@ -122,4 +159,16 @@
 		maybeAccept( objDecl->init, checker );
 		return checker.pass.depthOkay;
+	}
+
+	bool isDesignated( const ast::Init * init ) {
+		ast::Pass<HasDesignations_new> finder;
+		maybe_accept( init, finder );
+		return finder.core.result;
+	}
+
+	bool checkInitDepth( const ast::ObjectDecl * objDecl ) {
+		ast::Pass<InitDepthChecker_new> checker( objDecl->type );
+		maybe_accept( objDecl->init.get(), checker );
+		return checker.core.result;
 	}
 
@@ -358,8 +407,8 @@
 			if ( auto listInit = dynamic_cast< const ast::ListInit * >( init ) ) {
 				for ( const ast::Init * init : *listInit ) {
-					buildCallExpr( callExpr, index, dimension, init, out );
+					buildCallExpr( shallowCopy(callExpr), index, dimension, init, out );
 				}
 			} else {
-				buildCallExpr( callExpr, index, dimension, init, out );
+				buildCallExpr( shallowCopy(callExpr), index, dimension, init, out );
 			}
 		} else {
@@ -1027,4 +1076,47 @@
 	};
 
+	struct ConstExprChecker_new : public ast::WithShortCircuiting {
+		// most expressions are not const expr
+		void previsit( const ast::Expr * ) { result = false; visit_children = false; }
+
+		void previsit( const ast::AddressExpr *addressExpr ) {
+			visit_children = false;
+			const ast::Expr * arg = addressExpr->arg;
+
+			// address of a variable or member expression is constexpr
+			if ( ! dynamic_cast< const ast::NameExpr * >( arg ) 
+			&& ! dynamic_cast< const ast::VariableExpr * >( arg ) 
+			&& ! dynamic_cast< const ast::MemberExpr * >( arg ) 
+			&& ! dynamic_cast< const ast::UntypedMemberExpr * >( arg ) ) result = false;
+		}
+
+		// these expressions may be const expr, depending on their children
+		void previsit( const ast::SizeofExpr * ) {}
+		void previsit( const ast::AlignofExpr * ) {}
+		void previsit( const ast::UntypedOffsetofExpr * ) {}
+		void previsit( const ast::OffsetofExpr * ) {}
+		void previsit( const ast::OffsetPackExpr * ) {}
+		void previsit( const ast::CommaExpr * ) {}
+		void previsit( const ast::LogicalExpr * ) {}
+		void previsit( const ast::ConditionalExpr * ) {}
+		void previsit( const ast::CastExpr * ) {}
+		void previsit( const ast::ConstantExpr * ) {}
+
+		void previsit( const ast::VariableExpr * varExpr ) {
+			visit_children = false;
+
+			if ( auto inst = varExpr->result.as<ast::EnumInstType>() ) {
+				long long int value;
+				if ( inst->base->valueOf( varExpr->var, value ) ) {
+					// enumerators are const expr
+					return;
+				}
+			}
+			result = false;
+		}
+
+		bool result = true;
+	};
+
 	bool isConstExpr( Expression * expr ) {
 		if ( expr ) {
@@ -1046,4 +1138,23 @@
 	}
 
+	bool isConstExpr( const ast::Expr * expr ) {
+		if ( expr ) {
+			ast::Pass<ConstExprChecker_new> checker;
+			expr->accept( checker );
+			return checker.core.result;
+		}
+		return true;
+	}
+
+	bool isConstExpr( const ast::Init * init ) {
+		if ( init ) {
+			ast::Pass<ConstExprChecker_new> checker;
+			init->accept( checker );
+			return checker.core.result;
+		} // if
+		// for all intents and purposes, no initializer means const expr
+		return true;
+	}
+
 	bool isConstructor( const std::string & str ) { return str == "?{}"; }
 	bool isDestructor( const std::string & str ) { return str == "^?{}"; }
Index: src/InitTweak/InitTweak.h
===================================================================
--- src/InitTweak/InitTweak.h	(revision 6a8882c5d95c78ede2d214a855c752147cb22cd9)
+++ src/InitTweak/InitTweak.h	(revision 21255675538be8803fefa8e055131729c60a99ab)
@@ -59,8 +59,10 @@
 	/// True if the Initializer contains designations
 	bool isDesignated( Initializer * init );
+	bool isDesignated( const ast::Init * init );
 
 	/// True if the ObjectDecl's Initializer nesting level is not deeper than the depth of its
 	/// type, where the depth of its type is the number of nested ArrayTypes + 1
 	bool checkInitDepth( ObjectDecl * objDecl );
+	bool checkInitDepth( const ast::ObjectDecl * objDecl );
 
 	/// returns the declaration of the function called by the expr (must be ApplicationExpr or UntypedExpr)
@@ -107,4 +109,7 @@
 	bool isConstExpr( Expression * expr );
 	bool isConstExpr( Initializer * init );
+
+	bool isConstExpr( const ast::Expr * expr );
+	bool isConstExpr( const ast::Init * init );
 
 	/// Modifies objDecl to have:
Index: src/ResolvExpr/ResolveTypeof.cc
===================================================================
--- src/ResolvExpr/ResolveTypeof.cc	(revision 6a8882c5d95c78ede2d214a855c752147cb22cd9)
+++ src/ResolvExpr/ResolveTypeof.cc	(revision 21255675538be8803fefa8e055131729c60a99ab)
@@ -29,4 +29,6 @@
 #include "SynTree/Mutator.h"     // for Mutator
 #include "SynTree/Type.h"        // for TypeofType, Type
+#include "SymTab/Mangler.h"
+#include "InitTweak/InitTweak.h" // for isConstExpr
 
 namespace SymTab {
@@ -163,4 +165,63 @@
 }
 
+struct FixArrayDimension {
+	// should not require a mutable symbol table - prevent pass template instantiation
+	const ast::SymbolTable & _symtab; 
+	FixArrayDimension(const ast::SymbolTable & symtab): _symtab(symtab) {}
+
+	const ast::ArrayType * previsit (const ast::ArrayType * arrayType) {
+		if (!arrayType->dimension) return arrayType;
+		auto mutType = mutate(arrayType);
+		ast::ptr<ast::Type> sizetype = ast::sizeType ? ast::sizeType : new ast::BasicType(ast::BasicType::LongUnsignedInt); 
+		mutType->dimension = findSingleExpression(arrayType->dimension, sizetype, _symtab);
+
+		if (InitTweak::isConstExpr(mutType->dimension)) {
+			mutType->isVarLen = ast::LengthFlag::FixedLen;
+		}
+		else {
+			mutType->isVarLen = ast::LengthFlag::VariableLen;
+		}
+		return mutType;
+	}
+};
+
+const ast::Type * fixArrayType( const ast::Type * type, const ast::SymbolTable & symtab) {
+	ast::Pass<FixArrayDimension> visitor {symtab};
+	return type->accept(visitor);
+}
+
+const ast::ObjectDecl * fixObjectType( const ast::ObjectDecl * decl , const ast::SymbolTable & symtab ) {
+	if (!decl->isTypeFixed) { 
+		auto mutDecl = mutate(decl);
+		auto resolvedType = resolveTypeof(decl->type, symtab);
+		resolvedType = fixArrayType(resolvedType, symtab);
+		mutDecl->type = resolvedType;
+
+		// check variable length if object is an array.
+		// xxx - should this be part of fixObjectType?
+
+		/*
+		if (auto arrayType = dynamic_cast<const ast::ArrayType *>(resolvedType)) {
+			auto dimExpr = findSingleExpression(arrayType->dimension, ast::sizeType, symtab);
+			if (auto varexpr = arrayType->dimension.as<ast::VariableExpr>()) {// hoisted previously
+				if (InitTweak::isConstExpr(varexpr->var.strict_as<ast::ObjectDecl>()->init)) {
+					auto mutType = mutate(arrayType);
+					mutType->isVarLen = ast::LengthFlag::VariableLen;
+					mutDecl->type = mutType;
+				}
+			}
+		}
+		*/
+
+
+		if (!mutDecl->name.empty()) 
+			mutDecl->mangleName = Mangle::mangle(mutDecl); // do not mangle unnamed variables
+		
+		mutDecl->isTypeFixed = true;
+		return mutDecl;
+	}
+	return decl;
+}
+
 } // namespace ResolvExpr
 
Index: src/ResolvExpr/ResolveTypeof.h
===================================================================
--- src/ResolvExpr/ResolveTypeof.h	(revision 6a8882c5d95c78ede2d214a855c752147cb22cd9)
+++ src/ResolvExpr/ResolveTypeof.h	(revision 21255675538be8803fefa8e055131729c60a99ab)
@@ -23,4 +23,5 @@
 	class Type;
 	class SymbolTable;
+	class ObjectDecl;
 }
 
@@ -28,4 +29,5 @@
 	Type *resolveTypeof( Type*, const SymTab::Indexer &indexer );
 	const ast::Type * resolveTypeof( const ast::Type *, const ast::SymbolTable & );
+	const ast::ObjectDecl * fixObjectType( const ast::ObjectDecl * decl , const ast::SymbolTable & symtab );
 } // namespace ResolvExpr
 
Index: src/ResolvExpr/Resolver.cc
===================================================================
--- src/ResolvExpr/Resolver.cc	(revision 6a8882c5d95c78ede2d214a855c752147cb22cd9)
+++ src/ResolvExpr/Resolver.cc	(revision 21255675538be8803fefa8e055131729c60a99ab)
@@ -26,7 +26,9 @@
 #include "RenameVars.h"                  // for RenameVars, global_renamer
 #include "Resolver.h"
+#include "ResolveTypeof.h"
 #include "ResolvMode.h"                  // for ResolvMode
 #include "typeops.h"                     // for extractResultType
 #include "Unify.h"                       // for unify
+#include "CompilationState.h"
 #include "AST/Chain.hpp"
 #include "AST/Decl.hpp"
@@ -45,4 +47,5 @@
 #include "SymTab/Autogen.h"              // for SizeType
 #include "SymTab/Indexer.h"              // for Indexer
+#include "SymTab/Mangler.h"              // for Mangler
 #include "SynTree/Declaration.h"         // for ObjectDecl, TypeDecl, Declar...
 #include "SynTree/Expression.h"          // for Expression, CastExpr, InitExpr
@@ -1179,15 +1182,19 @@
 	} // anonymous namespace
 
-		ast::ptr< ast::Expr > findSingleExpression(
-			const ast::Expr * untyped, const ast::Type * type, const ast::SymbolTable & symtab
-		) {
-			assert( untyped && type );
-			ast::ptr< ast::Expr > castExpr = new ast::CastExpr{ untyped, type };
-			ast::ptr< ast::Expr > newExpr = findSingleExpression( castExpr, symtab );
-			removeExtraneousCast( newExpr, symtab );
-			return newExpr;
-		}
+	ast::ptr< ast::Expr > findSingleExpression(
+		const ast::Expr * untyped, const ast::Type * type, const ast::SymbolTable & symtab
+	) {
+		assert( untyped && type );
+		ast::ptr< ast::Expr > castExpr = new ast::CastExpr{ untyped, type };
+		ast::ptr< ast::Expr > newExpr = findSingleExpression( castExpr, symtab );
+		removeExtraneousCast( newExpr, symtab );
+		return newExpr;
+	}
 
 	namespace {
+		bool structOrUnion( const Candidate & i ) {
+			const ast::Type * t = i.expr->result->stripReferences();
+			return dynamic_cast< const ast::StructInstType * >( t ) || dynamic_cast< const ast::UnionInstType * >( t );
+		}
 		/// Predicate for "Candidate has integral type"
 		bool hasIntegralType( const Candidate & i ) {
@@ -1237,4 +1244,7 @@
 		ast::ptr< ast::Type > functionReturn = nullptr;
 		ast::CurrentObject currentObject;
+		// for work previously in GenInit
+		static InitTweak::ManagedTypes_new managedTypes;
+
 		bool inEnumDecl = false;
 
@@ -1244,7 +1254,9 @@
 		Resolver_new( const ast::SymbolTable & syms ) { symtab = syms; }
 
-		void previsit( const ast::FunctionDecl * );
+		const ast::FunctionDecl * previsit( const ast::FunctionDecl * );
 		const ast::FunctionDecl * postvisit( const ast::FunctionDecl * );
-		void previsit( const ast::ObjectDecl * );
+		const ast::ObjectDecl * previsit( const ast::ObjectDecl * );
+		void previsit( const ast::AggregateDecl * );
+		void previsit( const ast::StructDecl * );
 		void previsit( const ast::EnumDecl * );
 		const ast::StaticAssertDecl * previsit( const ast::StaticAssertDecl * );
@@ -1267,10 +1279,19 @@
 		const ast::CatchStmt *       postvisit( const ast::CatchStmt * );
 		const ast::WaitForStmt *     previsit( const ast::WaitForStmt * );
+		const ast::WithStmt *        previsit( const ast::WithStmt * );
 
 		const ast::SingleInit *      previsit( const ast::SingleInit * );
 		const ast::ListInit *        previsit( const ast::ListInit * );
 		const ast::ConstructorInit * previsit( const ast::ConstructorInit * );
+
+		void resolveWithExprs(std::vector<ast::ptr<ast::Expr>> & exprs, std::list<ast::ptr<ast::Stmt>> & stmtsToAdd);
+
+		void beginScope() { managedTypes.beginScope(); }
+		void endScope() { managedTypes.endScope(); }
+		bool on_error(ast::ptr<ast::Decl> & decl);
 	};
 	// size_t Resolver_new::traceId = Stats::Heap::new_stacktrace_id("Resolver");
+
+	InitTweak::ManagedTypes_new Resolver_new::managedTypes;
 
 	void resolve( ast::TranslationUnit& translationUnit ) {
@@ -1297,7 +1318,107 @@
 	}
 
-	void Resolver_new::previsit( const ast::FunctionDecl * functionDecl ) {
+	namespace {
+		const ast::Attribute * handleAttribute(const CodeLocation & loc, const ast::Attribute * attr, const ast::SymbolTable & symtab) {
+			std::string name = attr->normalizedName();
+			if (name == "constructor" || name == "destructor") {
+				if (attr->params.size() == 1) {
+					auto arg = attr->params.front();
+					auto resolved = ResolvExpr::findSingleExpression( arg, new ast::BasicType( ast::BasicType::LongLongSignedInt ), symtab );
+					auto result = eval(arg);
+
+					auto mutAttr = mutate(attr);
+					mutAttr->params.front() = resolved;
+					if (! result.second) {
+						SemanticWarning(loc, Warning::GccAttributes,
+							toCString( name, " priorities must be integers from 0 to 65535 inclusive: ", arg ) );
+					}
+					else {
+						auto priority = result.first;
+						if (priority < 101) {
+							SemanticWarning(loc, Warning::GccAttributes,
+								toCString( name, " priorities from 0 to 100 are reserved for the implementation" ) );
+						} else if (priority < 201 && ! buildingLibrary()) {
+							SemanticWarning(loc, Warning::GccAttributes,
+								toCString( name, " priorities from 101 to 200 are reserved for the implementation" ) );
+						}
+					}
+					return mutAttr;
+				} else if (attr->params.size() > 1) {
+					SemanticWarning(loc, Warning::GccAttributes, toCString( "too many arguments to ", name, " attribute" ) );
+				} else {
+					SemanticWarning(loc, Warning::GccAttributes, toCString( "too few arguments to ", name, " attribute" ) );
+				}
+			}
+			return attr;
+		}
+	}
+
+	const ast::FunctionDecl * Resolver_new::previsit( const ast::FunctionDecl * functionDecl ) {
 		GuardValue( functionReturn );
+
+		assert (functionDecl->unique());
+		if (!functionDecl->has_body() && !functionDecl->withExprs.empty()) {
+			SemanticError(functionDecl->location, functionDecl, "Function without body has with declarations");
+		}
+
+		if (!functionDecl->isTypeFixed) {
+			auto mutDecl = mutate(functionDecl);
+			auto mutType = mutDecl->type.get_and_mutate();
+
+			for (auto & attr: mutDecl->attributes) {
+				attr = handleAttribute(mutDecl->location, attr, symtab);
+			}
+
+			// handle assertions. (seems deep)
+
+			symtab.enterScope();
+			for (auto & typeParam : mutType->forall) {
+				auto mutParam = typeParam.get_and_mutate();
+				symtab.addType(mutParam);
+				for (auto & asst : mutParam->assertions) {
+					asst = fixObjectType(asst.strict_as<ast::ObjectDecl>(), symtab);
+					symtab.addId(asst);
+				}
+				typeParam = mutParam;
+			}
+
+			// temporarily adds params to symbol table.
+			// actual scoping rules for params and withexprs differ - see Pass::visit(FunctionDecl)
+
+			std::vector<ast::ptr<ast::Type>> paramTypes;
+			std::vector<ast::ptr<ast::Type>> returnTypes;
+
+			for (auto & param : mutDecl->params) {
+				param = fixObjectType(param.strict_as<ast::ObjectDecl>(), symtab);
+				symtab.addId(param);
+				paramTypes.emplace_back(param->get_type());
+			}
+			for (auto & ret : mutDecl->returns) {
+				ret = fixObjectType(ret.strict_as<ast::ObjectDecl>(), symtab);
+				returnTypes.emplace_back(ret->get_type());
+			}
+			// since function type in decl is just a view of param types, need to update that as well
+			mutType->params = std::move(paramTypes);
+			mutType->returns = std::move(returnTypes);
+
+			std::list<ast::ptr<ast::Stmt>> newStmts;
+			resolveWithExprs (mutDecl->withExprs, newStmts);
+
+			if (mutDecl->stmts) {
+				auto mutStmt = mutDecl->stmts.get_and_mutate();
+				mutStmt->kids.splice(mutStmt->kids.begin(), std::move(newStmts));
+				mutDecl->stmts = mutStmt;
+			}
+
+			symtab.leaveScope();
+
+			mutDecl->mangleName = Mangle::mangle(mutDecl);
+			mutDecl->isTypeFixed = true;
+			functionDecl = mutDecl;
+		}
+		managedTypes.handleDWT(functionDecl);
+
 		functionReturn = extractResultType( functionDecl->type );
+		return functionDecl;
 	}
 
@@ -1330,5 +1451,5 @@
 	}
 
-	void Resolver_new::previsit( const ast::ObjectDecl * objectDecl ) {
+	const ast::ObjectDecl * Resolver_new::previsit( const ast::ObjectDecl * objectDecl ) {
 		// To handle initialization of routine pointers [e.g. int (*fp)(int) = foo()],
 		// class-variable `initContext` is changed multiple times because the LHS is analyzed
@@ -1338,11 +1459,53 @@
 		// selecting the RHS.
 		GuardValue( currentObject );
-		currentObject = ast::CurrentObject{ objectDecl->location, objectDecl->get_type() };
+
 		if ( inEnumDecl && dynamic_cast< const ast::EnumInstType * >( objectDecl->get_type() ) ) {
 			// enumerator initializers should not use the enum type to initialize, since the
 			// enum type is still incomplete at this point. Use `int` instead.
+			objectDecl = fixObjectType(objectDecl, symtab);
 			currentObject = ast::CurrentObject{
 				objectDecl->location, new ast::BasicType{ ast::BasicType::SignedInt } };
 		}
+		else {
+			if (!objectDecl->isTypeFixed) {
+				auto newDecl = fixObjectType(objectDecl, symtab);
+				auto mutDecl = mutate(newDecl);
+				
+				// generate CtorInit wrapper when necessary.
+				// in certain cases, fixObjectType is called before reaching
+				// this object in visitor pass, thus disabling CtorInit codegen.
+				// this happens on aggregate members and function parameters.
+				if ( InitTweak::tryConstruct( mutDecl ) && ( managedTypes.isManaged( mutDecl ) || ((! isInFunction() || mutDecl->storage.is_static ) && ! InitTweak::isConstExpr( mutDecl->init ) ) ) ) {
+					// constructed objects cannot be designated
+					if ( InitTweak::isDesignated( mutDecl->init ) ) SemanticError( mutDecl, "Cannot include designations in the initializer for a managed Object. If this is really what you want, then initialize with @=.\n" );
+					// constructed objects should not have initializers nested too deeply
+					if ( ! InitTweak::checkInitDepth( mutDecl ) ) SemanticError( mutDecl, "Managed object's initializer is too deep " );
+
+					mutDecl->init = InitTweak::genCtorInit( mutDecl->location, mutDecl );
+				}
+
+				objectDecl = mutDecl;
+			}
+			currentObject = ast::CurrentObject{ objectDecl->location, objectDecl->get_type() };
+		}
+		
+		return objectDecl;
+	}
+
+	void Resolver_new::previsit( const ast::AggregateDecl * _aggDecl ) {
+		auto aggDecl = mutate(_aggDecl);
+		assertf(aggDecl == _aggDecl, "type declarations must be unique");
+
+		for (auto & member: aggDecl->members) {
+			// nested type decls are hoisted already. no need to do anything
+			if (auto obj = member.as<ast::ObjectDecl>()) {
+				member = fixObjectType(obj, symtab);
+			}
+		}
+	}
+
+	void Resolver_new::previsit( const ast::StructDecl * structDecl ) {
+		previsit(static_cast<const ast::AggregateDecl *>(structDecl));
+		managedTypes.handleStruct(structDecl);
 	}
 
@@ -1351,5 +1514,7 @@
 		GuardValue( inEnumDecl );
 		inEnumDecl = true;
-	}
+		// don't need to fix types for enum fields
+	}
+
 
 	const ast::StaticAssertDecl * Resolver_new::previsit(
@@ -1780,4 +1945,31 @@
 	}
 
+	const ast::WithStmt * Resolver_new::previsit( const ast::WithStmt * withStmt ) {
+		auto mutStmt = mutate(withStmt);
+		resolveWithExprs(mutStmt->exprs, stmtsToAddBefore);
+		return mutStmt;
+	}
+
+	void Resolver_new::resolveWithExprs(std::vector<ast::ptr<ast::Expr>> & exprs, std::list<ast::ptr<ast::Stmt>> & stmtsToAdd) {
+		for (auto & expr : exprs) {
+			// only struct- and union-typed expressions are viable candidates
+			expr = findKindExpression( expr, symtab, structOrUnion, "with expression" );
+
+			// if with expression might be impure, create a temporary so that it is evaluated once
+			if ( Tuples::maybeImpure( expr ) ) {
+				static UniqueName tmpNamer( "_with_tmp_" );
+				const CodeLocation loc = expr->location;
+				auto tmp = new ast::ObjectDecl(loc, tmpNamer.newName(), expr->result, new ast::SingleInit(loc, expr ) );
+				expr = new ast::VariableExpr( loc, tmp );
+				stmtsToAdd.push_back( new ast::DeclStmt(loc, tmp ) );
+				if ( InitTweak::isConstructable( tmp->type ) ) {
+					// generate ctor/dtor and resolve them
+					tmp->init = InitTweak::genCtorInit( loc, tmp );
+				}
+				// since tmp is freshly created, this should modify tmp in-place
+				tmp->accept( *visitor );
+			}
+		}
+	}
 
 
@@ -1875,4 +2067,19 @@
 	}
 
+	// suppress error on autogen functions and mark invalid autogen as deleted.
+	bool Resolver_new::on_error(ast::ptr<ast::Decl> & decl) {
+		if (auto functionDecl = decl.as<ast::FunctionDecl>()) {
+			// xxx - can intrinsic gen ever fail?
+			if (functionDecl->linkage == ast::Linkage::AutoGen) { 
+				auto mutDecl = mutate(functionDecl);
+				mutDecl->isDeleted = true;
+				mutDecl->stmts = nullptr;
+				decl = mutDecl;
+				return false;
+			}
+		}
+		return true;
+	}
+
 } // namespace ResolvExpr
 
Index: src/ResolvExpr/SatisfyAssertions.cpp
===================================================================
--- src/ResolvExpr/SatisfyAssertions.cpp	(revision 6a8882c5d95c78ede2d214a855c752147cb22cd9)
+++ src/ResolvExpr/SatisfyAssertions.cpp	(revision 21255675538be8803fefa8e055131729c60a99ab)
@@ -247,5 +247,5 @@
 				auto it = inferred.find( slot );
 				if ( it == inferred.end() ) {
-					std::cerr << "missing assertion " << slot << std::endl;
+					// std::cerr << "missing assertion " << slot << std::endl;
 					missingSlots.push_back(slot);
 					continue;
Index: src/SymTab/Autogen.cc
===================================================================
--- src/SymTab/Autogen.cc	(revision 6a8882c5d95c78ede2d214a855c752147cb22cd9)
+++ src/SymTab/Autogen.cc	(revision 21255675538be8803fefa8e055131729c60a99ab)
@@ -38,4 +38,5 @@
 #include "SynTree/Type.h"          // for FunctionType, Type, TypeInstType
 #include "SynTree/Visitor.h"       // for maybeAccept, Visitor, acceptAll
+#include "CompilationState.h"
 
 class Attribute;
@@ -346,5 +347,6 @@
 	void FuncGenerator::resolve( FunctionDecl * dcl ) {
 		try {
-			ResolvExpr::resolveDecl( dcl, indexer );
+			if (!useNewAST) // attempt to delay resolver call
+				ResolvExpr::resolveDecl( dcl, indexer );
 			if ( functionNesting == 0 ) {
 				// forward declare if top-level struct, so that
Index: src/SymTab/Autogen.h
===================================================================
--- src/SymTab/Autogen.h	(revision 6a8882c5d95c78ede2d214a855c752147cb22cd9)
+++ src/SymTab/Autogen.h	(revision 21255675538be8803fefa8e055131729c60a99ab)
@@ -167,5 +167,5 @@
 		fExpr->args.emplace_back( dstParam );
 
-		const ast::Stmt * listInit = srcParam.buildListInit( fExpr );
+		ast::ptr<ast::Stmt> listInit = srcParam.buildListInit( fExpr );
 
 		// fetch next set of arguments
Index: src/SymTab/Validate.cc
===================================================================
--- src/SymTab/Validate.cc	(revision 6a8882c5d95c78ede2d214a855c752147cb22cd9)
+++ src/SymTab/Validate.cc	(revision 21255675538be8803fefa8e055131729c60a99ab)
@@ -64,4 +64,5 @@
 #include "Common/UniqueName.h"         // for UniqueName
 #include "Common/utility.h"            // for operator+, cloneAll, deleteAll
+#include "CompilationState.h"          // skip some passes in new-ast build
 #include "Concurrency/Keywords.h"      // for applyKeywords
 #include "FixFunction.h"               // for FixFunction
@@ -368,13 +369,17 @@
 				mutateAll( translationUnit, compoundliteral );
 			});
-			Stats::Time::TimeBlock("Resolve With Expressions", [&]() {
-				ResolvExpr::resolveWithExprs( translationUnit ); // must happen before FixObjectType because user-code is resolved and may contain with variables
-			});
+			if (!useNewAST) {
+				Stats::Time::TimeBlock("Resolve With Expressions", [&]() {
+					ResolvExpr::resolveWithExprs( translationUnit ); // must happen before FixObjectType because user-code is resolved and may contain with variables
+				});
+			}
 		}
 		{
 			Stats::Heap::newPass("validate-F");
 			Stats::Time::BlockGuard guard("validate-F");
-			Stats::Time::TimeCall("Fix Object Type",
-				FixObjectType::fix, translationUnit);
+			if (!useNewAST) {
+				Stats::Time::TimeCall("Fix Object Type",
+					FixObjectType::fix, translationUnit);
+			}
 			Stats::Time::TimeCall("Array Length",
 				ArrayLength::computeLength, translationUnit);
@@ -383,6 +388,8 @@
 			Stats::Time::TimeCall("Fix Label Address",
 				mutateAll<LabelAddressFixer>, translationUnit, labelAddrFixer);
-			Stats::Time::TimeCall("Handle Attributes",
-				Validate::handleAttributes, translationUnit);
+			if (!useNewAST) {
+				Stats::Time::TimeCall("Handle Attributes",
+					Validate::handleAttributes, translationUnit);
+			}
 		}
 	}
@@ -1340,12 +1347,14 @@
 
 	void ArrayLength::previsit( ArrayType * type ) {
-		if ( type->dimension ) {
-			// need to resolve array dimensions early so that constructor code can correctly determine
-			// if a type is a VLA (and hence whether its elements need to be constructed)
-			ResolvExpr::findSingleExpression( type->dimension, Validate::SizeType->clone(), indexer );
-
-			// must re-evaluate whether a type is a VLA, now that more information is available
-			// (e.g. the dimension may have been an enumerator, which was unknown prior to this step)
-			type->isVarLen = ! InitTweak::isConstExpr( type->dimension );
+		if (!useNewAST) {
+			if ( type->dimension ) {
+				// need to resolve array dimensions early so that constructor code can correctly determine
+				// if a type is a VLA (and hence whether its elements need to be constructed)
+				ResolvExpr::findSingleExpression( type->dimension, Validate::SizeType->clone(), indexer );
+
+				// must re-evaluate whether a type is a VLA, now that more information is available
+				// (e.g. the dimension may have been an enumerator, which was unknown prior to this step)
+				type->isVarLen = ! InitTweak::isConstExpr( type->dimension );
+			}
 		}
 	}
Index: tests/alloc.cfa
===================================================================
--- tests/alloc.cfa	(revision 6a8882c5d95c78ede2d214a855c752147cb22cd9)
+++ tests/alloc.cfa	(revision 21255675538be8803fefa8e055131729c60a99ab)
@@ -208,5 +208,14 @@
 
 
+	int const_count, dest_count;
 	struct Struct { int x; double y; };
+	void  ?{}( Struct & a ) {					// construct
+		a.[ x, y ] = [ -1, -1.0 ];
+	}
+	void  ?{}( Struct & a, int x, double y ) {	// initialize
+		a.[ x, y ] = [ x, y ];
+		const_count++;
+	}
+	void ^?{}( Struct & a ) {  dest_count++; }	// destruct
 	Struct st, st1, sta[dim], sta1[dim], * stp, * stp1;
 
@@ -329,18 +338,27 @@
 	printf( "\n" );
 
+	const_count = dest_count = 0;
 	stp = new( 42, 42.5 );
+	assert( const_count == 1 && dest_count == 0 );						// assertion for testing
 	stp1 = new( 42, 42.5 );
+	assert( const_count == 2 && dest_count == 0 );						// assertion for testing
+
 	printf( "CFA new initialize\n%d %g %d %g\n", stp->x, stp->y, stp1->x, stp1->y );
 	delete( stp, stp1 );
+	assert( const_count == 2 && dest_count == 2 );						// assertion for testing
 
 	// new, array types
 	stp = anew( dim, 42, 42.5 );
+	assert( const_count == 2 + dim && dest_count == 2 );				// assertion for testing
 	printf( "CFA array new initialize\n" );
 	for ( i; dim ) { printf( "%d %g, ", stp[i].x, stp[i].y ); }
 	printf( "\n" );
+
 	stp1 = anew( dim, 42, 42.5 );
+	assert( const_count == 2 + 2 * dim && dest_count == 2 );			// assertion for testing
 	for ( i; dim ) { printf( "%d %g, ", stp1[i].x, stp1[i].y ); }
 	printf( "\n" );
 	adelete( stp, stp1 );
+	assert( const_count == 2 + 2 * dim && dest_count == 2 + 2 * dim);	// assertion for testing
 
 	// extras
@@ -354,5 +372,8 @@
 	*ip = 0xdeadbeef;
 	printf( "CFA deep malloc %#x\n", *ip );
-	free( ip );
+
+	dp = alloc(5.0`fill); // just for testing multiple free
+	assert(*dp == 5.0);
+	free( ip, dp );
 
 #ifdef ERR1
Index: tests/malloc.cfa
===================================================================
--- tests/malloc.cfa	(revision 6a8882c5d95c78ede2d214a855c752147cb22cd9)
+++ tests/malloc.cfa	(revision 21255675538be8803fefa8e055131729c60a99ab)
@@ -319,5 +319,5 @@
 	free(ip);
 
-	free( 0p ); // sanity check
+	free( (void*) 0p ); // sanity check
 	free( NULL ); // sanity check
 
Index: tests/manipulatorsOutput3.cfa
===================================================================
--- tests/manipulatorsOutput3.cfa	(revision 6a8882c5d95c78ede2d214a855c752147cb22cd9)
+++ tests/manipulatorsOutput3.cfa	(revision 21255675538be8803fefa8e055131729c60a99ab)
@@ -156,7 +156,4 @@
 	sout | nl;
 
-	ui128 = 0x7fffffffffffffff;
-	ui128 <<= 64;
-	ui128 += 0xffffffffffffffff;
 	sout | left( wd( 160, i128 ) );
 	sout | left( sign( wd( 0, i128 ) ) );
@@ -177,7 +174,7 @@
 	sout | left( wd( 160, bin( i128 ) ) );
 	sout | left( sign( wd( 160, i128 ) ) );
-	sout | left( wd( 160, upcase(hex( i128 )) ) );
-	sout | left( wd( 160, upcase(oct( i128 ) )) );
-	sout | left( wd( 160, upcase(bin( i128 )) ) );
+	sout | left( wd( 160, upcase( hex( i128 ) ) ) );
+	sout | left( wd( 160, upcase( oct( i128 ) ) ) );
+	sout | left( wd( 160, upcase( bin( i128 ) ) ) );
 
 	x = 1234;
@@ -316,5 +313,4 @@
 	}
 
-
 	// int128 constants (and printing)
 	int128 v = 0xffff_ffffffff_ffffffff_L128 + 0xffffffff_ffffffff_ffffffff_ffffffff_L128;
