changeset 1:c53b6e3fe49a trunk

[svn r5] Initial commit. Most things are very rough.
author lindquist
date Sat, 01 Sep 2007 21:43:27 +0200
parents a9e71648e74d
children 1fb7ce03965b
files dmd/Doxyfile dmd/access.c dmd/aggregate.h dmd/array.c dmd/arraytypes.h dmd/artistic.txt dmd/attrib.c dmd/attrib.h dmd/cast.c dmd/class.c dmd/complex_t.h dmd/cond.c dmd/cond.h dmd/constfold.c dmd/dchar.c dmd/dchar.h dmd/declaration.c dmd/declaration.h dmd/delegatize.c dmd/doc.c dmd/doc.h dmd/dsymbol.c dmd/dsymbol.h dmd/dump.c dmd/entity.c dmd/enum.c dmd/enum.h dmd/expression.c dmd/expression.h dmd/func.c dmd/gnuc.c dmd/gnuc.h dmd/gpl.txt dmd/hdrgen.c dmd/hdrgen.h dmd/html.c dmd/html.h dmd/id.c dmd/id.h dmd/identifier.c dmd/identifier.h dmd/idgen.c dmd/impcnvgen.c dmd/impcnvtab.c dmd/import.c dmd/import.h dmd/inifile.c dmd/init.c dmd/init.h dmd/inline.c dmd/interpret.c dmd/lexer.c dmd/lexer.h dmd/link.c dmd/lstring.c dmd/lstring.h dmd/macro.c dmd/macro.h dmd/mangle.c dmd/mars.c dmd/mars.h dmd/mem.c dmd/mem.h dmd/module.c dmd/module.h dmd/mtype.c dmd/mtype.h dmd/opover.c dmd/optimize.c dmd/parse.c dmd/parse.h dmd/port.h dmd/readme.txt dmd/root.c dmd/root.h dmd/scope.c dmd/scope.h dmd/statement.c dmd/statement.h dmd/staticassert.c dmd/staticassert.h dmd/stringtable.c dmd/stringtable.h dmd/struct.c dmd/template.c dmd/template.h dmd/total.h dmd/unialpha.c dmd/utf.c dmd/utf.h dmd/version.c dmd/version.h gen/elem.c gen/elem.h gen/enums.h gen/irstate.c gen/irstate.h gen/logger.c gen/logger.h gen/runtime.c gen/runtime.h gen/symbol.h gen/tocsym.c gen/todt.c gen/toir.c gen/tollvm.c gen/tollvm.h gen/toobj.c gen/typinf.c lphobos/build.sh lphobos/clean.sh lphobos/crc32.d lphobos/dsss.conf lphobos/gcstats.d lphobos/internal/arrays.d lphobos/internal/contract.d lphobos/internal/moduleinit.d lphobos/internal/moduleinit_backend.ll lphobos/internal/objectimpl.d lphobos/llvm/intrinsic.d lphobos/object.d lphobos/std/c/fenv.d lphobos/std/c/linux/linux.d lphobos/std/c/linux/linuxextern.d lphobos/std/c/linux/pthread.d lphobos/std/c/linux/socket.d lphobos/std/c/locale.d lphobos/std/c/math.d lphobos/std/c/process.d lphobos/std/c/stdarg.d lphobos/std/c/stddef.d lphobos/std/c/stdio.d lphobos/std/c/stdlib.d lphobos/std/c/string.d lphobos/std/c/time.d lphobos/std/intrinsic.d lphobos/std/stdint.d lphobos/std/typeinfo/ti_Aint.d lphobos/std/typeinfo/ti_byte.d lphobos/std/typeinfo/ti_char.d lphobos/std/typeinfo/ti_int.d lphobos/std/typeinfo/ti_ptr.d lphobos/std/typeinfo/ti_short.d lphobos/std/typeinfo/ti_ubyte.d lphobos/std/typeinfo/ti_uint.d lphobos/std/typeinfo/ti_ushort.d lphobos/std/typeinfounsupported/ti_AC.d lphobos/std/typeinfounsupported/ti_Acdouble.d lphobos/std/typeinfounsupported/ti_Acfloat.d lphobos/std/typeinfounsupported/ti_Acreal.d lphobos/std/typeinfounsupported/ti_Adouble.d lphobos/std/typeinfounsupported/ti_Afloat.d lphobos/std/typeinfounsupported/ti_Ag.d lphobos/std/typeinfounsupported/ti_Aint.d lphobos/std/typeinfounsupported/ti_Along.d lphobos/std/typeinfounsupported/ti_Areal.d lphobos/std/typeinfounsupported/ti_Ashort.d lphobos/std/typeinfounsupported/ti_C.d lphobos/std/typeinfounsupported/ti_byte.d lphobos/std/typeinfounsupported/ti_cdouble.d lphobos/std/typeinfounsupported/ti_cfloat.d lphobos/std/typeinfounsupported/ti_char.d lphobos/std/typeinfounsupported/ti_creal.d lphobos/std/typeinfounsupported/ti_dchar.d lphobos/std/typeinfounsupported/ti_delegate.d lphobos/std/typeinfounsupported/ti_double.d lphobos/std/typeinfounsupported/ti_float.d lphobos/std/typeinfounsupported/ti_idouble.d lphobos/std/typeinfounsupported/ti_ifloat.d lphobos/std/typeinfounsupported/ti_int.d lphobos/std/typeinfounsupported/ti_ireal.d lphobos/std/typeinfounsupported/ti_long.d lphobos/std/typeinfounsupported/ti_ptr.d lphobos/std/typeinfounsupported/ti_real.d lphobos/std/typeinfounsupported/ti_short.d lphobos/std/typeinfounsupported/ti_ubyte.d lphobos/std/typeinfounsupported/ti_uint.d lphobos/std/typeinfounsupported/ti_ulong.d lphobos/std/typeinfounsupported/ti_ushort.d lphobos/std/typeinfounsupported/ti_void.d lphobos/std/typeinfounsupported/ti_wchar.d premake.lua test/a.d test/alignment.d test/arrayinit.d test/arrays.d test/arrays2.d test/assign.d test/b.d test/bitops.d test/c.d test/classes.d test/classes2.d test/classes3.d test/classes4.d test/comma.d test/cond.d test/condexp.d test/cyclic.d test/d.d test/dgs.d test/dotproduct.d test/e.d test/f.d test/floatcmp.d test/forwdecl.d test/funcptr.d test/funcs.d test/imports_1of2.d test/imports_2of2.d test/intrinsics.d test/pointers.d test/pt.d test/ptrarith.d test/sieve.d test/slices.d test/static_ctor.d test/staticarrays.d test/structinit.d test/structinit2.d test/structs.d test/structs2.d test/terms.d test/typeinfo.d test/v2d.d test/virtcall.d tester.sh
diffstat 226 files changed, 84269 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/Doxyfile	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,1257 @@
+# Doxyfile 1.5.2
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file that
+# follow. The default is UTF-8 which is also the encoding used for all text before
+# the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into
+# libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list of
+# possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = DMDFE
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER         = 1.020
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = docs
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian,
+# Italian, Japanese, Japanese-en (Japanese with English messages), Korean,
+# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian,
+# Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like the Qt-style comments (thus requiring an
+# explicit @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF      = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
+DETAILS_AT_TOP         = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for Java.
+# For instance, namespaces will be presented as packages, qualified scopes
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to
+# include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES       = NO
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from the
+# version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT                  =
+
+# This tag can be used to specify the character encoding of the source files that
+# doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default
+# input encoding. Doxygen uses libiconv (or the iconv built into libc) for the transcoding.
+# See http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py
+
+FILE_PATTERNS          =
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the output.
+# The symbol name can be a fully qualified name, a word, or if the wildcard * is used,
+# a substring. Examples: ANamespace, AClass, AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.  If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.  Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.  The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default)
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default)
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.  Otherwise they will link to the documentstion.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE               =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX         = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA             =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD                =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.  This is useful
+# if you want to understand what is going on.  On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+#   TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#   TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see http://www.mcternan.me.uk/mscgen/) to
+# produce the chart and insert it in the documentation. The MSCGEN_PATH tag allows you to
+# specify the directory where the mscgen tool resides. If left empty the tool is assumed to
+# be found in the default search path.
+
+MSCGEN_PATH            =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = NO
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK               = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will
+# generate a call dependency graph for every global function or class method.
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then doxygen will
+# generate a caller dependency graph for every global function or class method.
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS           =
+
+# The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen will always
+# show the root nodes and its direct children regardless of this setting.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, which results in a white background.
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP            = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE           = NO
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/access.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,423 @@
+
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "root.h"
+#include "mem.h"
+
+#include "enum.h"
+#include "aggregate.h"
+#include "init.h"
+#include "attrib.h"
+#include "scope.h"
+#include "id.h"
+#include "mtype.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "expression.h"
+#include "module.h"
+
+#define LOG 0
+
+/* Code to do access checks
+ */
+
+int hasPackageAccess(Scope *sc, Dsymbol *s);
+
+/****************************************
+ * Return PROT access for Dsymbol smember in this declaration.
+ */
+
+enum PROT AggregateDeclaration::getAccess(Dsymbol *smember)
+{
+    return PROTpublic;
+}
+
+enum PROT StructDeclaration::getAccess(Dsymbol *smember)
+{
+    enum PROT access_ret = PROTnone;
+
+#if LOG
+    printf("+StructDeclaration::getAccess(this = '%s', smember = '%s')\n",
+	toChars(), smember->toChars());
+#endif
+    if (smember->toParent() == this)
+    {
+	access_ret = smember->prot();
+    }
+    else if (smember->isDeclaration()->isStatic())
+    {
+	access_ret = smember->prot();
+    }
+    return access_ret;
+}
+
+enum PROT ClassDeclaration::getAccess(Dsymbol *smember)
+{
+    enum PROT access_ret = PROTnone;
+
+#if LOG
+    printf("+ClassDeclaration::getAccess(this = '%s', smember = '%s')\n",
+	toChars(), smember->toChars());
+#endif
+    if (smember->toParent() == this)
+    {
+	access_ret = smember->prot();
+    }
+    else
+    {
+	enum PROT access;
+	int i;
+
+	if (smember->isDeclaration()->isStatic())
+	{
+	    access_ret = smember->prot();
+	}
+
+	for (i = 0; i < baseclasses.dim; i++)
+	{   BaseClass *b = (BaseClass *)baseclasses.data[i];
+
+	    access = b->base->getAccess(smember);
+	    switch (access)
+	    {
+		case PROTnone:
+		    break;
+
+		case PROTprivate:
+		    access = PROTnone;	// private members of base class not accessible
+		    break;
+
+		case PROTpackage:
+		case PROTprotected:
+		case PROTpublic:
+		case PROTexport:
+		    // If access is to be tightened
+		    if (b->protection < access)
+			access = b->protection;
+
+		    // Pick path with loosest access
+		    if (access > access_ret)
+			access_ret = access;
+		    break;
+
+		default:
+		    assert(0);
+	    }
+	}
+    }
+#if LOG
+    printf("-ClassDeclaration::getAccess(this = '%s', smember = '%s') = %d\n",
+	toChars(), smember->toChars(), access_ret);
+#endif
+    return access_ret;
+}
+
+/********************************************************
+ * Helper function for ClassDeclaration::accessCheck()
+ * Returns:
+ *	0	no access
+ * 	1	access
+ */
+
+static int accessCheckX(
+	Dsymbol *smember,
+	Dsymbol *sfunc,
+	AggregateDeclaration *dthis,
+	AggregateDeclaration *cdscope)
+{
+    assert(dthis);
+
+#if 0
+    printf("accessCheckX for %s.%s in function %s() in scope %s\n",
+	dthis->toChars(), smember->toChars(),
+	sfunc ? sfunc->toChars() : "NULL",
+	cdscope ? cdscope->toChars() : "NULL");
+#endif
+    if (dthis->hasPrivateAccess(sfunc) ||
+	dthis->isFriendOf(cdscope))
+    {
+	if (smember->toParent() == dthis)
+	    return 1;
+	else
+	{
+	    ClassDeclaration *cdthis = dthis->isClassDeclaration();
+	    if (cdthis)
+	    {
+		for (int i = 0; i < cdthis->baseclasses.dim; i++)
+		{   BaseClass *b = (BaseClass *)cdthis->baseclasses.data[i];
+		    enum PROT access;
+
+		    access = b->base->getAccess(smember);
+		    if (access >= PROTprotected ||
+			accessCheckX(smember, sfunc, b->base, cdscope)
+		       )
+			return 1;
+
+		}
+	    }
+	}
+    }
+    else
+    {
+	if (smember->toParent() != dthis)
+	{
+	    ClassDeclaration *cdthis = dthis->isClassDeclaration();
+	    if (cdthis)
+	    {
+		for (int i = 0; i < cdthis->baseclasses.dim; i++)
+		{   BaseClass *b = (BaseClass *)cdthis->baseclasses.data[i];
+
+		    if (accessCheckX(smember, sfunc, b->base, cdscope))
+			return 1;
+		}
+	    }
+	}
+    }
+    return 0;
+}
+
+/*******************************
+ * Do access check for member of this class, this class being the
+ * type of the 'this' pointer used to access smember.
+ */
+
+void AggregateDeclaration::accessCheck(Loc loc, Scope *sc, Dsymbol *smember)
+{
+    int result;
+
+    FuncDeclaration *f = sc->func;
+    AggregateDeclaration *cdscope = sc->getStructClassScope();
+    enum PROT access;
+
+#if LOG
+    printf("AggregateDeclaration::accessCheck() for %s.%s in function %s() in scope %s\n",
+	toChars(), smember->toChars(),
+	f ? f->toChars() : NULL,
+	cdscope ? cdscope->toChars() : NULL);
+#endif
+
+    Dsymbol *smemberparent = smember->toParent();
+    if (!smemberparent || !smemberparent->isAggregateDeclaration())
+    {
+#if LOG
+	printf("not an aggregate member\n");
+#endif
+	return;				// then it is accessible
+    }
+
+    // BUG: should enable this check
+    //assert(smember->parent->isBaseOf(this, NULL));
+
+    if (smemberparent == this)
+    {	enum PROT access = smember->prot();
+
+	result = access >= PROTpublic ||
+		hasPrivateAccess(f) ||
+		isFriendOf(cdscope) ||
+		(access == PROTpackage && hasPackageAccess(sc, this));
+#if LOG
+	printf("result1 = %d\n", result);
+#endif
+    }
+    else if ((access = this->getAccess(smember)) >= PROTpublic)
+    {
+	result = 1;
+#if LOG
+	printf("result2 = %d\n", result);
+#endif
+    }
+    else if (access == PROTpackage && hasPackageAccess(sc, this))
+    {
+	result = 1;
+#if LOG
+	printf("result3 = %d\n", result);
+#endif
+    }
+    else
+    {
+	result = accessCheckX(smember, f, this, cdscope);
+#if LOG
+	printf("result4 = %d\n", result);
+#endif
+    }
+    if (!result)
+    {
+	error(loc, "member %s is not accessible", smember->toChars());
+    }
+}
+
+/****************************************
+ * Determine if this is the same or friend of cd.
+ */
+
+int AggregateDeclaration::isFriendOf(AggregateDeclaration *cd)
+{
+#if LOG
+    printf("AggregateDeclaration::isFriendOf(this = '%s', cd = '%s')\n", toChars(), cd ? cd->toChars() : "null");
+#endif
+    if (this == cd)
+	return 1;
+
+    // Friends if both are in the same module
+    //if (toParent() == cd->toParent())
+    if (cd && getModule() == cd->getModule())
+    {
+#if LOG
+	printf("\tin same module\n");
+#endif
+	return 1;
+    }
+
+#if LOG
+    printf("\tnot friend\n");
+#endif
+    return 0;
+}
+
+/****************************************
+ * Determine if scope sc has package level access to s.
+ */
+
+int hasPackageAccess(Scope *sc, Dsymbol *s)
+{
+#if LOG
+    printf("hasPackageAccess(s = '%s', sc = '%p')\n", s->toChars(), sc);
+#endif
+
+    for (; s; s = s->parent)
+    {
+	if (s->isPackage() && !s->isModule())
+	    break;
+    }
+#if LOG
+    if (s)
+	printf("\tthis is in package '%s'\n", s->toChars());
+#endif
+
+    if (s && s == sc->module->parent)
+    {
+#if LOG
+	printf("\ts is in same package as sc\n");
+#endif
+	return 1;
+    }
+
+
+#if LOG
+    printf("\tno package access\n");
+#endif
+    return 0;
+}
+
+/**********************************
+ * Determine if smember has access to private members of this declaration.
+ */
+
+int AggregateDeclaration::hasPrivateAccess(Dsymbol *smember)
+{
+    if (smember)
+    {	AggregateDeclaration *cd = NULL;
+	Dsymbol *smemberparent = smember->toParent();
+	if (smemberparent)
+	    cd = smemberparent->isAggregateDeclaration();
+
+#if LOG
+	printf("AggregateDeclaration::hasPrivateAccess(class %s, member %s)\n",
+		toChars(), smember->toChars());
+#endif
+
+	if (this == cd)		// smember is a member of this class
+	{
+#if LOG
+	    printf("\tyes 1\n");
+#endif
+	    return 1;		// so we get private access
+	}
+
+	// If both are members of the same module, grant access
+	while (1)
+	{   Dsymbol *sp = smember->toParent();
+	    if (sp->isFuncDeclaration() && smember->isFuncDeclaration())
+		smember = sp;
+	    else
+		break;
+	}
+	if (!cd && toParent() == smember->toParent())
+	{
+#if LOG
+	    printf("\tyes 2\n");
+#endif
+	    return 1;
+	}
+	if (!cd && getModule() == smember->getModule())
+	{
+#if LOG
+	    printf("\tyes 3\n");
+#endif
+	    return 1;
+	}
+    }
+#if LOG
+    printf("\tno\n");
+#endif
+    return 0;
+}
+
+/****************************************
+ * Check access to d for expression e.d
+ */
+
+void accessCheck(Loc loc, Scope *sc, Expression *e, Declaration *d)
+{
+#if LOG
+    if (e)
+    {	printf("accessCheck(%s . %s)\n", e->toChars(), d->toChars());
+	printf("\te->type = %s\n", e->type->toChars());
+    }
+    else
+    {
+	//printf("accessCheck(%s)\n", d->toChars());
+    }
+#endif
+    if (!e)
+    {
+	if (d->prot() == PROTprivate && d->getModule() != sc->module ||
+	    d->prot() == PROTpackage && !hasPackageAccess(sc, d))
+
+	    error(loc, "%s %s.%s is not accessible from %s",
+		d->kind(), d->getModule()->toChars(), d->toChars(), sc->module->toChars());
+    }
+    else if (e->type->ty == Tclass)
+    {   // Do access check
+	ClassDeclaration *cd;
+
+	cd = (ClassDeclaration *)(((TypeClass *)e->type)->sym);
+#if 1
+	if (e->op == TOKsuper)
+	{   ClassDeclaration *cd2;
+
+	    cd2 = sc->func->toParent()->isClassDeclaration();
+	    if (cd2)
+		cd = cd2;
+	}
+#endif
+	cd->accessCheck(loc, sc, d);
+    }
+    else if (e->type->ty == Tstruct)
+    {   // Do access check
+	StructDeclaration *cd;
+
+	cd = (StructDeclaration *)(((TypeStruct *)e->type)->sym);
+	cd->accessCheck(loc, sc, d);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/aggregate.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,256 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#ifndef DMD_AGGREGATE_H
+#define DMD_AGGREGATE_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include "root.h"
+#include "dsymbol.h"
+
+struct Identifier;
+struct Type;
+struct TypeFunction;
+struct Expression;
+struct FuncDeclaration;
+struct CtorDeclaration;
+struct DtorDeclaration;
+struct InvariantDeclaration;
+struct NewDeclaration;
+struct DeleteDeclaration;
+struct InterfaceDeclaration;
+struct ClassInfoDeclaration;
+struct VarDeclaration;
+struct dt_t;
+
+namespace llvm
+{
+    class Type;
+    class Value;
+    class Constant;
+}
+
+struct AggregateDeclaration : ScopeDsymbol
+{
+    Type *type;
+    unsigned storage_class;
+    enum PROT protection;
+    Type *handle;		// 'this' type
+    unsigned structsize;	// size of struct
+    unsigned alignsize;		// size of struct for alignment purposes
+    unsigned structalign;	// struct member alignment in effect
+    int hasUnions;		// set if aggregate has overlapping fields
+    Array fields;		// VarDeclaration fields
+    unsigned sizeok;		// set when structsize contains valid data
+				// 0: no size
+				// 1: size is correct
+				// 2: cannot determine size; fwd referenced
+    int isdeprecated;		// !=0 if deprecated
+    Scope *scope;		// !=NULL means context to use
+
+    // Special member functions
+    InvariantDeclaration *inv;		// invariant
+    NewDeclaration *aggNew;		// allocator
+    DeleteDeclaration *aggDelete;	// deallocator
+
+#ifdef IN_GCC
+    Array methods;              // flat list of all methods for debug information
+#endif
+
+    AggregateDeclaration(Loc loc, Identifier *id);
+    void semantic2(Scope *sc);
+    void semantic3(Scope *sc);
+    void inlineScan();
+    unsigned size(Loc loc);
+    static void alignmember(unsigned salign, unsigned size, unsigned *poffset);
+    Type *getType();
+    void addField(Scope *sc, VarDeclaration *v);
+    int isDeprecated();		// is aggregate deprecated?
+
+    void emitComment(Scope *sc);
+    void toDocBuffer(OutBuffer *buf);
+
+    // For access checking
+    virtual PROT getAccess(Dsymbol *smember);	// determine access to smember
+    int isFriendOf(AggregateDeclaration *cd);
+    int hasPrivateAccess(Dsymbol *smember);	// does smember have private access to members of this class?
+    void accessCheck(Loc loc, Scope *sc, Dsymbol *smember);
+
+    enum PROT prot();
+
+    // Back end
+    Symbol *stag;		// tag symbol for debug data
+    Symbol *sinit;
+    Symbol *toInitializer();
+
+    bool llvmInProgress;
+    llvm::Type* llvmType;
+    llvm::Value* llvmVtbl;
+    llvm::Constant* llvmInitZ;
+    virtual unsigned offsetToIndex(unsigned os); // converts a DMD field offsets to LLVM struct index
+
+    AggregateDeclaration *isAggregateDeclaration() { return this; }
+};
+
+struct AnonymousAggregateDeclaration : AggregateDeclaration
+{
+    AnonymousAggregateDeclaration()
+	: AggregateDeclaration(0, NULL)
+    {
+    }
+
+    AnonymousAggregateDeclaration *isAnonymousAggregateDeclaration() { return this; }
+};
+
+struct StructDeclaration : AggregateDeclaration
+{
+    int zeroInit;		// !=0 if initialize with 0 fill
+
+    StructDeclaration(Loc loc, Identifier *id);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    void semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    char *mangle();
+    char *kind();
+    void toDocBuffer(OutBuffer *buf);
+
+    PROT getAccess(Dsymbol *smember);	// determine access to smember
+
+    void toObjFile();			// compile to .obj file
+    void toDt(dt_t **pdt);
+    void toDebug();			// to symbolic debug info
+
+    StructDeclaration *isStructDeclaration() { return this; }
+};
+
+struct UnionDeclaration : StructDeclaration
+{
+    UnionDeclaration(Loc loc, Identifier *id);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    char *kind();
+
+    UnionDeclaration *isUnionDeclaration() { return this; }
+};
+
+struct BaseClass
+{
+    Type *type;				// (before semantic processing)
+    enum PROT protection;		// protection for the base interface
+
+    ClassDeclaration *base;
+    int offset;				// 'this' pointer offset
+    Array vtbl;				// for interfaces: Array of FuncDeclaration's
+					// making up the vtbl[]
+
+    int baseInterfaces_dim;
+    BaseClass *baseInterfaces;		// if BaseClass is an interface, these
+					// are a copy of the InterfaceDeclaration::interfaces
+
+    BaseClass();
+    BaseClass(Type *type, enum PROT protection);
+
+    int fillVtbl(ClassDeclaration *cd, Array *vtbl, int newinstance);
+    void copyBaseInterfaces(BaseClasses *);
+};
+
+#define CLASSINFO_SIZE 	(0x3C+12)	// value of ClassInfo.size
+
+struct ClassDeclaration : AggregateDeclaration
+{
+    static ClassDeclaration *object;
+    static ClassDeclaration *classinfo;
+
+    ClassDeclaration *baseClass;	// NULL only if this is Object
+    CtorDeclaration *ctor;
+    CtorDeclaration *defaultCtor;	// default constructor
+    FuncDeclarations dtors;		// Array of destructors
+    FuncDeclaration *staticCtor;
+    FuncDeclaration *staticDtor;
+    Array vtbl;				// Array of FuncDeclaration's making up the vtbl[]
+    Array vtblFinal;			// More FuncDeclaration's that aren't in vtbl[]
+
+    BaseClasses baseclasses;		// Array of BaseClass's; first is super,
+					// rest are Interface's
+
+    int interfaces_dim;
+    BaseClass **interfaces;		// interfaces[interfaces_dim] for this class
+					// (does not include baseClass)
+
+    BaseClasses *vtblInterfaces;	// array of base interfaces that have
+					// their own vtbl[]
+
+    ClassInfoDeclaration *vclassinfo;	// the ClassInfo object for this ClassDeclaration
+    int com;				// !=0 if this is a COM class
+    int isauto;				// !=0 if this is an auto class
+    int isabstract;			// !=0 if abstract class
+
+    int isnested;			// !=0 if is nested
+    VarDeclaration *vthis;		// 'this' parameter if this class is nested
+
+    ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    void semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    int isBaseOf2(ClassDeclaration *cd);
+
+    #define OFFSET_RUNTIME 0x76543210
+    virtual int isBaseOf(ClassDeclaration *cd, int *poffset);
+
+    Dsymbol *search(Loc, Identifier *ident, int flags);
+    FuncDeclaration *findFunc(Identifier *ident, TypeFunction *tf);
+    void interfaceSemantic(Scope *sc);
+    int isNested();
+    int isCOMclass();
+    int isAbstract();
+    virtual int vtblOffset();
+    char *kind();
+    char *mangle();
+    void toDocBuffer(OutBuffer *buf);
+
+    PROT getAccess(Dsymbol *smember);	// determine access to smember
+
+    void addLocalClass(ClassDeclarations *);
+
+    // Back end
+    void toObjFile();			// compile to .obj file
+    void toDebug();
+    unsigned baseVtblOffset(BaseClass *bc);
+    Symbol *toSymbol();
+    Symbol *toVtblSymbol();
+    void toDt(dt_t **pdt);
+    void toDt2(dt_t **pdt, ClassDeclaration *cd);
+
+    Symbol *vtblsym;
+
+    virtual unsigned offsetToIndex(unsigned os);
+
+    ClassDeclaration *isClassDeclaration() { return (ClassDeclaration *)this; }
+};
+
+struct InterfaceDeclaration : ClassDeclaration
+{
+    InterfaceDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    void semantic(Scope *sc);
+    int isBaseOf(ClassDeclaration *cd, int *poffset);
+    int isBaseOf(BaseClass *bc, int *poffset);
+    char *kind();
+    int vtblOffset();
+
+    void toObjFile();			// compile to .obj file
+    Symbol *toSymbol();
+
+    InterfaceDeclaration *isInterfaceDeclaration() { return this; }
+};
+
+#endif /* DMD_AGGREGATE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/array.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,220 @@
+
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <assert.h>
+
+#if _MSC_VER
+#include <malloc.h>
+#endif
+
+#if IN_GCC
+#include "gdc_alloca.h"
+#endif
+
+#if _WIN32
+#include <windows.h>
+#endif
+
+#ifndef _WIN32
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <utime.h>
+#endif
+
+#include "port.h"
+#include "root.h"
+#include "dchar.h"
+#include "mem.h"
+
+
+/********************************* Array ****************************/
+
+Array::Array()
+{
+    data = NULL;
+    dim = 0;
+    allocdim = 0;
+}
+
+Array::~Array()
+{
+    mem.free(data);
+}
+
+void Array::mark()
+{   unsigned u;
+
+    mem.mark(data);
+    for (u = 0; u < dim; u++)
+	mem.mark(data[u]);	// BUG: what if arrays of Object's?
+}
+
+void Array::reserve(unsigned nentries)
+{
+    //printf("Array::reserve: size = %d, offset = %d, nbytes = %d\n", size, offset, nbytes);
+    if (allocdim - dim < nentries)
+    {
+	allocdim = dim + nentries;
+	data = (void **)mem.realloc(data, allocdim * sizeof(*data));
+    }
+}
+
+void Array::setDim(unsigned newdim)
+{
+    if (dim < newdim)
+    {
+	reserve(newdim - dim);
+    }
+    dim = newdim;
+}
+
+void Array::fixDim()
+{
+    if (dim != allocdim)
+    {	data = (void **)mem.realloc(data, dim * sizeof(*data));
+	allocdim = dim;
+    }
+}
+
+void Array::push(void *ptr)
+{
+    reserve(1);
+    data[dim++] = ptr;
+}
+
+void *Array::pop()
+{
+    return data[--dim];
+}
+
+void Array::shift(void *ptr)
+{
+    reserve(1);
+    memmove(data + 1, data, dim * sizeof(*data));
+    data[0] = ptr;
+    dim++;
+}
+
+void Array::insert(unsigned index, void *ptr)
+{
+    reserve(1);
+    memmove(data + index + 1, data + index, (dim - index) * sizeof(*data));
+    data[index] = ptr;
+    dim++;
+}
+
+
+void Array::insert(unsigned index, Array *a)
+{
+    if (a)
+    {	unsigned d;
+
+	d = a->dim;
+	reserve(d);
+	if (dim != index)
+	    memmove(data + index + d, data + index, (dim - index) * sizeof(*data));
+	memcpy(data + index, a->data, d * sizeof(*data));
+	dim += d;
+    }
+}
+
+
+/***********************************
+ * Append array a to this array.
+ */
+
+void Array::append(Array *a)
+{
+    insert(dim, a);
+}
+
+void Array::remove(unsigned i)
+{
+    memmove(data + i, data + i + 1, (dim - i) * sizeof(data[0]));
+    dim--;
+}
+
+char *Array::toChars()
+{
+    unsigned len;
+    unsigned u;
+    char **buf;
+    char *str;
+    char *p;
+
+    buf = (char **)alloca(dim * sizeof(char *));
+    len = 2;
+    for (u = 0; u < dim; u++)
+    {
+	buf[u] = ((Object *)data[u])->toChars();
+	len += strlen(buf[u]) + 1;
+    }
+    str = (char *)mem.malloc(len);
+
+    str[0] = '[';
+    p = str + 1;
+    for (u = 0; u < dim; u++)
+    {
+	if (u)
+	    *p++ = ',';
+	len = strlen(buf[u]);
+	memcpy(p,buf[u],len);
+	p += len;
+    }
+    *p++ = ']';
+    *p = 0;
+    return str;
+}
+
+void Array::zero()
+{
+    memset(data,0,dim * sizeof(data[0]));
+}
+
+void *Array::tos()
+{
+    return dim ? data[dim - 1] : NULL;
+}
+
+int
+#if _WIN32
+  __cdecl
+#endif
+	Array_sort_compare(const void *x, const void *y)
+{
+    Object *ox = *(Object **)x;
+    Object *oy = *(Object **)y;
+
+    return ox->compare(oy);
+}
+
+void Array::sort()
+{
+    if (dim)
+    {
+	qsort(data, dim, sizeof(Object *), Array_sort_compare);
+    }
+}
+
+Array *Array::copy()
+{
+    Array *a = new Array();
+
+    a->setDim(dim);
+    memcpy(a->data, data, dim * sizeof(void *));
+    return a;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/arraytypes.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,51 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 2006-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#ifndef DMD_ARRAYTYPES_H
+#define DMD_ARRAYTYPES_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+
+#include "root.h"
+
+struct Expression;
+struct Statement;
+struct BaseClass;
+struct TemplateParameter;
+struct FuncDeclaration;
+struct Identifier;
+struct Initializer;
+
+struct TemplateParameters : Array { };
+
+struct Expressions : Array { };
+
+struct Statements : Array { };
+
+struct BaseClasses : Array { };
+
+struct ClassDeclarations : Array { };
+
+struct Dsymbols : Array { };
+
+struct Objects : Array { };
+
+struct FuncDeclarations : Array { };
+
+struct Arguments : Array { };
+
+struct Identifiers : Array { };
+
+struct Initializers : Array { };
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/artistic.txt	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,117 @@
+
+
+
+
+			 The "Artistic License"
+
+				Preamble
+
+The intent of this document is to state the conditions under which a
+Package may be copied, such that the Copyright Holder maintains some
+semblance of artistic control over the development of the package,
+while giving the users of the package the right to use and distribute
+the Package in a more-or-less customary fashion, plus the right to make
+reasonable modifications.
+
+Definitions:
+
+	"Package" refers to the collection of files distributed by the
+	Copyright Holder, and derivatives of that collection of files
+	created through textual modification.
+
+	"Standard Version" refers to such a Package if it has not been
+	modified, or has been modified in accordance with the wishes
+	of the Copyright Holder as specified below.
+
+	"Copyright Holder" is whoever is named in the copyright or
+	copyrights for the package.
+
+	"You" is you, if you're thinking about copying or distributing
+	this Package.
+
+	"Reasonable copying fee" is whatever you can justify on the
+	basis of media cost, duplication charges, time of people involved,
+	and so on.  (You will not be required to justify it to the
+	Copyright Holder, but only to the computing community at large
+	as a market that must bear the fee.)
+
+	"Freely Available" means that no fee is charged for the item
+	itself, though there may be fees involved in handling the item.
+	It also means that recipients of the item may redistribute it
+	under the same conditions they received it.
+
+1. You may make and give away verbatim copies of the source form of the
+Standard Version of this Package without restriction, provided that you
+duplicate all of the original copyright notices and associated disclaimers.
+
+2. You may apply bug fixes, portability fixes and other modifications
+derived from the Public Domain or from the Copyright Holder.  A Package
+modified in such a way shall still be considered the Standard Version.
+
+3. You may otherwise modify your copy of this Package in any way, provided
+that you insert a prominent notice in each changed file stating how and
+when you changed that file, and provided that you do at least ONE of the
+following:
+
+    a) place your modifications in the Public Domain or otherwise make them
+    Freely Available, such as by posting said modifications to Usenet or
+    an equivalent medium, or placing the modifications on a major archive
+    site such as uunet.uu.net, or by allowing the Copyright Holder to include
+    your modifications in the Standard Version of the Package.
+
+    b) use the modified Package only within your corporation or organization.
+
+    c) rename any non-standard executables so the names do not conflict
+    with standard executables, which must also be provided, and provide
+    a separate manual page for each non-standard executable that clearly
+    documents how it differs from the Standard Version.
+
+    d) make other distribution arrangements with the Copyright Holder.
+
+4. You may distribute the programs of this Package in object code or
+executable form, provided that you do at least ONE of the following:
+
+    a) distribute a Standard Version of the executables and library files,
+    together with instructions (in the manual page or equivalent) on where
+    to get the Standard Version.
+
+    b) accompany the distribution with the machine-readable source of
+    the Package with your modifications.
+
+    c) give non-standard executables non-standard names, and clearly
+    document the differences in manual pages (or equivalent), together
+    with instructions on where to get the Standard Version.
+
+    d) make other distribution arrangements with the Copyright Holder.
+
+5. You may charge a reasonable copying fee for any distribution of this
+Package.  You may charge any fee you choose for support of this
+Package.  You may not charge a fee for this Package itself.  However,
+you may distribute this Package in aggregate with other (possibly
+commercial) programs as part of a larger (possibly commercial) software
+distribution provided that you do not advertise this Package as a
+product of your own.  You may embed this Package's interpreter within
+an executable of yours (by linking); this shall be construed as a mere
+form of aggregation, provided that the complete Standard Version of the
+interpreter is so embedded.
+
+6. The source code and object code supplied as input to or produced as
+output from the programs of this Package do not automatically fall
+under the copyright of this Package, but belong to whoever generated
+them, and may be sold commercially, and may be aggregated with this
+Package.
+
+7. Aggregation of this Package with a commercial distribution is always
+permitted provided that the use of this Package is embedded; that is,
+when no overt attempt is made to make this Package's interfaces visible
+to the end user of the commercial distribution.  Such use shall not be
+construed as a distribution of this Package.
+
+8. The name of the Copyright Holder may not be used to endorse or promote
+products derived from this software without specific prior written permission.
+
+9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+				The End
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/attrib.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,1249 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#if _WIN32 || IN_GCC || IN_LLVM
+#include "mem.h"
+#elif linux
+#include "../root/mem.h"
+#endif
+
+#include "init.h"
+#include "declaration.h"
+#include "attrib.h"
+#include "cond.h"
+#include "scope.h"
+#include "id.h"
+#include "expression.h"
+#include "dsymbol.h"
+#include "aggregate.h"
+#include "module.h"
+#include "parse.h"
+
+#include "../gen/enums.h"
+
+extern void obj_includelib(char *name);
+
+
+/********************************* AttribDeclaration ****************************/
+
+AttribDeclaration::AttribDeclaration(Array *decl)
+	: Dsymbol()
+{
+    this->decl = decl;
+}
+
+Array *AttribDeclaration::include(Scope *sc, ScopeDsymbol *sd)
+{
+    return decl;
+}
+
+int AttribDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum)
+{
+    unsigned i;
+    int m = 0;
+    Array *d = include(sc, sd);
+
+    if (d)
+    {
+	for (i = 0; i < d->dim; i++)
+	{   Dsymbol *s;
+
+	    s = (Dsymbol *)d->data[i];
+	    m |= s->addMember(sc, sd, m | memnum);
+	}
+    }
+    return m;
+}
+
+void AttribDeclaration::semantic(Scope *sc)
+{
+    Array *d = include(sc, NULL);
+
+    //printf("\tAttribDeclaration::semantic '%s'\n",toChars());
+    if (d)
+    {
+	for (unsigned i = 0; i < d->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)d->data[i];
+
+	    s->semantic(sc);
+	}
+    }
+}
+
+void AttribDeclaration::semantic2(Scope *sc)
+{
+    unsigned i;
+    Array *d = include(sc, NULL);
+
+    if (d)
+    {
+	for (i = 0; i < d->dim; i++)
+	{   Dsymbol *s;
+
+	    s = (Dsymbol *)d->data[i];
+	    s->semantic2(sc);
+	}
+    }
+}
+
+void AttribDeclaration::semantic3(Scope *sc)
+{
+    unsigned i;
+    Array *d = include(sc, NULL);
+
+    if (d)
+    {
+	for (i = 0; i < d->dim; i++)
+	{   Dsymbol *s;
+
+	    s = (Dsymbol *)d->data[i];
+	    s->semantic3(sc);
+	}
+    }
+}
+
+void AttribDeclaration::inlineScan()
+{
+    unsigned i;
+    Array *d = include(NULL, NULL);
+
+    if (d)
+    {
+	for (i = 0; i < d->dim; i++)
+	{   Dsymbol *s;
+
+	    s = (Dsymbol *)d->data[i];
+	    //printf("AttribDeclaration::inlineScan %s\n", s->toChars());
+	    s->inlineScan();
+	}
+    }
+}
+
+void AttribDeclaration::addComment(unsigned char *comment)
+{
+    if (comment)
+    {
+	unsigned i;
+	Array *d = include(NULL, NULL);
+
+	if (d)
+	{
+	    for (i = 0; i < d->dim; i++)
+	    {   Dsymbol *s;
+
+		s = (Dsymbol *)d->data[i];
+		//printf("AttribDeclaration::addComment %s\n", s->toChars());
+		s->addComment(comment);
+	    }
+	}
+    }
+}
+
+void AttribDeclaration::emitComment(Scope *sc)
+{
+    //printf("AttribDeclaration::emitComment(sc = %p)\n", sc);
+
+    /* If generating doc comment, skip this because if we're inside
+     * a template, then include(NULL, NULL) will fail.
+     */
+//    if (sc->docbuf)
+//	return;
+
+    unsigned i;
+    Array *d = include(NULL, NULL);
+
+    if (d)
+    {
+	for (i = 0; i < d->dim; i++)
+	{   Dsymbol *s;
+
+	    s = (Dsymbol *)d->data[i];
+	    //printf("AttribDeclaration::emitComment %s\n", s->toChars());
+	    s->emitComment(sc);
+	}
+    }
+}
+
+void AttribDeclaration::toObjFile()
+{
+    unsigned i;
+    Array *d = include(NULL, NULL);
+
+    if (d)
+    {
+	for (i = 0; i < d->dim; i++)
+	{   Dsymbol *s;
+
+	    s = (Dsymbol *)d->data[i];
+	    s->toObjFile();
+	}
+    }
+}
+
+int AttribDeclaration::hasPointers()
+{
+    Array *d = include(NULL, NULL);
+
+    if (d)
+    {
+	for (size_t i = 0; i < d->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)d->data[i];
+	    if (s->hasPointers())
+		return 1;
+	}
+    }
+    return 0;
+}
+
+char *AttribDeclaration::kind()
+{
+    return "attribute";
+}
+
+int AttribDeclaration::oneMember(Dsymbol **ps)
+{
+    Array *d = include(NULL, NULL);
+
+    return Dsymbol::oneMembers(d, ps);
+}
+
+void AttribDeclaration::checkCtorConstInit()
+{
+    unsigned i;
+    Array *d = include(NULL, NULL);
+
+    if (d)
+    {
+	for (i = 0; i < d->dim; i++)
+	{   Dsymbol *s;
+
+	    s = (Dsymbol *)d->data[i];
+	    s->checkCtorConstInit();
+	}
+    }
+}
+
+/****************************************
+ */
+
+void AttribDeclaration::addLocalClass(ClassDeclarations *aclasses)
+{   unsigned i;
+    Array *d = include(NULL, NULL);
+
+    if (d)
+    {
+	for (i = 0; i < d->dim; i++)
+	{   Dsymbol *s;
+
+	    s = (Dsymbol *)d->data[i];
+	    s->addLocalClass(aclasses);
+	}
+    }
+}
+
+
+void AttribDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    if (decl)
+    {
+	buf->writenl();
+	buf->writeByte('{');
+	buf->writenl();
+	for (unsigned i = 0; i < decl->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)decl->data[i];
+
+	    buf->writestring("    ");
+	    s->toCBuffer(buf, hgs);
+	}
+	buf->writeByte('}');
+    }
+    else
+	buf->writeByte(';');
+    buf->writenl();
+}
+
+/************************* StorageClassDeclaration ****************************/
+
+StorageClassDeclaration::StorageClassDeclaration(unsigned stc, Array *decl)
+	: AttribDeclaration(decl)
+{
+    this->stc = stc;
+}
+
+Dsymbol *StorageClassDeclaration::syntaxCopy(Dsymbol *s)
+{
+    StorageClassDeclaration *scd;
+
+    assert(!s);
+    scd = new StorageClassDeclaration(stc, Dsymbol::arraySyntaxCopy(decl));
+    return scd;
+}
+
+void StorageClassDeclaration::semantic(Scope *sc)
+{
+    if (decl)
+    {	unsigned stc_save = sc->stc;
+
+	if (stc & (STCauto | STCscope | STCstatic | STCextern))
+	    sc->stc &= ~(STCauto | STCscope | STCstatic | STCextern);
+	sc->stc |= stc;
+	for (unsigned i = 0; i < decl->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)decl->data[i];
+
+	    s->semantic(sc);
+	}
+	sc->stc = stc_save;
+    }
+    else
+	sc->stc = stc;
+}
+
+void StorageClassDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    struct SCstring
+    {
+	int stc;
+	enum TOK tok;
+    };
+
+    static SCstring table[] =
+    {
+	{ STCauto,         TOKauto },
+	{ STCscope,        TOKscope },
+	{ STCstatic,       TOKstatic },
+	{ STCextern,       TOKextern },
+	{ STCconst,        TOKconst },
+	{ STCfinal,        TOKfinal },
+	{ STCabstract,     TOKabstract },
+	{ STCsynchronized, TOKsynchronized },
+	{ STCdeprecated,   TOKdeprecated },
+	{ STCoverride,     TOKoverride },
+    };
+
+    int written = 0;
+    for (int i = 0; i < sizeof(table)/sizeof(table[0]); i++)
+    {
+	if (stc & table[i].stc)
+	{
+	    if (written)
+		buf->writeByte(' ');
+	    written = 1;
+	    buf->writestring(Token::toChars(table[i].tok));
+	}
+    }
+
+    AttribDeclaration::toCBuffer(buf, hgs);
+}
+
+/********************************* LinkDeclaration ****************************/
+
+LinkDeclaration::LinkDeclaration(enum LINK p, Array *decl)
+	: AttribDeclaration(decl)
+{
+    //printf("LinkDeclaration(linkage = %d, decl = %p)\n", p, decl);
+    linkage = p;
+}
+
+Dsymbol *LinkDeclaration::syntaxCopy(Dsymbol *s)
+{
+    LinkDeclaration *ld;
+
+    assert(!s);
+    ld = new LinkDeclaration(linkage, Dsymbol::arraySyntaxCopy(decl));
+    return ld;
+}
+
+void LinkDeclaration::semantic(Scope *sc)
+{
+    //printf("LinkDeclaration::semantic(linkage = %d, decl = %p)\n", linkage, decl);
+    if (decl)
+    {	enum LINK linkage_save = sc->linkage;
+
+	sc->linkage = linkage;
+	for (unsigned i = 0; i < decl->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)decl->data[i];
+
+	    s->semantic(sc);
+	}
+	sc->linkage = linkage_save;
+    }
+    else
+    {
+	sc->linkage = linkage;
+    }
+}
+
+void LinkDeclaration::semantic3(Scope *sc)
+{
+    //printf("LinkDeclaration::semantic3(linkage = %d, decl = %p)\n", linkage, decl);
+    if (decl)
+    {	enum LINK linkage_save = sc->linkage;
+
+	sc->linkage = linkage;
+	for (unsigned i = 0; i < decl->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)decl->data[i];
+
+	    s->semantic3(sc);
+	}
+	sc->linkage = linkage_save;
+    }
+    else
+    {
+	sc->linkage = linkage;
+    }
+}
+
+void LinkDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{   char *p;
+
+    switch (linkage)
+    {
+	case LINKd:		p = "D";		break;
+	case LINKc:		p = "C";		break;
+	case LINKcpp:		p = "C++";		break;
+	case LINKwindows:	p = "Windows";		break;
+	case LINKpascal:	p = "Pascal";		break;
+	default:
+	    assert(0);
+	    break;
+    }
+    buf->writestring("extern (");
+    buf->writestring(p);
+    buf->writestring(") ");
+    AttribDeclaration::toCBuffer(buf, hgs);
+}
+
+char *LinkDeclaration::toChars()
+{
+    return "extern ()";
+}
+
+/********************************* ProtDeclaration ****************************/
+
+ProtDeclaration::ProtDeclaration(enum PROT p, Array *decl)
+	: AttribDeclaration(decl)
+{
+    protection = p;
+    //printf("decl = %p\n", decl);
+}
+
+Dsymbol *ProtDeclaration::syntaxCopy(Dsymbol *s)
+{
+    ProtDeclaration *pd;
+
+    assert(!s);
+    pd = new ProtDeclaration(protection, Dsymbol::arraySyntaxCopy(decl));
+    return pd;
+}
+
+void ProtDeclaration::semantic(Scope *sc)
+{
+    if (decl)
+    {	enum PROT protection_save = sc->protection;
+	int explicitProtection_save = sc->explicitProtection;
+
+	sc->protection = protection;
+	sc->explicitProtection = 1;
+	for (unsigned i = 0; i < decl->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)decl->data[i];
+
+	    s->semantic(sc);
+	}
+	sc->protection = protection_save;
+	sc->explicitProtection = explicitProtection_save;
+    }
+    else
+    {	sc->protection = protection;
+	sc->explicitProtection = 1;
+    }
+}
+
+void ProtDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{   char *p;
+
+    switch (protection)
+    {
+	case PROTprivate:	p = "private";		break;
+	case PROTpackage:	p = "package";		break;
+	case PROTprotected:	p = "protected";	break;
+	case PROTpublic:	p = "public";		break;
+	case PROTexport:	p = "export";		break;
+	default:
+	    assert(0);
+	    break;
+    }
+    buf->writestring(p);
+    AttribDeclaration::toCBuffer(buf, hgs);
+}
+
+/********************************* AlignDeclaration ****************************/
+
+AlignDeclaration::AlignDeclaration(unsigned sa, Array *decl)
+	: AttribDeclaration(decl)
+{
+    salign = sa;
+}
+
+Dsymbol *AlignDeclaration::syntaxCopy(Dsymbol *s)
+{
+    AlignDeclaration *ad;
+
+    assert(!s);
+    ad = new AlignDeclaration(salign, Dsymbol::arraySyntaxCopy(decl));
+    return ad;
+}
+
+void AlignDeclaration::semantic(Scope *sc)
+{
+    //printf("\tAlignDeclaration::semantic '%s'\n",toChars());
+    if (decl)
+    {	unsigned salign_save = sc->structalign;
+
+	sc->structalign = salign;
+	for (unsigned i = 0; i < decl->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)decl->data[i];
+
+	    s->semantic(sc);
+	}
+	sc->structalign = salign_save;
+    }
+    else
+	sc->structalign = salign;
+}
+
+
+void AlignDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->printf("align (%d)", salign);
+    AttribDeclaration::toCBuffer(buf, hgs);
+}
+
+/********************************* AnonDeclaration ****************************/
+
+AnonDeclaration::AnonDeclaration(Loc loc, int isunion, Array *decl)
+	: AttribDeclaration(decl)
+{
+    this->loc = loc;
+    this->isunion = isunion;
+    this->scope = NULL;
+    this->sem = 0;
+}
+
+Dsymbol *AnonDeclaration::syntaxCopy(Dsymbol *s)
+{
+    AnonDeclaration *ad;
+
+    assert(!s);
+    ad = new AnonDeclaration(loc, isunion, Dsymbol::arraySyntaxCopy(decl));
+    return ad;
+}
+
+void AnonDeclaration::semantic(Scope *sc)
+{
+    //printf("\tAnonDeclaration::semantic %s %p\n", isunion ? "union" : "struct", this);
+
+    Scope *scx = NULL;
+    if (scope)
+    {   sc = scope;
+	scx = scope;
+	scope = NULL;
+    }
+
+    assert(sc->parent);
+
+    Dsymbol *parent = sc->parent->pastMixin();
+    AggregateDeclaration *ad = parent->isAggregateDeclaration();
+
+    if (!ad || (!ad->isStructDeclaration() && !ad->isClassDeclaration()))
+    {
+	error("can only be a part of an aggregate");
+	return;
+    }
+
+    if (decl)
+    {
+	AnonymousAggregateDeclaration aad;
+	int adisunion;
+
+	if (sc->anonAgg)
+	{   ad = sc->anonAgg;
+	    adisunion = sc->inunion;
+	}
+	else
+	    adisunion = ad->isUnionDeclaration() != NULL;
+
+//	printf("\tsc->anonAgg = %p\n", sc->anonAgg);
+//	printf("\tad  = %p\n", ad);
+//	printf("\taad = %p\n", &aad);
+
+	sc = sc->push();
+	sc->anonAgg = &aad;
+	sc->stc &= ~(STCauto | STCscope | STCstatic);
+	sc->inunion = isunion;
+	sc->offset = 0;
+	sc->flags = 0;
+	aad.structalign = sc->structalign;
+	aad.parent = ad;
+
+	for (unsigned i = 0; i < decl->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)decl->data[i];
+
+	    s->semantic(sc);
+	    if (isunion)
+		sc->offset = 0;
+	    if (aad.sizeok == 2)
+	    {
+		break;
+	    }
+	}
+	sc = sc->pop();
+
+	// If failed due to forward references, unwind and try again later
+	if (aad.sizeok == 2)
+	{
+	    ad->sizeok = 2;
+	    //printf("\tsetting ad->sizeok %p to 2\n", ad);
+	    if (!sc->anonAgg)
+	    {
+		scope = scx ? scx : new Scope(*sc);
+		scope->setNoFree();
+		scope->module->addDeferredSemantic(this);
+	    }
+	    //printf("\tforward reference %p\n", this);
+	    return;
+	}
+	if (sem == 0)
+	{   Module::dprogress++;
+	    sem = 1;
+	    //printf("\tcompleted %p\n", this);
+	}
+	else
+	    ;//printf("\talready completed %p\n", this);
+
+	// 0 sized structs are set to 1 byte
+	if (aad.structsize == 0)
+	{
+	    aad.structsize = 1;
+	    aad.alignsize = 1;
+	}
+
+	// Align size of anonymous aggregate
+//printf("aad.structalign = %d, aad.alignsize = %d, sc->offset = %d\n", aad.structalign, aad.alignsize, sc->offset);
+	ad->alignmember(aad.structalign, aad.alignsize, &sc->offset);
+	//ad->structsize = sc->offset;
+//printf("sc->offset = %d\n", sc->offset);
+
+	// Add members of aad to ad
+	//printf("\tadding members of aad to '%s'\n", ad->toChars());
+	for (unsigned i = 0; i < aad.fields.dim; i++)
+	{
+	    VarDeclaration *v = (VarDeclaration *)aad.fields.data[i];
+
+	    v->offset += sc->offset;
+	    ad->fields.push(v);
+	}
+
+	// Add size of aad to ad
+	if (adisunion)
+	{
+	    if (aad.structsize > ad->structsize)
+		ad->structsize = aad.structsize;
+	    sc->offset = 0;
+	}
+	else
+	{
+	    ad->structsize = sc->offset + aad.structsize;
+	    sc->offset = ad->structsize;
+	}
+
+	if (ad->alignsize < aad.alignsize)
+	    ad->alignsize = aad.alignsize;
+    }
+}
+
+
+void AnonDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->printf(isunion ? "union" : "struct");
+    buf->writestring("\n{\n");
+    if (decl)
+    {
+	for (unsigned i = 0; i < decl->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)decl->data[i];
+
+	    //buf->writestring("    ");
+	    s->toCBuffer(buf, hgs);
+	}
+    }
+    buf->writestring("}\n");
+}
+
+char *AnonDeclaration::kind()
+{
+    return (char *)(isunion ? "anonymous union" : "anonymous struct");
+}
+
+/********************************* PragmaDeclaration ****************************/
+
+PragmaDeclaration::PragmaDeclaration(Loc loc, Identifier *ident, Expressions *args, Array *decl)
+	: AttribDeclaration(decl)
+{
+    this->loc = loc;
+    this->ident = ident;
+    this->args = args;
+}
+
+Dsymbol *PragmaDeclaration::syntaxCopy(Dsymbol *s)
+{
+    PragmaDeclaration *pd;
+
+    assert(!s);
+    pd = new PragmaDeclaration(loc, ident,
+	Expression::arraySyntaxCopy(args), Dsymbol::arraySyntaxCopy(decl));
+    return pd;
+}
+
+void PragmaDeclaration::semantic(Scope *sc)
+{   // Should be merged with PragmaStatement
+
+#if IN_LLVM
+    int llvm_internal = 0;
+    char* llvm_str1 = NULL;
+    
+#endif
+    
+    //printf("\tPragmaDeclaration::semantic '%s'\n",toChars());
+    if (ident == Id::msg)
+    {
+	if (args)
+	{
+	    for (size_t i = 0; i < args->dim; i++)
+	    {
+		Expression *e = (Expression *)args->data[i];
+
+		e = e->semantic(sc);
+		e = e->optimize(WANTvalue | WANTinterpret);
+		if (e->op == TOKstring)
+		{
+		    StringExp *se = (StringExp *)e;
+		    fprintf(stdmsg, "%.*s", (int)se->len, se->string);
+		}
+		else
+		    error("string expected for message, not '%s'", e->toChars());
+	    }
+	    fprintf(stdmsg, "\n");
+	}
+	goto Lnodecl;
+    }
+    else if (ident == Id::lib)
+    {
+	if (!args || args->dim != 1)
+	    error("string expected for library name");
+	else
+	{
+	    Expression *e = (Expression *)args->data[0];
+
+	    e = e->semantic(sc);
+	    e = e->optimize(WANTvalue | WANTinterpret);
+	    args->data[0] = (void *)e;
+	    if (e->op != TOKstring)
+		error("string expected for library name, not '%s'", e->toChars());
+	    else if (global.params.verbose)
+	    {
+		StringExp *se = (StringExp *)e;
+		char *name = (char *)mem.malloc(se->len + 1);
+		memcpy(name, se->string, se->len);
+		name[se->len] = 0;
+		printf("library   %s\n", name);
+		mem.free(name);
+	    }
+	}
+	goto Lnodecl;
+    }
+#if IN_GCC
+    else if (ident == Id::GNU_asm)
+    {
+	if (! args || args->dim != 2)
+	    error("identifier and string expected for asm name");
+	else
+	{
+	    Expression *e;
+	    Declaration *d = NULL;
+	    StringExp *s = NULL;
+
+	    e = (Expression *)args->data[0];
+	    e = e->semantic(sc);
+	    if (e->op == TOKvar)
+	    {
+		d = ((VarExp *)e)->var;
+		if (! d->isFuncDeclaration() && ! d->isVarDeclaration())
+		    d = NULL;
+	    }
+	    if (!d)
+		error("first argument of GNU_asm must be a function or variable declaration");
+
+	    e = (Expression *)args->data[1];
+	    e = e->semantic(sc);
+	    e = e->optimize(WANTvalue);
+	    if (e->op == TOKstring && ((StringExp *)e)->sz == 1)
+		s = ((StringExp *)e);
+	    else
+		error("second argument of GNU_asm must be a char string");
+
+	    if (d && s)
+		d->c_ident = Lexer::idPool((char*) s->string);
+	}
+	goto Lnodecl;
+    }
+#endif
+#if IN_LLVM
+    else if (ident == Id::LLVM_internal)
+    {
+        if (!args || args->dim < 1 || args->dim > 2)
+            error("needs 1-3 parameters");
+        else if (!decl || decl->dim < 1)
+            error("must apply to at least one declaration");
+        else
+        {
+            Expression *e;
+            StringExp *s = NULL;
+
+            e = (Expression *)args->data[0];
+            e = e->semantic(sc);
+            e = e->optimize(WANTvalue);
+            if (e->op == TOKstring && (s = (StringExp *)e))
+            {
+                char* str = (char*)s->string;
+                if (strcmp(str,"intrinsic")==0) {
+                    llvm_internal = LLVMintrinsic;
+                    assert(args->dim == 2);
+                }
+                else if (strcmp(str,"null")==0) {
+                    llvm_internal = LLVMnull;
+                    assert(args->dim == 1);
+                }
+                else if (strcmp(str,"mangle")==0) {
+                    llvm_internal = LLVMmangle;
+                    assert(args->dim == 2);
+                }
+                else if (strcmp(str,"bind")==0) {
+                    llvm_internal = LLVMbind;
+                    assert(args->dim == 2);
+                }
+                else {
+                    error("unknown pragma command: %s", str);
+                }
+            }
+            else
+            error("1st argument must be a string");
+            
+            if (llvm_internal)
+            switch (llvm_internal)
+            {
+            case LLVMintrinsic:
+            case LLVMmangle:
+            case LLVMbind:
+                e = (Expression *)args->data[1];
+                e = e->semantic(sc);
+                e = e->optimize(WANTvalue);
+                if (e->op == TOKstring && (s = (StringExp *)e)) {
+                    llvm_str1 = (char*)s->string;
+                }
+                else
+                error("2nd argument must be a string");
+                break;
+            
+            case LLVMnull:
+                break;
+            
+            default:
+                assert(0);
+            }
+        }
+    }
+#endif
+    else
+	error("unrecognized pragma(%s)", ident->toChars());
+
+    if (decl)
+    {
+	for (unsigned i = 0; i < decl->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)decl->data[i];
+
+	    s->semantic(sc);
+        
+#if IN_LLVM
+        if (llvm_internal)
+        {
+            switch(llvm_internal)
+            {
+            case LLVMintrinsic:
+            case LLVMmangle:
+                if (FuncDeclaration* fd = s->isFuncDeclaration()) {
+                    fd->llvmInternal = llvm_internal;
+                    fd->llvmInternal1 = llvm_str1;
+                }
+                else {
+                    error("may only be used on function declarations");
+                    assert(0);
+                }
+                break;
+            
+            case LLVMnull:
+                if (StaticCtorDeclaration* sd = s->isStaticCtorDeclaration()) {
+                    sd->llvmInternal = llvm_internal;
+                }
+                else {
+                    error("may only be used on static constructors");
+                    assert(0);
+                }
+                break;
+            
+            case LLVMbind:
+                if (VarDeclaration* vd = s->isVarDeclaration()) {
+                    vd->llvmInternal = llvm_internal;
+                    vd->llvmInternal1 = llvm_str1;
+                }
+                else {
+                    error("may only be used on var declarations");
+                    assert(0);
+                }
+                break;
+            
+            default:
+                assert(0 && "invalid LLVM_internal pragma got through :/");
+            }
+        }
+        
+#endif
+    }
+    }
+    return;
+
+Lnodecl:
+    if (decl)
+	error("pragma is missing closing ';'");
+}
+
+int PragmaDeclaration::oneMember(Dsymbol **ps)
+{
+    *ps = NULL;
+    return TRUE;
+}
+
+char *PragmaDeclaration::kind()
+{
+    return "pragma";
+}
+
+void PragmaDeclaration::toObjFile()
+{
+    if (ident == Id::lib)
+    {
+	assert(args && args->dim == 1);
+
+	Expression *e = (Expression *)args->data[0];
+
+	assert(e->op == TOKstring);
+
+	StringExp *se = (StringExp *)e;
+	char *name = (char *)mem.malloc(se->len + 1);
+	memcpy(name, se->string, se->len);
+	name[se->len] = 0;
+	obj_includelib(name);
+    }
+    AttribDeclaration::toObjFile();
+}
+
+void PragmaDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->printf("pragma(%s", ident->toChars());
+    if (args)
+    {
+	for (size_t i = 0; i < args->dim; i++)
+	{
+	    Expression *e = (Expression *)args->data[i];
+
+	    buf->writestring(", ");
+	    e->toCBuffer(buf, hgs);
+	}
+    }
+    buf->writestring(")");
+    AttribDeclaration::toCBuffer(buf, hgs);
+}
+
+
+/********************************* ConditionalDeclaration ****************************/
+
+ConditionalDeclaration::ConditionalDeclaration(Condition *condition, Array *decl, Array *elsedecl)
+	: AttribDeclaration(decl)
+{
+    //printf("ConditionalDeclaration::ConditionalDeclaration()\n");
+    this->condition = condition;
+    this->elsedecl = elsedecl;
+}
+
+Dsymbol *ConditionalDeclaration::syntaxCopy(Dsymbol *s)
+{
+    ConditionalDeclaration *dd;
+
+    assert(!s);
+    dd = new ConditionalDeclaration(condition->syntaxCopy(),
+	Dsymbol::arraySyntaxCopy(decl),
+	Dsymbol::arraySyntaxCopy(elsedecl));
+    return dd;
+}
+
+
+int ConditionalDeclaration::oneMember(Dsymbol **ps)
+{
+    //printf("ConditionalDeclaration::oneMember(), inc = %d\n", condition->inc);
+    if (condition->inc)
+    {
+	Array *d = condition->include(NULL, NULL) ? decl : elsedecl;
+	return Dsymbol::oneMembers(d, ps);
+    }
+    *ps = NULL;
+    return TRUE;
+}
+
+void ConditionalDeclaration::emitComment(Scope *sc)
+{
+    //printf("ConditionalDeclaration::emitComment(sc = %p)\n", sc);
+    if (condition->inc)
+    {
+	AttribDeclaration::emitComment(sc);
+    }
+}
+
+// Decide if 'then' or 'else' code should be included
+
+Array *ConditionalDeclaration::include(Scope *sc, ScopeDsymbol *sd)
+{
+    //printf("ConditionalDeclaration::include()\n");
+    assert(condition);
+    return condition->include(sc, sd) ? decl : elsedecl;
+}
+
+
+void ConditionalDeclaration::addComment(unsigned char *comment)
+{
+    /* Because addComment is called by the parser, if we called
+     * include() it would define a version before it was used.
+     * But it's no problem to drill down to both decl and elsedecl,
+     * so that's the workaround.
+     */
+
+    if (comment)
+    {
+	Array *d = decl;
+
+	for (int j = 0; j < 2; j++)
+	{
+	    if (d)
+	    {
+		for (unsigned i = 0; i < d->dim; i++)
+		{   Dsymbol *s;
+
+		    s = (Dsymbol *)d->data[i];
+		    //printf("ConditionalDeclaration::addComment %s\n", s->toChars());
+		    s->addComment(comment);
+		}
+	    }
+	    d = elsedecl;
+	}
+    }
+}
+
+void ConditionalDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    condition->toCBuffer(buf, hgs);
+    if (decl || elsedecl)
+    {
+	buf->writenl();
+	buf->writeByte('{');
+	buf->writenl();
+	if (decl)
+	{
+	    for (unsigned i = 0; i < decl->dim; i++)
+	    {
+		Dsymbol *s = (Dsymbol *)decl->data[i];
+
+		buf->writestring("    ");
+		s->toCBuffer(buf, hgs);
+	    }
+	}
+	buf->writeByte('}');
+	if (elsedecl)
+	{
+	    buf->writenl();
+	    buf->writestring("else");
+	    buf->writenl();
+	    buf->writeByte('{');
+	    buf->writenl();
+	    for (unsigned i = 0; i < elsedecl->dim; i++)
+	    {
+		Dsymbol *s = (Dsymbol *)elsedecl->data[i];
+
+		buf->writestring("    ");
+		s->toCBuffer(buf, hgs);
+	    }
+	    buf->writeByte('}');
+	}
+    }
+    else
+	buf->writeByte(':');
+    buf->writenl();
+}
+
+/***************************** StaticIfDeclaration ****************************/
+
+StaticIfDeclaration::StaticIfDeclaration(Condition *condition,
+	Array *decl, Array *elsedecl)
+	: ConditionalDeclaration(condition, decl, elsedecl)
+{
+    //printf("StaticIfDeclaration::StaticIfDeclaration()\n");
+    sd = NULL;
+    addisdone = 0;
+}
+
+
+Dsymbol *StaticIfDeclaration::syntaxCopy(Dsymbol *s)
+{
+    StaticIfDeclaration *dd;
+
+    assert(!s);
+    dd = new StaticIfDeclaration(condition->syntaxCopy(),
+	Dsymbol::arraySyntaxCopy(decl),
+	Dsymbol::arraySyntaxCopy(elsedecl));
+    return dd;
+}
+
+
+int StaticIfDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum)
+{
+    /* This is deferred until semantic(), so that
+     * expressions in the condition can refer to declarations
+     * in the same scope, such as:
+     *
+     * template Foo(int i)
+     * {
+     *     const int j = i + 1;
+     *     static if (j == 3)
+     *         const int k;
+     * }
+     */
+    this->sd = sd;
+    int m = 0;
+
+    if (memnum == 0)
+    {	m = AttribDeclaration::addMember(sc, sd, memnum);
+	addisdone = 1;
+    }
+    return m;
+}
+
+
+void StaticIfDeclaration::semantic(Scope *sc)
+{
+    Array *d = include(sc, sd);
+
+    //printf("\tStaticIfDeclaration::semantic '%s'\n",toChars());
+    if (d)
+    {
+	if (!addisdone)
+	{   AttribDeclaration::addMember(sc, sd, 1);
+	    addisdone = 1;
+	}
+
+	for (unsigned i = 0; i < d->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)d->data[i];
+
+	    s->semantic(sc);
+	}
+    }
+}
+
+char *StaticIfDeclaration::kind()
+{
+    return "static if";
+}
+
+
+/***************************** CompileDeclaration *****************************/
+
+CompileDeclaration::CompileDeclaration(Loc loc, Expression *exp)
+    : AttribDeclaration(NULL)
+{
+    this->exp = exp;
+    this->sd = NULL;
+}
+
+Dsymbol *CompileDeclaration::syntaxCopy(Dsymbol *s)
+{
+    //printf("CompileDeclaration::syntaxCopy('%s')\n", toChars());
+    CompileDeclaration *sc = new CompileDeclaration(loc, exp->syntaxCopy());
+    return sc;
+}
+
+int CompileDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum)
+{
+    this->sd = sd;
+    return memnum;
+}
+
+void CompileDeclaration::semantic(Scope *sc)
+{
+    //printf("CompileDeclaration::semantic()\n");
+    exp = exp->semantic(sc);
+    exp = resolveProperties(sc, exp);
+    exp = exp->optimize(WANTvalue | WANTinterpret);
+    if (exp->op != TOKstring)
+    {	error("argument to mixin must be a string, not (%s)", exp->toChars());
+	return;
+    }
+    StringExp *se = (StringExp *)exp;
+    se = se->toUTF8(sc);
+    Parser p(sc->module, (unsigned char *)se->string, se->len, 0);
+    p.loc = loc;
+    p.nextToken();
+    decl = p.parseDeclDefs(0);
+    if (p.token.value != TOKeof)
+    {
+	error("incomplete mixin declaration (%s)", se->toChars());
+    }
+
+    AttribDeclaration::addMember(sc, sd, 0);
+    AttribDeclaration::semantic(sc);
+}
+
+void CompileDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("mixin(");
+    exp->toCBuffer(buf, hgs);
+    buf->writestring(");");
+    buf->writenl();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/attrib.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,165 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#ifndef DMD_ATTRIB_H
+#define DMD_ATTRIB_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include "dsymbol.h"
+
+struct Expression;
+struct Statement;
+struct LabelDsymbol;
+struct Initializer;
+struct Module;
+struct Condition;
+#ifdef _DH
+struct HdrGenState;
+#endif
+
+/**************************************************************/
+
+struct AttribDeclaration : Dsymbol
+{
+    Array *decl;	// array of Dsymbol's
+
+    AttribDeclaration(Array *decl);
+    virtual Array *include(Scope *sc, ScopeDsymbol *s);
+    int addMember(Scope *sc, ScopeDsymbol *s, int memnum);
+    void semantic(Scope *sc);
+    void semantic2(Scope *sc);
+    void semantic3(Scope *sc);
+    void inlineScan();
+    void addComment(unsigned char *comment);
+    void emitComment(Scope *sc);
+    char *kind();
+    int oneMember(Dsymbol **ps);
+    int hasPointers();
+    void checkCtorConstInit();
+    void addLocalClass(ClassDeclarations *);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    AttribDeclaration *isAttribDeclaration() { return this; }
+
+    void toObjFile();			// compile to .obj file
+};
+
+struct StorageClassDeclaration: AttribDeclaration
+{
+    unsigned stc;
+
+    StorageClassDeclaration(unsigned stc, Array *decl);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    void semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+struct LinkDeclaration : AttribDeclaration
+{
+    enum LINK linkage;
+
+    LinkDeclaration(enum LINK p, Array *decl);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    void semantic(Scope *sc);
+    void semantic3(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    char *toChars();
+};
+
+struct ProtDeclaration : AttribDeclaration
+{
+    enum PROT protection;
+
+    ProtDeclaration(enum PROT p, Array *decl);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    void semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+struct AlignDeclaration : AttribDeclaration
+{
+    unsigned salign;
+
+    AlignDeclaration(unsigned sa, Array *decl);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    void semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+struct AnonDeclaration : AttribDeclaration
+{
+    int isunion;
+    Scope *scope;		// !=NULL means context to use
+    int sem;			// 1 if successful semantic()
+
+    AnonDeclaration(Loc loc, int isunion, Array *decl);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    void semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    char *kind();
+};
+
+struct PragmaDeclaration : AttribDeclaration
+{
+    Expressions *args;		// array of Expression's
+
+    PragmaDeclaration(Loc loc, Identifier *ident, Expressions *args, Array *decl);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    void semantic(Scope *sc);
+    int oneMember(Dsymbol **ps);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    char *kind();
+    void toObjFile();			// compile to .obj file
+};
+
+struct ConditionalDeclaration : AttribDeclaration
+{
+    Condition *condition;
+    Array *elsedecl;	// array of Dsymbol's for else block
+
+    ConditionalDeclaration(Condition *condition, Array *decl, Array *elsedecl);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    int oneMember(Dsymbol **ps);
+    void emitComment(Scope *sc);
+    Array *include(Scope *sc, ScopeDsymbol *s);
+    void addComment(unsigned char *comment);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+struct StaticIfDeclaration : ConditionalDeclaration
+{
+    ScopeDsymbol *sd;
+    int addisdone;
+
+    StaticIfDeclaration(Condition *condition, Array *decl, Array *elsedecl);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    int addMember(Scope *sc, ScopeDsymbol *s, int memnum);
+    void semantic(Scope *sc);
+    char *kind();
+};
+
+// Mixin declarations
+
+struct CompileDeclaration : AttribDeclaration
+{
+    Expression *exp;
+
+    ScopeDsymbol *sd;
+
+    CompileDeclaration(Loc loc, Expression *exp);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    int addMember(Scope *sc, ScopeDsymbol *sd, int memnum);
+    void semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+#endif /* DMD_ATTRIB_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/cast.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,1419 @@
+
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <assert.h>
+
+#if _WIN32 || IN_GCC || IN_LLVM
+#include "mem.h"
+#else
+#include "../root/mem.h"
+#endif
+
+#include "expression.h"
+#include "mtype.h"
+#include "utf.h"
+#include "declaration.h"
+#include "aggregate.h"
+
+/* ==================== implicitCast ====================== */
+
+/**************************************
+ * Do an implicit cast.
+ * Issue error if it can't be done.
+ */
+
+Expression *Expression::implicitCastTo(Scope *sc, Type *t)
+{
+    //printf("implicitCastTo(%s) => %s\n", type->toChars(), t->toChars());
+    if (implicitConvTo(t))
+    {
+	if (global.params.warnings &&
+	    Type::impcnvWarn[type->toBasetype()->ty][t->toBasetype()->ty] &&
+	    op != TOKint64)
+	{
+	    Expression *e = optimize(WANTflags | WANTvalue);
+
+	    if (e->op == TOKint64)
+		return e->implicitCastTo(sc, t);
+
+	    fprintf(stdmsg, "warning - ");
+	    error("implicit conversion of expression (%s) of type %s to %s can cause loss of data",
+		toChars(), type->toChars(), t->toChars());
+	}
+	return castTo(sc, t);
+    }
+
+    Expression *e = optimize(WANTflags | WANTvalue);
+    if (e != this)
+	return e->implicitCastTo(sc, t);
+
+#if 0
+print();
+type->print();
+printf("to:\n");
+t->print();
+printf("%p %p type: %s to: %s\n", type->deco, t->deco, type->deco, t->deco);
+//printf("%p %p %p\n", type->next->arrayOf(), type, t);
+fflush(stdout);
+#endif
+    if (!t->deco)
+    {	/* Can happen with:
+	 *    enum E { One }
+	 *    class A
+	 *    { static void fork(EDG dg) { dg(E.One); }
+	 *	alias void delegate(E) EDG;
+	 *    }
+	 * Should eventually make it work.
+	 */
+	error("forward reference to type %s", t->toChars());
+    }
+    else if (t->reliesOnTident())
+	error("forward reference to type %s", t->reliesOnTident()->toChars());
+
+    error("cannot implicitly convert expression (%s) of type %s to %s",
+	toChars(), type->toChars(), t->toChars());
+    return castTo(sc, t);
+}
+
+/*******************************************
+ * Return !=0 if we can implicitly convert this to type t.
+ * Don't do the actual cast.
+ */
+
+MATCH Expression::implicitConvTo(Type *t)
+{
+#if 0
+    printf("Expression::implicitConvTo(this=%s, type=%s, t=%s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    if (!type)
+    {	error("%s is not an expression", toChars());
+	type = Type::terror;
+    }
+    if (t->ty == Tbit && isBit())
+	return MATCHconvert;
+    Expression *e = optimize(WANTvalue | WANTflags);
+    if (e != this)
+    {	//printf("optimzed to %s\n", e->toChars());
+	return e->implicitConvTo(t);
+    }
+    MATCH match = type->implicitConvTo(t);
+    if (match)
+	return match;
+#if 0
+    Type *tb = t->toBasetype();
+    if (tb->ty == Tdelegate)
+    {	TypeDelegate *td = (TypeDelegate *)tb;
+	TypeFunction *tf = (TypeFunction *)td->next;
+
+	if (!tf->varargs &&
+	    !(tf->arguments && tf->arguments->dim)
+	   )
+	{
+	    match = type->implicitConvTo(tf->next);
+	    if (match)
+		return match;
+	    if (tf->next->toBasetype()->ty == Tvoid)
+		return MATCHconvert;
+	}
+    }
+#endif
+    return MATCHnomatch;
+}
+
+
+MATCH IntegerExp::implicitConvTo(Type *t)
+{
+#if 0
+    printf("IntegerExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    if (type->equals(t))
+	return MATCHexact;
+
+    enum TY ty = type->toBasetype()->ty;
+    enum TY toty = t->toBasetype()->ty;
+
+    if (type->implicitConvTo(t) == MATCHnomatch && t->ty == Tenum)
+    {
+	return MATCHnomatch;
+    }
+
+    switch (ty)
+    {
+	case Tbit:
+	case Tbool:
+	    value &= 1;
+	    ty = Tint32;
+	    break;
+
+	case Tint8:
+	    value = (signed char)value;
+	    ty = Tint32;
+	    break;
+
+	case Tchar:
+	case Tuns8:
+	    value &= 0xFF;
+	    ty = Tint32;
+	    break;
+
+	case Tint16:
+	    value = (short)value;
+	    ty = Tint32;
+	    break;
+
+	case Tuns16:
+	case Twchar:
+	    value &= 0xFFFF;
+	    ty = Tint32;
+	    break;
+
+	case Tint32:
+	    value = (int)value;
+	    break;
+
+	case Tuns32:
+	case Tdchar:
+	    value &= 0xFFFFFFFF;
+	    ty = Tuns32;
+	    break;
+
+	default:
+	    break;
+    }
+
+    // Only allow conversion if no change in value
+    switch (toty)
+    {
+	case Tbit:
+	case Tbool:
+	    if ((value & 1) != value)
+		goto Lno;
+	    goto Lyes;
+
+	case Tint8:
+	    if ((signed char)value != value)
+		goto Lno;
+	    goto Lyes;
+
+	case Tchar:
+	case Tuns8:
+	    //printf("value = %llu %llu\n", (integer_t)(unsigned char)value, value);
+	    if ((unsigned char)value != value)
+		goto Lno;
+	    goto Lyes;
+
+	case Tint16:
+	    if ((short)value != value)
+		goto Lno;
+	    goto Lyes;
+
+	case Tuns16:
+	    if ((unsigned short)value != value)
+		goto Lno;
+	    goto Lyes;
+
+	case Tint32:
+	    if (ty == Tuns32)
+	    {
+	    }
+	    else if ((int)value != value)
+		goto Lno;
+	    goto Lyes;
+
+	case Tuns32:
+	    if (ty == Tint32)
+	    {
+	    }
+	    else if ((unsigned)value != value)
+		goto Lno;
+	    goto Lyes;
+
+	case Tdchar:
+	    if (value > 0x10FFFFUL)
+		goto Lno;
+	    goto Lyes;
+
+	case Twchar:
+	    if ((unsigned short)value != value)
+		goto Lno;
+	    goto Lyes;
+
+	case Tfloat32:
+	{
+	    volatile float f;
+	    if (type->isunsigned())
+	    {
+		f = (float)value;
+		if (f != value)
+		    goto Lno;
+	    }
+	    else
+	    {
+		f = (float)(long long)value;
+		if (f != (long long)value)
+		    goto Lno;
+	    }
+	    goto Lyes;
+	}
+
+	case Tfloat64:
+	{
+	    volatile double f;
+	    if (type->isunsigned())
+	    {
+		f = (double)value;
+		if (f != value)
+		    goto Lno;
+	    }
+	    else
+	    {
+		f = (double)(long long)value;
+		if (f != (long long)value)
+		    goto Lno;
+	    }
+	    goto Lyes;
+	}
+
+	case Tfloat80:
+	{
+	    volatile long double f;
+	    if (type->isunsigned())
+	    {
+		f = (long double)value;
+		if (f != value)
+		    goto Lno;
+	    }
+	    else
+	    {
+		f = (long double)(long long)value;
+		if (f != (long long)value)
+		    goto Lno;
+	    }
+	    goto Lyes;
+	}
+    }
+    return Expression::implicitConvTo(t);
+
+Lyes:
+    //printf("MATCHconvert\n");
+    return MATCHconvert;
+
+Lno:
+    //printf("MATCHnomatch\n");
+    return MATCHnomatch;
+}
+
+MATCH NullExp::implicitConvTo(Type *t)
+{
+#if 0
+    printf("NullExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    if (this->type->equals(t))
+	return MATCHexact;
+    // NULL implicitly converts to any pointer type or dynamic array
+    if (type->ty == Tpointer && type->next->ty == Tvoid)
+    {
+	if (t->ty == Ttypedef)
+	    t = ((TypeTypedef *)t)->sym->basetype;
+	if (t->ty == Tpointer || t->ty == Tarray ||
+	    t->ty == Taarray  || t->ty == Tclass ||
+	    t->ty == Tdelegate)
+	    return committed ? MATCHconvert : MATCHexact;
+    }
+    return Expression::implicitConvTo(t);
+}
+
+MATCH StringExp::implicitConvTo(Type *t)
+{   MATCH m;
+
+#if 0
+    printf("StringExp::implicitConvTo(this=%s, committed=%d, type=%s, t=%s)\n",
+	toChars(), committed, type->toChars(), t->toChars());
+#endif
+    if (!committed)
+    {
+    if (!committed && t->ty == Tpointer && t->next->ty == Tvoid)
+    {
+	return MATCHnomatch;
+    }
+    if (type->ty == Tsarray || type->ty == Tarray || type->ty == Tpointer)
+    {
+	if (type->next->ty == Tchar)
+	{
+	    switch (t->ty)
+	    {
+		case Tsarray:
+		    if (type->ty == Tsarray &&
+			((TypeSArray *)type)->dim->toInteger() !=
+			((TypeSArray *)t)->dim->toInteger())
+			return MATCHnomatch;
+		    goto L1;
+		case Tarray:
+		    goto L1;
+		case Tpointer:
+		L1:
+		    if (t->next->ty == Tchar)
+			return MATCHexact;
+		    else if (t->next->ty == Twchar)
+			return MATCHexact;
+		    else if (t->next->ty == Tdchar)
+			return MATCHexact;
+		    break;
+	    }
+	}
+    }
+    }
+    return Expression::implicitConvTo(t);
+#if 0
+    m = (MATCH)type->implicitConvTo(t);
+    if (m)
+    {
+	return m;
+    }
+
+    return MATCHnomatch;
+#endif
+}
+
+MATCH ArrayLiteralExp::implicitConvTo(Type *t)
+{   MATCH result = MATCHexact;
+
+    Type *typeb = type->toBasetype();
+    Type *tb = t->toBasetype();
+    if ((tb->ty == Tarray || tb->ty == Tsarray) &&
+	(typeb->ty == Tarray || typeb->ty == Tsarray))
+    {
+	if (tb->ty == Tsarray)
+	{   TypeSArray *tsa = (TypeSArray *)tb;
+	    if (elements->dim != tsa->dim->toInteger())
+		result = MATCHnomatch;
+	}
+
+	for (int i = 0; i < elements->dim; i++)
+	{   Expression *e = (Expression *)elements->data[i];
+	    MATCH m = (MATCH)e->implicitConvTo(tb->next);
+	    if (m < result)
+		result = m;			// remember worst match
+	    if (result == MATCHnomatch)
+		break;				// no need to check for worse
+	}
+	return result;
+    }
+    else
+	return Expression::implicitConvTo(t);
+}
+
+MATCH AssocArrayLiteralExp::implicitConvTo(Type *t)
+{   MATCH result = MATCHexact;
+
+    Type *typeb = type->toBasetype();
+    Type *tb = t->toBasetype();
+    if (tb->ty == Taarray && typeb->ty == Taarray)
+    {
+	for (size_t i = 0; i < keys->dim; i++)
+	{   Expression *e = (Expression *)keys->data[i];
+	    MATCH m = (MATCH)e->implicitConvTo(((TypeAArray *)tb)->key);
+	    if (m < result)
+		result = m;			// remember worst match
+	    if (result == MATCHnomatch)
+		break;				// no need to check for worse
+	    e = (Expression *)values->data[i];
+	    m = (MATCH)e->implicitConvTo(tb->next);
+	    if (m < result)
+		result = m;			// remember worst match
+	    if (result == MATCHnomatch)
+		break;				// no need to check for worse
+	}
+	return result;
+    }
+    else
+	return Expression::implicitConvTo(t);
+}
+
+MATCH AddrExp::implicitConvTo(Type *t)
+{
+#if 0
+    printf("AddrExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    MATCH result;
+
+    result = type->implicitConvTo(t);
+    //printf("\tresult = %d\n", result);
+
+    if (result == MATCHnomatch)
+    {
+	// Look for pointers to functions where the functions are overloaded.
+	VarExp *ve;
+	FuncDeclaration *f;
+
+	t = t->toBasetype();
+	if (type->ty == Tpointer && type->next->ty == Tfunction &&
+	    t->ty == Tpointer && t->next->ty == Tfunction &&
+	    e1->op == TOKvar)
+	{
+	    ve = (VarExp *)e1;
+	    f = ve->var->isFuncDeclaration();
+	    if (f && f->overloadExactMatch(t->next))
+		result = MATCHexact;
+	}
+    }
+    //printf("\tresult = %d\n", result);
+    return result;
+}
+
+MATCH SymOffExp::implicitConvTo(Type *t)
+{
+#if 0
+    printf("SymOffExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    MATCH result;
+
+    result = type->implicitConvTo(t);
+    //printf("\tresult = %d\n", result);
+
+    if (result == MATCHnomatch)
+    {
+	// Look for pointers to functions where the functions are overloaded.
+	FuncDeclaration *f;
+
+	t = t->toBasetype();
+	if (type->ty == Tpointer && type->next->ty == Tfunction &&
+	    t->ty == Tpointer && t->next->ty == Tfunction)
+	{
+	    f = var->isFuncDeclaration();
+	    if (f && f->overloadExactMatch(t->next))
+		result = MATCHexact;
+	}
+    }
+    //printf("\tresult = %d\n", result);
+    return result;
+}
+
+MATCH DelegateExp::implicitConvTo(Type *t)
+{
+#if 0
+    printf("DelegateExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    MATCH result;
+
+    result = type->implicitConvTo(t);
+
+    if (result == 0)
+    {
+	// Look for pointers to functions where the functions are overloaded.
+	FuncDeclaration *f;
+
+	t = t->toBasetype();
+	if (type->ty == Tdelegate && type->next->ty == Tfunction &&
+	    t->ty == Tdelegate && t->next->ty == Tfunction)
+	{
+	    if (func && func->overloadExactMatch(t->next))
+		result = MATCHexact;
+	}
+    }
+    return result;
+}
+
+MATCH CondExp::implicitConvTo(Type *t)
+{
+    MATCH m1;
+    MATCH m2;
+
+    m1 = e1->implicitConvTo(t);
+    m2 = e2->implicitConvTo(t);
+
+    // Pick the worst match
+    return (m1 < m2) ? m1 : m2;
+}
+
+
+/* ==================== castTo ====================== */
+
+/**************************************
+ * Do an explicit cast.
+ */
+
+Expression *Expression::castTo(Scope *sc, Type *t)
+{   Expression *e;
+    Type *tb;
+
+    //printf("Expression::castTo(this=%s, t=%s)\n", toChars(), t->toChars());
+#if 0
+    printf("Expression::castTo(this=%s, type=%s, t=%s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    e = this;
+    tb = t->toBasetype();
+    type = type->toBasetype();
+    if (tb != type)
+    {
+	if (tb->ty == Tbit && isBit())
+	    ;
+
+	// Do (type *) cast of (type [dim])
+	else if (tb->ty == Tpointer &&
+	    type->ty == Tsarray
+	   )
+	{
+	    //printf("Converting [dim] to *\n");
+
+	    if (type->size(loc) == 0)
+		e = new NullExp(loc);
+	    else
+		e = new AddrExp(loc, e);
+	}
+#if 0
+	else if (tb->ty == Tdelegate && type->ty != Tdelegate)
+	{
+	    TypeDelegate *td = (TypeDelegate *)tb;
+	    TypeFunction *tf = (TypeFunction *)td->next;
+	    return toDelegate(sc, tf->next);
+	}
+#endif
+	else
+	{
+	    e = new CastExp(loc, e, tb);
+	}
+    }
+    e->type = t;
+    //printf("Returning: %s\n", e->toChars());
+    return e;
+}
+
+
+Expression *RealExp::castTo(Scope *sc, Type *t)
+{
+    if (type->isreal() && t->isreal())
+	type = t;
+    else if (type->isimaginary() && t->isimaginary())
+	type = t;
+    else
+	return Expression::castTo(sc, t);
+    return this;
+}
+
+
+Expression *ComplexExp::castTo(Scope *sc, Type *t)
+{
+    if (type->iscomplex() && t->iscomplex())
+	type = t;
+    else
+	return Expression::castTo(sc, t);
+    return this;
+}
+
+
+Expression *NullExp::castTo(Scope *sc, Type *t)
+{   Expression *e;
+    Type *tb;
+
+    //printf("NullExp::castTo(t = %p)\n", t);
+    committed = 1;
+    e = this;
+    tb = t->toBasetype();
+    type = type->toBasetype();
+    if (tb != type)
+    {
+	// NULL implicitly converts to any pointer type or dynamic array
+	if (type->ty == Tpointer && type->next->ty == Tvoid &&
+	    (tb->ty == Tpointer || tb->ty == Tarray || tb->ty == Taarray ||
+	     tb->ty == Tdelegate))
+	{
+#if 0
+	    if (tb->ty == Tdelegate)
+	    {   TypeDelegate *td = (TypeDelegate *)tb;
+		TypeFunction *tf = (TypeFunction *)td->next;
+
+		if (!tf->varargs &&
+		    !(tf->arguments && tf->arguments->dim)
+		   )
+		{
+		    return Expression::castTo(sc, t);
+		}
+	    }
+#endif
+	}
+	else
+	{
+	    return Expression::castTo(sc, t);
+	    //e = new CastExp(loc, e, tb);
+	}
+    }
+    e->type = t;
+    return e;
+}
+
+Expression *StringExp::castTo(Scope *sc, Type *t)
+{
+    StringExp *se;
+    Type *tb;
+    int unique;
+
+    //printf("StringExp::castTo(t = %s), '%s' committed = %d\n", t->toChars(), toChars(), committed);
+
+    if (!committed && t->ty == Tpointer && t->next->ty == Tvoid)
+    {
+	error("cannot convert string literal to void*");
+    }
+
+    tb = t->toBasetype();
+    //printf("\ttype = %s\n", type->toChars());
+    if (tb->ty == Tdelegate && type->toBasetype()->ty != Tdelegate)
+	return Expression::castTo(sc, t);
+
+    se = this;
+    unique = 0;
+    if (!committed)
+    {
+	// Copy when committing the type
+	void *s;
+
+	s = (unsigned char *)mem.malloc((len + 1) * sz);
+	memcpy(s, string, (len + 1) * sz);
+	se = new StringExp(loc, s, len);
+	se->type = type;
+	se->sz = sz;
+	se->committed = 0;
+	unique = 1;		// this is the only instance
+    }
+    se->type = type->toBasetype();
+    if (tb == se->type)
+    {	se->type = t;
+	se->committed = 1;
+	return se;
+    }
+
+    if (tb->ty != Tsarray && tb->ty != Tarray && tb->ty != Tpointer)
+    {	se->committed = 1;
+	goto Lcast;
+    }
+    if (se->type->ty != Tsarray && se->type->ty != Tarray && se->type->ty != Tpointer)
+    {	se->committed = 1;
+	goto Lcast;
+    }
+
+    if (se->committed == 1)
+    {
+	if (se->type->next->size() == tb->next->size())
+	{   se->type = t;
+	    return se;
+	}
+	goto Lcast;
+    }
+
+    se->committed = 1;
+
+    int tfty;
+    int ttty;
+    char *p;
+    size_t u;
+    unsigned c;
+    size_t newlen;
+
+#define X(tf,tt)	((tf) * 256 + (tt))
+    {
+    OutBuffer buffer;
+    newlen = 0;
+    tfty = se->type->next->toBasetype()->ty;
+    ttty = tb->next->toBasetype()->ty;
+    switch (X(tfty, ttty))
+    {
+	case X(Tchar, Tchar):
+	case X(Twchar,Twchar):
+	case X(Tdchar,Tdchar):
+	    break;
+
+	case X(Tchar, Twchar):
+	    for (u = 0; u < len;)
+	    {
+		p = utf_decodeChar((unsigned char *)se->string, len, &u, &c);
+		if (p)
+		    error("%s", p);
+		else
+		    buffer.writeUTF16(c);
+	    }
+	    newlen = buffer.offset / 2;
+	    buffer.writeUTF16(0);
+	    goto L1;
+
+	case X(Tchar, Tdchar):
+	    for (u = 0; u < len;)
+	    {
+		p = utf_decodeChar((unsigned char *)se->string, len, &u, &c);
+		if (p)
+		    error("%s", p);
+		buffer.write4(c);
+		newlen++;
+	    }
+	    buffer.write4(0);
+	    goto L1;
+
+	case X(Twchar,Tchar):
+	    for (u = 0; u < len;)
+	    {
+		p = utf_decodeWchar((unsigned short *)se->string, len, &u, &c);
+		if (p)
+		    error("%s", p);
+		else
+		    buffer.writeUTF8(c);
+	    }
+	    newlen = buffer.offset;
+	    buffer.writeUTF8(0);
+	    goto L1;
+
+	case X(Twchar,Tdchar):
+	    for (u = 0; u < len;)
+	    {
+		p = utf_decodeWchar((unsigned short *)se->string, len, &u, &c);
+		if (p)
+		    error("%s", p);
+		buffer.write4(c);
+		newlen++;
+	    }
+	    buffer.write4(0);
+	    goto L1;
+
+	case X(Tdchar,Tchar):
+	    for (u = 0; u < len; u++)
+	    {
+		c = ((unsigned *)se->string)[u];
+		if (!utf_isValidDchar(c))
+		    error("invalid UCS-32 char \\U%08x", c);
+		else
+		    buffer.writeUTF8(c);
+		newlen++;
+	    }
+	    newlen = buffer.offset;
+	    buffer.writeUTF8(0);
+	    goto L1;
+
+	case X(Tdchar,Twchar):
+	    for (u = 0; u < len; u++)
+	    {
+		c = ((unsigned *)se->string)[u];
+		if (!utf_isValidDchar(c))
+		    error("invalid UCS-32 char \\U%08x", c);
+		else
+		    buffer.writeUTF16(c);
+		newlen++;
+	    }
+	    newlen = buffer.offset / 2;
+	    buffer.writeUTF16(0);
+	    goto L1;
+
+	L1:
+	    if (!unique)
+		se = new StringExp(loc, NULL, 0);
+	    se->string = buffer.extractData();
+	    se->len = newlen;
+	    se->sz = tb->next->size();
+	    break;
+
+	default:
+	    if (se->type->next->size() == tb->next->size())
+	    {	se->type = t;
+		return se;
+	    }
+	    goto Lcast;
+    }
+    }
+#undef X
+
+    // See if need to truncate or extend the literal
+    if (tb->ty == Tsarray)
+    {
+	int dim2 = ((TypeSArray *)tb)->dim->toInteger();
+
+	//printf("dim from = %d, to = %d\n", se->len, dim2);
+
+	// Changing dimensions
+	if (dim2 != se->len)
+	{
+	    unsigned newsz = se->sz;
+
+	    if (unique && dim2 < se->len)
+	    {   se->len = dim2;
+		// Add terminating 0
+		memset((unsigned char *)se->string + dim2 * newsz, 0, newsz);
+	    }
+	    else
+	    {
+		// Copy when changing the string literal
+		void *s;
+		int d;
+
+		d = (dim2 < se->len) ? dim2 : se->len;
+		s = (unsigned char *)mem.malloc((dim2 + 1) * newsz);
+		memcpy(s, se->string, d * newsz);
+		// Extend with 0, add terminating 0
+		memset((char *)s + d * newsz, 0, (dim2 + 1 - d) * newsz);
+		se = new StringExp(loc, s, dim2);
+		se->committed = 1;	// it now has a firm type
+		se->sz = newsz;
+	    }
+	}
+    }
+    se->type = t;
+    return se;
+
+Lcast:
+    Expression *e = new CastExp(loc, se, t);
+    e->type = t;
+    return e;
+}
+
+Expression *AddrExp::castTo(Scope *sc, Type *t)
+{
+    Type *tb;
+
+#if 0
+    printf("AddrExp::castTo(this=%s, type=%s, t=%s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    Expression *e = this;
+
+    tb = t->toBasetype();
+    type = type->toBasetype();
+    if (tb != type)
+    {
+	// Look for pointers to functions where the functions are overloaded.
+	VarExp *ve;
+	FuncDeclaration *f;
+
+	if (type->ty == Tpointer && type->next->ty == Tfunction &&
+	    tb->ty == Tpointer && tb->next->ty == Tfunction &&
+	    e1->op == TOKvar)
+	{
+	    ve = (VarExp *)e1;
+	    f = ve->var->isFuncDeclaration();
+	    if (f)
+	    {
+		f = f->overloadExactMatch(tb->next);
+		if (f)
+		{
+		    e = new VarExp(loc, f);
+		    e->type = f->type;
+		    e = new AddrExp(loc, e);
+		    e->type = t;
+		    return e;
+		}
+	    }
+	}
+	e = Expression::castTo(sc, t);
+    }
+    e->type = t;
+    return e;
+}
+
+
+Expression *TupleExp::castTo(Scope *sc, Type *t)
+{
+    for (size_t i = 0; i < exps->dim; i++)
+    {   Expression *e = (Expression *)exps->data[i];
+	e = e->castTo(sc, t);
+	exps->data[i] = (void *)e;
+    }
+    return this;
+}
+
+
+Expression *ArrayLiteralExp::castTo(Scope *sc, Type *t)
+{
+    Type *typeb = type->toBasetype();
+    Type *tb = t->toBasetype();
+    if ((tb->ty == Tarray || tb->ty == Tsarray) &&
+	(typeb->ty == Tarray || typeb->ty == Tsarray) &&
+	tb->next->toBasetype()->ty != Tvoid)
+    {
+	if (tb->ty == Tsarray)
+	{   TypeSArray *tsa = (TypeSArray *)tb;
+	    if (elements->dim != tsa->dim->toInteger())
+		goto L1;
+	}
+
+	for (int i = 0; i < elements->dim; i++)
+	{   Expression *e = (Expression *)elements->data[i];
+	    e = e->castTo(sc, tb->next);
+	    elements->data[i] = (void *)e;
+	}
+	type = t;
+	return this;
+    }
+    if (tb->ty == Tpointer && typeb->ty == Tsarray)
+    {
+	type = typeb->next->pointerTo();
+    }
+L1:
+    return Expression::castTo(sc, t);
+}
+
+Expression *AssocArrayLiteralExp::castTo(Scope *sc, Type *t)
+{
+    Type *typeb = type->toBasetype();
+    Type *tb = t->toBasetype();
+    if (tb->ty == Taarray && typeb->ty == Taarray &&
+	tb->next->toBasetype()->ty != Tvoid)
+    {
+	assert(keys->dim == values->dim);
+	for (size_t i = 0; i < keys->dim; i++)
+	{   Expression *e = (Expression *)values->data[i];
+	    e = e->castTo(sc, tb->next);
+	    values->data[i] = (void *)e;
+
+	    e = (Expression *)keys->data[i];
+	    e = e->castTo(sc, ((TypeAArray *)tb)->key);
+	    keys->data[i] = (void *)e;
+	}
+	type = t;
+	return this;
+    }
+L1:
+    return Expression::castTo(sc, t);
+}
+
+Expression *SymOffExp::castTo(Scope *sc, Type *t)
+{
+    Type *tb;
+
+#if 0
+    printf("SymOffExp::castTo(this=%s, type=%s, t=%s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    Expression *e = this;
+
+    tb = t->toBasetype();
+    type = type->toBasetype();
+    if (tb != type)
+    {
+	// Look for pointers to functions where the functions are overloaded.
+	FuncDeclaration *f;
+
+	if (type->ty == Tpointer && type->next->ty == Tfunction &&
+	    tb->ty == Tpointer && tb->next->ty == Tfunction)
+	{
+	    f = var->isFuncDeclaration();
+	    if (f)
+	    {
+		f = f->overloadExactMatch(tb->next);
+		if (f)
+		{
+		    e = new SymOffExp(loc, f, 0);
+		    e->type = t;
+		    return e;
+		}
+	    }
+	}
+	e = Expression::castTo(sc, t);
+    }
+    e->type = t;
+    return e;
+}
+
+Expression *DelegateExp::castTo(Scope *sc, Type *t)
+{
+    Type *tb;
+#if 0
+    printf("DelegateExp::castTo(this=%s, type=%s, t=%s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    Expression *e = this;
+    static char msg[] = "cannot form delegate due to covariant return type";
+
+    tb = t->toBasetype();
+    type = type->toBasetype();
+    if (tb != type)
+    {
+	// Look for delegates to functions where the functions are overloaded.
+	FuncDeclaration *f;
+
+	if (type->ty == Tdelegate && type->next->ty == Tfunction &&
+	    tb->ty == Tdelegate && tb->next->ty == Tfunction)
+	{
+	    if (func)
+	    {
+		f = func->overloadExactMatch(tb->next);
+		if (f)
+		{   int offset;
+		    if (f->tintro && f->tintro->next->isBaseOf(f->type->next, &offset) && offset)
+			error("%s", msg);
+		    e = new DelegateExp(loc, e1, f);
+		    e->type = t;
+		    return e;
+		}
+		if (func->tintro)
+		    error("%s", msg);
+	    }
+	}
+	e = Expression::castTo(sc, t);
+    }
+    else
+    {	int offset;
+
+	if (func->tintro && func->tintro->next->isBaseOf(func->type->next, &offset) && offset)
+	    error("%s", msg);
+    }
+    e->type = t;
+    return e;
+}
+
+Expression *CondExp::castTo(Scope *sc, Type *t)
+{
+    Expression *e = this;
+
+    if (type != t)
+    {
+	if (1 || e1->op == TOKstring || e2->op == TOKstring)
+	{   e = new CondExp(loc, econd, e1->castTo(sc, t), e2->castTo(sc, t));
+	    e->type = t;
+	}
+	else
+	    e = Expression::castTo(sc, t);
+    }
+    return e;
+}
+
+/* ==================== ====================== */
+
+/****************************************
+ * Scale addition/subtraction to/from pointer.
+ */
+
+Expression *BinExp::scaleFactor(Scope *sc)
+{   d_uns64 stride;
+    Type *t1b = e1->type->toBasetype();
+    Type *t2b = e2->type->toBasetype();
+
+    if (t1b->ty == Tpointer && t2b->isintegral())
+    {   // Need to adjust operator by the stride
+	// Replace (ptr + int) with (ptr + (int * stride))
+	Type *t = Type::tptrdiff_t;
+
+	stride = t1b->next->size();
+	if (!t->equals(t2b))
+	    e2 = e2->castTo(sc, t);
+    // LLVMDC: llvm uses typesafe pointer arithmetic
+    #if !IN_LLVM
+	if (t1b->next->isbit())
+	    // BUG: should add runtime check for misaligned offsets
+	    // This perhaps should be done by rewriting as &p[i]
+	    // and letting back end do it.
+	    e2 = new UshrExp(loc, e2, new IntegerExp(0, 3, t));
+	else
+	    e2 = new MulExp(loc, e2, new IntegerExp(0, stride, t));
+    #endif
+	e2->type = t;
+	type = e1->type;
+    }
+    else if (t2b->ty && t1b->isintegral())
+    {   // Need to adjust operator by the stride
+	// Replace (int + ptr) with (ptr + (int * stride))
+	Type *t = Type::tptrdiff_t;
+	Expression *e;
+
+	stride = t2b->next->size();
+	if (!t->equals(t1b))
+	    e = e1->castTo(sc, t);
+	else
+	    e = e1;
+	if (t2b->next->isbit())
+	    // BUG: should add runtime check for misaligned offsets
+	    e = new UshrExp(loc, e, new IntegerExp(0, 3, t));
+	else
+	    e = new MulExp(loc, e, new IntegerExp(0, stride, t));
+	e->type = t;
+	type = e2->type;
+	e1 = e2;
+	e2 = e;
+    }
+    return this;
+}
+
+/************************************
+ * Bring leaves to common type.
+ */
+
+Expression *BinExp::typeCombine(Scope *sc)
+{
+    Type *t1;
+    Type *t2;
+    Type *t;
+    TY ty;
+
+    //printf("BinExp::typeCombine()\n");
+    //dump(0);
+
+    e1 = e1->integralPromotions(sc);
+    e2 = e2->integralPromotions(sc);
+
+    // BUG: do toBasetype()
+    t1 = e1->type;
+    t2 = e2->type;
+    assert(t1);
+
+    //if (t1) printf("\tt1 = %s\n", t1->toChars());
+    //if (t2) printf("\tt2 = %s\n", t2->toChars());
+#ifdef DEBUG
+    if (!t2) printf("\te2 = '%s'\n", e2->toChars());
+#endif
+    assert(t2);
+
+    Type *t1b = t1->toBasetype();
+    Type *t2b = t2->toBasetype();
+
+    ty = (TY)Type::impcnvResult[t1b->ty][t2b->ty];
+    if (ty != Terror)
+    {	TY ty1;
+	TY ty2;
+
+	ty1 = (TY)Type::impcnvType1[t1b->ty][t2b->ty];
+	ty2 = (TY)Type::impcnvType2[t1b->ty][t2b->ty];
+
+	if (t1b->ty == ty1)	// if no promotions
+	{
+	    if (t1 == t2)
+	    {
+		if (!type)
+		    type = t1;
+		return this;
+	    }
+
+	    if (t1b == t2b)
+	    {
+		if (!type)
+		    type = t1b;
+		return this;
+	    }
+	}
+
+	if (!type)
+	    type = Type::basic[ty];
+
+	t1 = Type::basic[ty1];
+	t2 = Type::basic[ty2];
+	e1 = e1->castTo(sc, t1);
+	e2 = e2->castTo(sc, t2);
+#if 0
+	if (type != Type::basic[ty])
+	{   t = type;
+	    type = Type::basic[ty];
+	    return castTo(sc, t);
+	}
+#endif
+	//printf("after typeCombine():\n");
+	//dump(0);
+	//printf("ty = %d, ty1 = %d, ty2 = %d\n", ty, ty1, ty2);
+	return this;
+    }
+
+    t = t1;
+    if (t1 == t2)
+    {
+	if ((t1->ty == Tstruct || t1->ty == Tclass) &&
+	    (op == TOKmin || op == TOKadd))
+	    goto Lincompatible;
+    }
+    else if (t1->isintegral() && t2->isintegral())
+    {
+	printf("t1 = %s, t2 = %s\n", t1->toChars(), t2->toChars());
+	int sz1 = t1->size();
+	int sz2 = t2->size();
+	int sign1 = t1->isunsigned() == 0;
+	int sign2 = t2->isunsigned() == 0;
+
+	if (sign1 == sign2)
+	{
+	    if (sz1 < sz2)
+		goto Lt2;
+	    else
+		goto Lt1;
+	}
+	if (!sign1)
+	{
+	    if (sz1 >= sz2)
+		goto Lt1;
+	    else
+		goto Lt2;
+	}
+	else
+	{
+	    if (sz2 >= sz1)
+		goto Lt2;
+	    else
+		goto Lt1;
+	}
+    }
+    else if (t1->ty == Tpointer && t2->ty == Tpointer)
+    {
+	// Bring pointers to compatible type
+	Type *t1n = t1->next;
+	Type *t2n = t2->next;
+
+//t1->print();
+//t2->print();
+//if (t1n == t2n) *(char *)0 = 0;
+	assert(t1n != t2n);
+	if (t1n->ty == Tvoid)		// pointers to void are always compatible
+	    t = t2;
+	else if (t2n->ty == Tvoid)
+	    ;
+	else if (t1n->ty == Tclass && t2n->ty == Tclass)
+	{   ClassDeclaration *cd1 = t1n->isClassHandle();
+	    ClassDeclaration *cd2 = t2n->isClassHandle();
+	    int offset;
+
+	    if (cd1->isBaseOf(cd2, &offset))
+	    {
+		if (offset)
+		    e2 = e2->castTo(sc, t);
+	    }
+	    else if (cd2->isBaseOf(cd1, &offset))
+	    {
+		t = t2;
+		if (offset)
+		    e1 = e1->castTo(sc, t);
+	    }
+	    else
+		goto Lincompatible;
+	}
+	else
+	    goto Lincompatible;
+    }
+    else if ((t1->ty == Tsarray || t1->ty == Tarray) &&
+	     e2->op == TOKnull && t2->ty == Tpointer && t2->next->ty == Tvoid)
+    {
+	goto Lx1;
+    }
+    else if ((t2->ty == Tsarray || t2->ty == Tarray) &&
+	     e1->op == TOKnull && t1->ty == Tpointer && t1->next->ty == Tvoid)
+    {
+	goto Lx2;
+    }
+    else if ((t1->ty == Tsarray || t1->ty == Tarray) && t1->implicitConvTo(t2))
+    {
+	goto Lt2;
+    }
+    else if ((t2->ty == Tsarray || t2->ty == Tarray) && t2->implicitConvTo(t1))
+    {
+	goto Lt1;
+    }
+    else if (t1->ty == Tclass || t2->ty == Tclass)
+    {	int i1;
+	int i2;
+
+	i1 = e2->implicitConvTo(t1);
+	i2 = e1->implicitConvTo(t2);
+
+	if (i1 && i2)
+	{
+	    // We have the case of class vs. void*, so pick class
+	    if (t1->ty == Tpointer)
+		i1 = 0;
+	    else if (t2->ty == Tpointer)
+		i2 = 0;
+	}
+
+	if (i2)
+	{
+	    goto Lt2;
+	}
+	else if (i1)
+	{
+	    goto Lt1;
+	}
+	else
+	    goto Lincompatible;
+    }
+    else if ((e1->op == TOKstring || e1->op == TOKnull) && e1->implicitConvTo(t2))
+    {
+	goto Lt2;
+    }
+//else if (e2->op == TOKstring) { printf("test2\n"); }
+    else if ((e2->op == TOKstring || e2->op == TOKnull) && e2->implicitConvTo(t1))
+    {
+	goto Lt1;
+    }
+    else if (t1->ty == Tsarray && t2->ty == Tsarray &&
+	     e2->implicitConvTo(t1->next->arrayOf()))
+    {
+     Lx1:
+	t = t1->next->arrayOf();
+	e1 = e1->castTo(sc, t);
+	e2 = e2->castTo(sc, t);
+    }
+    else if (t1->ty == Tsarray && t2->ty == Tsarray &&
+	     e1->implicitConvTo(t2->next->arrayOf()))
+    {
+     Lx2:
+	t = t2->next->arrayOf();
+	e1 = e1->castTo(sc, t);
+	e2 = e2->castTo(sc, t);
+    }
+    else
+    {
+     Lincompatible:
+	incompatibleTypes();
+    }
+Lret:
+    if (!type)
+	type = t;
+    //dump(0);
+    return this;
+
+
+Lt1:
+    e2 = e2->castTo(sc, t1);
+    t = t1;
+    goto Lret;
+
+Lt2:
+    e1 = e1->castTo(sc, t2);
+    t = t2;
+    goto Lret;
+}
+
+/***********************************
+ * Do integral promotions (convertchk).
+ * Don't convert <array of> to <pointer to>
+ */
+
+Expression *Expression::integralPromotions(Scope *sc)
+{   Expression *e;
+
+    e = this;
+    switch (type->toBasetype()->ty)
+    {
+	case Tvoid:
+	    error("void has no value");
+	    break;
+
+	case Tint8:
+	case Tuns8:
+	case Tint16:
+	case Tuns16:
+	case Tbit:
+	case Tbool:
+	case Tchar:
+	case Twchar:
+	    e = e->castTo(sc, Type::tint32);
+	    break;
+
+	case Tdchar:
+	    e = e->castTo(sc, Type::tuns32);
+	    break;
+    }
+    return e;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/class.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,1267 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "root.h"
+#include "mem.h"
+
+#include "enum.h"
+#include "init.h"
+#include "attrib.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "id.h"
+#include "mtype.h"
+#include "scope.h"
+#include "module.h"
+#include "expression.h"
+#include "statement.h"
+
+/********************************* ClassDeclaration ****************************/
+
+ClassDeclaration *ClassDeclaration::classinfo;
+ClassDeclaration *ClassDeclaration::object;
+
+ClassDeclaration::ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses)
+    : AggregateDeclaration(loc, id)
+{
+    static char msg[] = "only object.d can define this reserved class name";
+
+    if (baseclasses)
+	this->baseclasses = *baseclasses;
+    baseClass = NULL;
+
+    interfaces_dim = 0;
+    interfaces = NULL;
+
+    vtblInterfaces = NULL;
+
+    //printf("ClassDeclaration(%s), dim = %d\n", id->toChars(), this->baseclasses.dim);
+
+    // For forward references
+    type = new TypeClass(this);
+    handle = type;
+
+    ctor = NULL;
+    defaultCtor = NULL;
+    staticCtor = NULL;
+    staticDtor = NULL;
+
+    vtblsym = NULL;
+    vclassinfo = NULL;
+
+    if (id)
+    {	// Look for special class names
+
+	if (id == Id::__sizeof || id == Id::alignof || id == Id::mangleof)
+	    error("illegal class name");
+
+	// BUG: What if this is the wrong TypeInfo, i.e. it is nested?
+	if (id->toChars()[0] == 'T')
+	{
+	    if (id == Id::TypeInfo)
+	    {	if (Type::typeinfo)
+		    Type::typeinfo->error("%s", msg);
+		Type::typeinfo = this;
+	    }
+
+	    if (id == Id::TypeInfo_Class)
+	    {	if (Type::typeinfoclass)
+		    Type::typeinfoclass->error("%s", msg);
+		Type::typeinfoclass = this;
+	    }
+
+	    if (id == Id::TypeInfo_Interface)
+	    {	if (Type::typeinfointerface)
+		    Type::typeinfointerface->error("%s", msg);
+		Type::typeinfointerface = this;
+	    }
+
+	    if (id == Id::TypeInfo_Struct)
+	    {	if (Type::typeinfostruct)
+		    Type::typeinfostruct->error("%s", msg);
+		Type::typeinfostruct = this;
+	    }
+
+	    if (id == Id::TypeInfo_Typedef)
+	    {	if (Type::typeinfotypedef)
+		    Type::typeinfotypedef->error("%s", msg);
+		Type::typeinfotypedef = this;
+	    }
+
+	    if (id == Id::TypeInfo_Pointer)
+	    {	if (Type::typeinfopointer)
+		    Type::typeinfopointer->error("%s", msg);
+		Type::typeinfopointer = this;
+	    }
+
+	    if (id == Id::TypeInfo_Array)
+	    {	if (Type::typeinfoarray)
+		    Type::typeinfoarray->error("%s", msg);
+		Type::typeinfoarray = this;
+	    }
+
+	    if (id == Id::TypeInfo_StaticArray)
+	    {	//if (Type::typeinfostaticarray)
+		    //Type::typeinfostaticarray->error("%s", msg);
+		Type::typeinfostaticarray = this;
+	    }
+
+	    if (id == Id::TypeInfo_AssociativeArray)
+	    {	if (Type::typeinfoassociativearray)
+		    Type::typeinfoassociativearray->error("%s", msg);
+		Type::typeinfoassociativearray = this;
+	    }
+
+	    if (id == Id::TypeInfo_Enum)
+	    {	if (Type::typeinfoenum)
+		    Type::typeinfoenum->error("%s", msg);
+		Type::typeinfoenum = this;
+	    }
+
+	    if (id == Id::TypeInfo_Function)
+	    {	if (Type::typeinfofunction)
+		    Type::typeinfofunction->error("%s", msg);
+		Type::typeinfofunction = this;
+	    }
+
+	    if (id == Id::TypeInfo_Delegate)
+	    {	if (Type::typeinfodelegate)
+		    Type::typeinfodelegate->error("%s", msg);
+		Type::typeinfodelegate = this;
+	    }
+
+	    if (id == Id::TypeInfo_Tuple)
+	    {	if (Type::typeinfotypelist)
+		    Type::typeinfotypelist->error("%s", msg);
+		Type::typeinfotypelist = this;
+	    }
+	}
+
+	if (id == Id::Object)
+	{   if (object)
+		object->error("%s", msg);
+	    object = this;
+	}
+
+	if (id == Id::ClassInfo)
+	{   if (classinfo)
+		classinfo->error("%s", msg);
+	    classinfo = this;
+	}
+
+	if (id == Id::ModuleInfo)
+	{   if (Module::moduleinfo)
+		Module::moduleinfo->error("%s", msg);
+	    Module::moduleinfo = this;
+	}
+    }
+
+    com = 0;
+#if 0
+    if (id == Id::IUnknown)		// IUnknown is the root of all COM objects
+	com = 1;
+#endif
+    isauto = 0;
+    isabstract = 0;
+    isnested = 0;
+    vthis = NULL;
+}
+
+Dsymbol *ClassDeclaration::syntaxCopy(Dsymbol *s)
+{
+    ClassDeclaration *cd;
+
+    //printf("ClassDeclaration::syntaxCopy('%s')\n", toChars());
+    if (s)
+	cd = (ClassDeclaration *)s;
+    else
+	cd = new ClassDeclaration(loc, ident, NULL);
+
+    cd->storage_class |= storage_class;
+
+    cd->baseclasses.setDim(this->baseclasses.dim);
+    for (int i = 0; i < cd->baseclasses.dim; i++)
+    {
+	BaseClass *b = (BaseClass *)this->baseclasses.data[i];
+	BaseClass *b2 = new BaseClass(b->type->syntaxCopy(), b->protection);
+	cd->baseclasses.data[i] = b2;
+    }
+
+    ScopeDsymbol::syntaxCopy(cd);
+    return cd;
+}
+
+void ClassDeclaration::semantic(Scope *sc)
+{   int i;
+    unsigned offset;
+
+    //printf("ClassDeclaration::semantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this);
+    //printf("\tparent = %p, '%s'\n", sc->parent, sc->parent ? sc->parent->toChars() : "");
+    //printf("sc->stc = %x\n", sc->stc);
+
+    //{ static int n;  if (++n == 20) *(char*)0=0; }
+
+    if (!ident)		// if anonymous class
+    {	char *id = "__anonclass";
+
+	ident = Identifier::generateId(id);
+    }
+
+    if (!scope)
+    {
+	if (!parent && sc->parent && !sc->parent->isModule())
+	    parent = sc->parent;
+
+	type = type->semantic(loc, sc);
+	handle = handle->semantic(loc, sc);
+    }
+    if (!members)			// if forward reference
+    {	//printf("\tclass '%s' is forward referenced\n", toChars());
+	return;
+    }
+    if (symtab)
+    {	if (!scope)
+	{   //printf("\tsemantic for '%s' is already completed\n", toChars());
+	    return;		// semantic() already completed
+	}
+    }
+    else
+	symtab = new DsymbolTable();
+
+    Scope *scx = NULL;
+    if (scope)
+    {	sc = scope;
+	scx = scope;		// save so we don't make redundant copies
+	scope = NULL;
+    }
+#ifdef IN_GCC
+    methods.setDim(0);
+#endif
+
+    // Expand any tuples in baseclasses[]
+    for (i = 0; i < baseclasses.dim; )
+    {	BaseClass *b = (BaseClass *)baseclasses.data[i];
+	b->type = b->type->semantic(loc, sc);
+	Type *tb = b->type->toBasetype();
+
+	if (tb->ty == Ttuple)
+	{   TypeTuple *tup = (TypeTuple *)tb;
+	    enum PROT protection = b->protection;
+	    baseclasses.remove(i);
+	    size_t dim = Argument::dim(tup->arguments);
+	    for (size_t j = 0; j < dim; j++)
+	    {	Argument *arg = Argument::getNth(tup->arguments, j);
+		b = new BaseClass(arg->type, protection);
+		baseclasses.insert(i + j, b);
+	    }
+	}
+	else
+	    i++;
+    }
+
+    // See if there's a base class as first in baseclasses[]
+    if (baseclasses.dim)
+    {	TypeClass *tc;
+	BaseClass *b;
+	Type *tb;
+
+	b = (BaseClass *)baseclasses.data[0];
+	//b->type = b->type->semantic(loc, sc);
+	tb = b->type->toBasetype();
+	if (tb->ty != Tclass)
+	{   error("base type must be class or interface, not %s", b->type->toChars());
+	    baseclasses.remove(0);
+	}
+	else
+	{
+	    tc = (TypeClass *)(tb);
+	    if (tc->sym->isInterfaceDeclaration())
+		;
+	    else
+	    {
+		for (ClassDeclaration *cdb = tc->sym; cdb; cdb = cdb->baseClass)
+		{
+		    if (cdb == this)
+		    {
+			error("circular inheritance");
+			baseclasses.remove(0);
+			goto L7;
+		    }
+		}
+		if (!tc->sym->symtab || tc->sym->scope || tc->sym->sizeok == 0)
+		{
+		    //error("forward reference of base class %s", baseClass->toChars());
+		    // Forward reference of base class, try again later
+		    //printf("\ttry later, forward reference of base class %s\n", tc->sym->toChars());
+		    scope = scx ? scx : new Scope(*sc);
+		    scope->setNoFree();
+		    scope->module->addDeferredSemantic(this);
+		    return;
+		}
+		else
+		{   baseClass = tc->sym;
+		    b->base = baseClass;
+		}
+	     L7: ;
+	    }
+	}
+    }
+
+    // Treat the remaining entries in baseclasses as interfaces
+    // Check for errors, handle forward references
+    for (i = (baseClass ? 1 : 0); i < baseclasses.dim; )
+    {	TypeClass *tc;
+	BaseClass *b;
+	Type *tb;
+
+	b = (BaseClass *)baseclasses.data[i];
+	b->type = b->type->semantic(loc, sc);
+	tb = b->type->toBasetype();
+	if (tb->ty == Tclass)
+	    tc = (TypeClass *)tb;
+	else
+	    tc = NULL;
+	if (!tc || !tc->sym->isInterfaceDeclaration())
+	{
+	    error("base type must be interface, not %s", b->type->toChars());
+	    baseclasses.remove(i);
+	    continue;
+	}
+	else
+	{
+	    // Check for duplicate interfaces
+	    for (size_t j = (baseClass ? 1 : 0); j < i; j++)
+	    {
+		BaseClass *b2 = (BaseClass *)baseclasses.data[j];
+		if (b2->base == tc->sym)
+		    error("inherits from duplicate interface %s", b2->base->toChars());
+	    }
+
+	    b->base = tc->sym;
+	    if (!b->base->symtab || b->base->scope)
+	    {
+		//error("forward reference of base class %s", baseClass->toChars());
+		// Forward reference of base, try again later
+		//printf("\ttry later, forward reference of base %s\n", baseClass->toChars());
+		scope = scx ? scx : new Scope(*sc);
+		scope->setNoFree();
+		scope->module->addDeferredSemantic(this);
+		return;
+	    }
+	}
+	i++;
+    }
+
+
+    // If no base class, and this is not an Object, use Object as base class
+    if (!baseClass && ident != Id::Object)
+    {
+	// BUG: what if Object is redefined in an inner scope?
+	Type *tbase = new TypeIdentifier(0, Id::Object);
+	BaseClass *b;
+	TypeClass *tc;
+	Type *bt;
+
+	if (!object)
+	{
+	    error("missing or corrupt object.d");
+	    fatal();
+	}
+	bt = tbase->semantic(loc, sc)->toBasetype();
+	b = new BaseClass(bt, PROTpublic);
+	baseclasses.shift(b);
+	assert(b->type->ty == Tclass);
+	tc = (TypeClass *)(b->type);
+	baseClass = tc->sym;
+	assert(!baseClass->isInterfaceDeclaration());
+	b->base = baseClass;
+    }
+
+    interfaces_dim = baseclasses.dim;
+    interfaces = (BaseClass **)baseclasses.data;
+
+
+    if (baseClass)
+    {
+	if (baseClass->storage_class & STCfinal)
+	    error("cannot inherit from final class %s", baseClass->toChars());
+
+	interfaces_dim--;
+	interfaces++;
+
+	// Copy vtbl[] from base class
+	vtbl.setDim(baseClass->vtbl.dim);
+	memcpy(vtbl.data, baseClass->vtbl.data, sizeof(void *) * vtbl.dim);
+
+	// Inherit properties from base class
+	com = baseClass->isCOMclass();
+	isauto = baseClass->isauto;
+	vthis = baseClass->vthis;
+    }
+    else
+    {
+	// No base class, so this is the root of the class hierarchy
+	vtbl.setDim(0);
+	vtbl.push(this);		// leave room for classinfo as first member
+    }
+
+    protection = sc->protection;
+    storage_class |= sc->stc;
+
+    if (sizeok == 0)
+    {
+	interfaceSemantic(sc);
+
+	for (i = 0; i < members->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)members->data[i];
+	    s->addMember(sc, this, 1);
+	}
+
+	/* If this is a nested class, add the hidden 'this'
+	 * member which is a pointer to the enclosing scope.
+	 */
+	if (vthis)		// if inheriting from nested class
+	{   // Use the base class's 'this' member
+	    isnested = 1;
+	    if (storage_class & STCstatic)
+		error("static class cannot inherit from nested class %s", baseClass->toChars());
+	    if (toParent2() != baseClass->toParent2())
+		error("super class %s is nested within %s, not %s",
+			baseClass->toChars(),
+			baseClass->toParent2()->toChars(),
+			toParent2()->toChars());
+	}
+	else if (!(storage_class & STCstatic))
+	{   Dsymbol *s = toParent2();
+	    if (s)
+	    {
+		ClassDeclaration *cd = s->isClassDeclaration();
+		FuncDeclaration *fd = s->isFuncDeclaration();
+
+
+		if (cd || fd)
+		{   isnested = 1;
+		    Type *t;
+		    if (cd)
+			t = cd->type;
+		    else if (fd)
+		    {	AggregateDeclaration *ad = fd->isMember2();
+			if (ad)
+			    t = ad->handle;
+			else
+			{
+			    t = new TypePointer(Type::tvoid);
+			    t = t->semantic(0, sc);
+			}
+		    }
+		    else
+			assert(0);
+		    assert(!vthis);
+		    vthis = new ThisDeclaration(t);
+		    members->push(vthis);
+		}
+	    }
+	}
+    }
+
+    if (storage_class & (STCauto | STCscope))
+	isauto = 1;
+    if (storage_class & STCabstract)
+	isabstract = 1;
+    if (storage_class & STCdeprecated)
+	isdeprecated = 1;
+
+    sc = sc->push(this);
+    sc->stc &= ~(STCfinal | STCauto | STCscope | STCstatic |
+		 STCabstract | STCdeprecated);
+    sc->parent = this;
+    sc->inunion = 0;
+
+    if (isCOMclass())
+	sc->linkage = LINKwindows;
+    sc->protection = PROTpublic;
+    sc->explicitProtection = 0;
+    sc->structalign = 8;
+    structalign = sc->structalign;
+    if (baseClass)
+    {	sc->offset = baseClass->structsize;
+	alignsize = baseClass->alignsize;
+//	if (isnested)
+//	    sc->offset += PTRSIZE;	// room for uplevel context pointer
+    }
+    else
+    {	sc->offset = 8;		// allow room for vptr[] and monitor
+	alignsize = 4;
+    }
+    structsize = sc->offset;
+    Scope scsave = *sc;
+    int members_dim = members->dim;
+    sizeok = 0;
+    for (i = 0; i < members_dim; i++)
+    {
+	Dsymbol *s = (Dsymbol *)members->data[i];
+	s->semantic(sc);
+    }
+
+    if (sizeok == 2)
+    {	// semantic() failed because of forward references.
+	// Unwind what we did, and defer it for later
+	fields.setDim(0);
+	structsize = 0;
+	alignsize = 0;
+	structalign = 0;
+
+	sc = sc->pop();
+
+	scope = scx ? scx : new Scope(*sc);
+	scope->setNoFree();
+	scope->module->addDeferredSemantic(this);
+
+	//printf("\tsemantic('%s') failed\n", toChars());
+	return;
+    }
+
+    //printf("\tsemantic('%s') successful\n", toChars());
+
+    structsize = sc->offset;
+    //members->print();
+
+    /* Look for special member functions.
+     * They must be in this class, not in a base class.
+     */
+    ctor = (CtorDeclaration *)search(0, Id::ctor, 0);
+    if (ctor && ctor->toParent() != this)
+	ctor = NULL;
+
+//    dtor = (DtorDeclaration *)search(Id::dtor, 0);
+//    if (dtor && dtor->toParent() != this)
+//	dtor = NULL;
+
+//    inv = (InvariantDeclaration *)search(Id::classInvariant, 0);
+//    if (inv && inv->toParent() != this)
+//	inv = NULL;
+
+    // Can be in base class
+    aggNew    = (NewDeclaration *)search(0, Id::classNew, 0);
+    aggDelete = (DeleteDeclaration *)search(0, Id::classDelete, 0);
+
+    // If this class has no constructor, but base class does, create
+    // a constructor:
+    //    this() { }
+    if (!ctor && baseClass && baseClass->ctor)
+    {
+	//printf("Creating default this(){} for class %s\n", toChars());
+	ctor = new CtorDeclaration(0, 0, NULL, 0);
+	ctor->fbody = new CompoundStatement(0, new Statements());
+	members->push(ctor);
+	ctor->addMember(sc, this, 1);
+	*sc = scsave;
+	sc->offset = structsize;
+	ctor->semantic(sc);
+	defaultCtor = ctor;
+    }
+
+#if 0
+    if (baseClass)
+    {	if (!aggDelete)
+	    aggDelete = baseClass->aggDelete;
+	if (!aggNew)
+	    aggNew = baseClass->aggNew;
+    }
+#endif
+
+    // Allocate instance of each new interface
+    for (i = 0; i < vtblInterfaces->dim; i++)
+    {
+	BaseClass *b = (BaseClass *)vtblInterfaces->data[i];
+	unsigned thissize = PTRSIZE;
+
+	alignmember(structalign, thissize, &sc->offset);
+	assert(b->offset == 0);
+	b->offset = sc->offset;
+
+	// Take care of single inheritance offsets
+	while (b->baseInterfaces_dim)
+	{
+	    b = &b->baseInterfaces[0];
+	    b->offset = sc->offset;
+	}
+
+	sc->offset += thissize;
+	if (alignsize < thissize)
+	    alignsize = thissize;
+    }
+    structsize = sc->offset;
+    sizeok = 1;
+    Module::dprogress++;
+
+
+    sc->pop();
+
+#if 0 // Do not call until toObjfile() because of forward references
+    // Fill in base class vtbl[]s
+    for (i = 0; i < vtblInterfaces->dim; i++)
+    {
+	BaseClass *b = (BaseClass *)vtblInterfaces->data[i];
+
+	//b->fillVtbl(this, &b->vtbl, 1);
+    }
+#endif
+    //printf("-ClassDeclaration::semantic(%s), type = %p\n", toChars(), type);
+}
+
+void ClassDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    if (!isAnonymous())
+    {
+	buf->printf("%s ", kind());
+	buf->writestring(toChars());
+	if (baseclasses.dim)
+	    buf->writestring(" : ");
+    }
+    for (int i = 0; i < baseclasses.dim; i++)
+    {
+	BaseClass *b = (BaseClass *)baseclasses.data[i];
+
+	if (i)
+	    buf->writeByte(',');
+	//buf->writestring(b->base->ident->toChars());
+	b->type->toCBuffer(buf, NULL, hgs);
+    }
+    buf->writenl();
+    buf->writeByte('{');
+    buf->writenl();
+    for (int i = 0; i < members->dim; i++)
+    {
+	Dsymbol *s = (Dsymbol *)members->data[i];
+
+	buf->writestring("    ");
+	s->toCBuffer(buf, hgs);
+    }
+    buf->writestring("}");
+    buf->writenl();
+}
+
+#if 0
+void ClassDeclaration::defineRef(Dsymbol *s)
+{
+    ClassDeclaration *cd;
+
+    AggregateDeclaration::defineRef(s);
+    cd = s->isClassDeclaration();
+    baseType = cd->baseType;
+    cd->baseType = NULL;
+}
+#endif
+
+/*********************************************
+ * Determine if 'this' is a base class of cd.
+ * This is used to detect circular inheritance only.
+ */
+
+int ClassDeclaration::isBaseOf2(ClassDeclaration *cd)
+{
+    if (!cd)
+	return 0;
+    //printf("ClassDeclaration::isBaseOf2(this = '%s', cd = '%s')\n", toChars(), cd->toChars());
+    for (int i = 0; i < cd->baseclasses.dim; i++)
+    {	BaseClass *b = (BaseClass *)cd->baseclasses.data[i];
+
+	if (b->base == this || isBaseOf2(b->base))
+	    return 1;
+    }
+    return 0;
+}
+
+/*******************************************
+ * Determine if 'this' is a base class of cd.
+ */
+
+int ClassDeclaration::isBaseOf(ClassDeclaration *cd, int *poffset)
+{
+    //printf("ClassDeclaration::isBaseOf(this = '%s', cd = '%s')\n", toChars(), cd->toChars());
+    if (poffset)
+	*poffset = 0;
+    while (cd)
+    {
+	if (this == cd->baseClass)
+	    return 1;
+
+	/* cd->baseClass might not be set if cd is forward referenced.
+	 */
+	if (!cd->baseClass && cd->baseclasses.dim && !cd->isInterfaceDeclaration())
+	{
+	    cd->error("base class is forward referenced by %s", toChars());
+	}
+
+	cd = cd->baseClass;
+    }
+    return 0;
+}
+
+Dsymbol *ClassDeclaration::search(Loc loc, Identifier *ident, int flags)
+{
+    Dsymbol *s;
+
+    //printf("%s.ClassDeclaration::search('%s')\n", toChars(), ident->toChars());
+    if (scope)
+	semantic(scope);
+
+    if (!members || !symtab || scope)
+    {	error("is forward referenced when looking for '%s'", ident->toChars());
+	//*(char*)0=0;
+	return NULL;
+    }
+
+    s = ScopeDsymbol::search(loc, ident, flags);
+    if (!s)
+    {
+	// Search bases classes in depth-first, left to right order
+
+	int i;
+
+	for (i = 0; i < baseclasses.dim; i++)
+	{
+	    BaseClass *b = (BaseClass *)baseclasses.data[i];
+
+	    if (b->base)
+	    {
+		if (!b->base->symtab)
+		    error("base %s is forward referenced", b->base->ident->toChars());
+		else
+		{
+		    s = b->base->search(loc, ident, flags);
+		    if (s == this)	// happens if s is nested in this and derives from this
+			s = NULL;
+		    else if (s)
+			break;
+		}
+	    }
+	}
+    }
+    return s;
+}
+
+/****************
+ * Find virtual function matching identifier and type.
+ * Used to build virtual function tables for interface implementations.
+ */
+
+FuncDeclaration *ClassDeclaration::findFunc(Identifier *ident, TypeFunction *tf)
+{
+    //printf("ClassDeclaration::findFunc(%s, %s) %s\n", ident->toChars(), tf->toChars(), toChars());
+
+    ClassDeclaration *cd = this;
+    Array *vtbl = &cd->vtbl;
+    while (1)
+    {
+	for (size_t i = 0; i < vtbl->dim; i++)
+	{
+	    FuncDeclaration *fd = (FuncDeclaration *)vtbl->data[i];
+
+	    //printf("\t[%d] = %s\n", i, fd->toChars());
+	    if (ident == fd->ident &&
+		//tf->equals(fd->type)
+		fd->type->covariant(tf) == 1
+	       )
+	    {   //printf("\t\tfound\n");
+		return fd;
+	    }
+	    //else printf("\t\t%d\n", fd->type->covariant(tf));
+	}
+	if (!cd)
+	    break;
+	vtbl = &cd->vtblFinal;
+	cd = cd->baseClass;
+    }
+
+    return NULL;
+}
+
+void ClassDeclaration::interfaceSemantic(Scope *sc)
+{   int i;
+
+    vtblInterfaces = new BaseClasses();
+    vtblInterfaces->reserve(interfaces_dim);
+
+    for (i = 0; i < interfaces_dim; i++)
+    {
+	BaseClass *b = interfaces[i];
+
+	// If this is an interface, and it derives from a COM interface,
+	// then this is a COM interface too.
+	if (b->base->isCOMclass())
+	    com = 1;
+
+	vtblInterfaces->push(b);
+	b->copyBaseInterfaces(vtblInterfaces);
+    }
+}
+
+/****************************************
+ */
+
+int ClassDeclaration::isCOMclass()
+{
+    return com;
+}
+
+
+/****************************************
+ */
+
+int ClassDeclaration::isAbstract()
+{
+    if (isabstract)
+	return TRUE;
+    for (int i = 1; i < vtbl.dim; i++)
+    {
+	FuncDeclaration *fd = ((Dsymbol *)vtbl.data[i])->isFuncDeclaration();
+
+	//printf("\tvtbl[%d] = %p\n", i, fd);
+	if (!fd || fd->isAbstract())
+	{
+	    isabstract |= 1;
+	    return TRUE;
+	}
+    }
+    return FALSE;
+}
+
+/****************************************
+ * Returns !=0 if there's an extra member which is the 'this'
+ * pointer to the enclosing context (enclosing class or function)
+ */
+
+int ClassDeclaration::isNested()
+{
+    return isnested;
+}
+
+/****************************************
+ * Determine if slot 0 of the vtbl[] is reserved for something else.
+ * For class objects, yes, this is where the classinfo ptr goes.
+ * For COM interfaces, no.
+ * For non-COM interfaces, yes, this is where the Interface ptr goes.
+ */
+
+int ClassDeclaration::vtblOffset()
+{
+    return 1;
+}
+
+/****************************************
+ */
+
+char *ClassDeclaration::kind()
+{
+    return "class";
+}
+
+/****************************************
+ */
+
+void ClassDeclaration::addLocalClass(ClassDeclarations *aclasses)
+{
+    aclasses->push(this);
+}
+
+/********************************* InterfaceDeclaration ****************************/
+
+InterfaceDeclaration::InterfaceDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses)
+    : ClassDeclaration(loc, id, baseclasses)
+{
+    com = 0;
+    if (id == Id::IUnknown)		// IUnknown is the root of all COM objects
+	com = 1;
+}
+
+Dsymbol *InterfaceDeclaration::syntaxCopy(Dsymbol *s)
+{
+    InterfaceDeclaration *id;
+
+    if (s)
+	id = (InterfaceDeclaration *)s;
+    else
+	id = new InterfaceDeclaration(loc, ident, NULL);
+
+    ClassDeclaration::syntaxCopy(id);
+    return id;
+}
+
+void InterfaceDeclaration::semantic(Scope *sc)
+{   int i;
+
+    //printf("InterfaceDeclaration::semantic(%s), type = %p\n", toChars(), type);
+    if (!scope)
+    {	type = type->semantic(loc, sc);
+	handle = handle->semantic(loc, sc);
+    }
+    if (!members)			// if forward reference
+    {	//printf("\tinterface '%s' is forward referenced\n", toChars());
+	return;
+    }
+    if (symtab)			// if already done
+    {	if (!scope)
+	    return;
+    }
+    else
+	symtab = new DsymbolTable();
+
+    Scope *scx = NULL;
+    if (scope)
+    {	sc = scope;
+	scx = scope;		// save so we don't make redundant copies
+	scope = NULL;
+    }
+
+    // Expand any tuples in baseclasses[]
+    for (i = 0; i < baseclasses.dim; )
+    {	BaseClass *b = (BaseClass *)baseclasses.data[0];
+	b->type = b->type->semantic(loc, sc);
+	Type *tb = b->type->toBasetype();
+
+	if (tb->ty == Ttuple)
+	{   TypeTuple *tup = (TypeTuple *)tb;
+	    enum PROT protection = b->protection;
+	    baseclasses.remove(i);
+	    size_t dim = Argument::dim(tup->arguments);
+	    for (size_t j = 0; j < dim; j++)
+	    {	Argument *arg = Argument::getNth(tup->arguments, j);
+		b = new BaseClass(arg->type, protection);
+		baseclasses.insert(i + j, b);
+	    }
+	}
+	else
+	    i++;
+    }
+
+    // Check for errors, handle forward references
+    for (i = 0; i < baseclasses.dim; )
+    {	TypeClass *tc;
+	BaseClass *b;
+	Type *tb;
+
+	b = (BaseClass *)baseclasses.data[i];
+	b->type = b->type->semantic(loc, sc);
+	tb = b->type->toBasetype();
+	if (tb->ty == Tclass)
+	    tc = (TypeClass *)tb;
+	else
+	    tc = NULL;
+	if (!tc || !tc->sym->isInterfaceDeclaration())
+	{
+	    error("base type must be interface, not %s", b->type->toChars());
+	    baseclasses.remove(i);
+	    continue;
+	}
+	else
+	{
+	    // Check for duplicate interfaces
+	    for (size_t j = 0; j < i; j++)
+	    {
+		BaseClass *b2 = (BaseClass *)baseclasses.data[j];
+		if (b2->base == tc->sym)
+		    error("inherits from duplicate interface %s", b2->base->toChars());
+	    }
+
+	    b->base = tc->sym;
+	    if (b->base == this || isBaseOf2(b->base))
+	    {
+		error("circular inheritance of interface");
+		baseclasses.remove(i);
+		continue;
+	    }
+	    if (!b->base->symtab || b->base->scope)
+	    {
+		//error("forward reference of base class %s", baseClass->toChars());
+		// Forward reference of base, try again later
+		//printf("\ttry later, forward reference of base %s\n", b->base->toChars());
+		scope = scx ? scx : new Scope(*sc);
+		scope->setNoFree();
+		scope->module->addDeferredSemantic(this);
+		return;
+	    }
+	}
+	i++;
+    }
+
+    interfaces_dim = baseclasses.dim;
+    interfaces = (BaseClass **)baseclasses.data;
+
+    interfaceSemantic(sc);
+
+    if (vtblOffset())
+	vtbl.push(this);		// leave room at vtbl[0] for classinfo
+
+    // Cat together the vtbl[]'s from base interfaces
+    for (i = 0; i < interfaces_dim; i++)
+    {	BaseClass *b = interfaces[i];
+
+	// Skip if b has already appeared
+	for (int k = 0; k < i; k++)
+	{
+	    if (b == interfaces[i])
+		goto Lcontinue;
+	}
+
+	// Copy vtbl[] from base class
+	if (b->base->vtblOffset())
+	{   int d = b->base->vtbl.dim;
+	    if (d > 1)
+	    {
+		vtbl.reserve(d - 1);
+		for (int j = 1; j < d; j++)
+		    vtbl.push(b->base->vtbl.data[j]);
+	    }
+	}
+	else
+	{
+	    vtbl.append(&b->base->vtbl);
+	}
+
+      Lcontinue:
+	;
+    }
+
+    for (i = 0; i < members->dim; i++)
+    {
+	Dsymbol *s = (Dsymbol *)members->data[i];
+	s->addMember(sc, this, 1);
+    }
+
+    sc = sc->push(this);
+    sc->parent = this;
+    if (isCOMclass())
+	sc->linkage = LINKwindows;
+    sc->structalign = 8;
+    structalign = sc->structalign;
+    sc->offset = 8;
+    for (i = 0; i < members->dim; i++)
+    {
+	Dsymbol *s = (Dsymbol *)members->data[i];
+	s->semantic(sc);
+    }
+    //members->print();
+    sc->pop();
+    //printf("-InterfaceDeclaration::semantic(%s), type = %p\n", toChars(), type);
+}
+
+
+/*******************************************
+ * Determine if 'this' is a base class of cd.
+ * (Actually, if it is an interface supported by cd)
+ * Output:
+ *	*poffset	offset to start of class
+ *			OFFSET_RUNTIME	must determine offset at runtime
+ * Returns:
+ *	0	not a base
+ *	1	is a base
+ */
+
+int InterfaceDeclaration::isBaseOf(ClassDeclaration *cd, int *poffset)
+{
+    unsigned j;
+
+    //printf("%s.InterfaceDeclaration::isBaseOf(cd = '%s')\n", toChars(), cd->toChars());
+    assert(!baseClass);
+    for (j = 0; j < cd->interfaces_dim; j++)
+    {
+	BaseClass *b = cd->interfaces[j];
+
+	//printf("\tbase %s\n", b->base->toChars());
+	if (this == b->base)
+	{
+	    //printf("\tfound at offset %d\n", b->offset);
+	    if (poffset)
+	    {	*poffset = b->offset;
+		if (j && cd->isInterfaceDeclaration())
+		    *poffset = OFFSET_RUNTIME;
+	    }
+	    return 1;
+	}
+	if (isBaseOf(b, poffset))
+	{   if (j && poffset && cd->isInterfaceDeclaration())
+		*poffset = OFFSET_RUNTIME;
+	    return 1;
+	}
+    }
+
+    if (cd->baseClass && isBaseOf(cd->baseClass, poffset))
+	return 1;
+
+    if (poffset)
+	*poffset = 0;
+    return 0;
+}
+
+
+int InterfaceDeclaration::isBaseOf(BaseClass *bc, int *poffset)
+{
+    //printf("%s.InterfaceDeclaration::isBaseOf(bc = '%s')\n", toChars(), bc->base->toChars());
+    for (unsigned j = 0; j < bc->baseInterfaces_dim; j++)
+    {
+	BaseClass *b = &bc->baseInterfaces[j];
+
+	if (this == b->base)
+	{
+	    if (poffset)
+	    {	*poffset = b->offset;
+	    }
+	    return 1;
+	}
+	if (isBaseOf(b, poffset))
+	{
+	    return 1;
+	}
+    }
+    if (poffset)
+	*poffset = 0;
+    return 0;
+}
+
+/****************************************
+ * Determine if slot 0 of the vtbl[] is reserved for something else.
+ * For class objects, yes, this is where the classinfo ptr goes.
+ * For COM interfaces, no.
+ * For non-COM interfaces, yes, this is where the Interface ptr goes.
+ */
+
+int InterfaceDeclaration::vtblOffset()
+{
+    if (isCOMclass())
+	return 0;
+    return 1;
+}
+
+/*******************************************
+ */
+
+char *InterfaceDeclaration::kind()
+{
+    return "interface";
+}
+
+
+/******************************** BaseClass *****************************/
+
+BaseClass::BaseClass()
+{
+    memset(this, 0, sizeof(BaseClass));
+}
+
+BaseClass::BaseClass(Type *type, enum PROT protection)
+{
+    //printf("BaseClass(this = %p, '%s')\n", this, type->toChars());
+    this->type = type;
+    this->protection = protection;
+    base = NULL;
+    offset = 0;
+
+    baseInterfaces_dim = 0;
+    baseInterfaces = NULL;
+}
+
+/****************************************
+ * Fill in vtbl[] for base class based on member functions of class cd.
+ * Input:
+ *	vtbl		if !=NULL, fill it in
+ *	newinstance	!=0 means all entries must be filled in by members
+ *			of cd, not members of any base classes of cd.
+ * Returns:
+ *	!=0 if any entries were filled in by members of cd (not exclusively
+ *	by base classes)
+ */
+
+int BaseClass::fillVtbl(ClassDeclaration *cd, Array *vtbl, int newinstance)
+{
+    ClassDeclaration *id = base;
+    int j;
+    int result = 0;
+
+    //printf("BaseClass::fillVtbl(this='%s', cd='%s')\n", base->toChars(), cd->toChars());
+    if (vtbl)
+	vtbl->setDim(base->vtbl.dim);
+
+    // first entry is ClassInfo reference
+    for (j = base->vtblOffset(); j < base->vtbl.dim; j++)
+    {
+	FuncDeclaration *ifd = ((Dsymbol *)base->vtbl.data[j])->isFuncDeclaration();
+	FuncDeclaration *fd;
+	TypeFunction *tf;
+
+	//printf("        vtbl[%d] is '%s'\n", j, ifd ? ifd->toChars() : "null");
+
+	assert(ifd);
+	// Find corresponding function in this class
+	tf = (ifd->type->ty == Tfunction) ? (TypeFunction *)(ifd->type) : NULL;
+	fd = cd->findFunc(ifd->ident, tf);
+	if (fd && !fd->isAbstract())
+	{
+	    //printf("            found\n");
+	    // Check that calling conventions match
+	    if (fd->linkage != ifd->linkage)
+		fd->error("linkage doesn't match interface function");
+
+	    // Check that it is current
+	    if (newinstance &&
+		fd->toParent() != cd &&
+		ifd->toParent() == base)
+		cd->error("interface function %s.%s is not implemented",
+		    id->toChars(), ifd->ident->toChars());
+
+	    if (fd->toParent() == cd)
+		result = 1;
+	}
+	else
+	{
+	    //printf("            not found\n");
+	    // BUG: should mark this class as abstract?
+	    if (!cd->isAbstract())
+		cd->error("interface function %s.%s isn't implemented",
+		    id->toChars(), ifd->ident->toChars());
+	    fd = NULL;
+	}
+	if (vtbl)
+	    vtbl->data[j] = fd;
+    }
+
+    return result;
+}
+
+void BaseClass::copyBaseInterfaces(BaseClasses *vtblInterfaces)
+{
+    //printf("+copyBaseInterfaces(), %s\n", base->toChars());
+//    if (baseInterfaces_dim)
+//	return;
+
+    baseInterfaces_dim = base->interfaces_dim;
+    baseInterfaces = (BaseClass *)mem.calloc(baseInterfaces_dim, sizeof(BaseClass));
+
+    //printf("%s.copyBaseInterfaces()\n", base->toChars());
+    for (int i = 0; i < baseInterfaces_dim; i++)
+    {
+	BaseClass *b = &baseInterfaces[i];
+	BaseClass *b2 = base->interfaces[i];
+
+	assert(b2->vtbl.dim == 0);	// should not be filled yet
+	memcpy(b, b2, sizeof(BaseClass));
+
+	if (i)				// single inheritance is i==0
+	    vtblInterfaces->push(b);	// only need for M.I.
+	b->copyBaseInterfaces(vtblInterfaces);
+    }
+    //printf("-copyBaseInterfaces\n");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/complex_t.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,74 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright and Burton Radons
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#ifndef DMD_COMPLEX_T_H
+#define DMD_COMPLEX_T_H
+
+/* Roll our own complex type for compilers that don't support complex
+ */
+
+struct complex_t
+{
+    long double re;
+    long double im;    
+
+    complex_t() { this->re = 0; this->im = 0; }
+    complex_t(long double re) { this->re = re; this->im = 0; }
+    complex_t(long double re, long double im) { this->re = re; this->im = im; }
+
+    complex_t operator + (complex_t y) { complex_t r; r.re = re + y.re; r.im = im + y.im; return r; }
+    complex_t operator - (complex_t y) { complex_t r; r.re = re - y.re; r.im = im - y.im; return r; }
+    complex_t operator - () { complex_t r; r.re = -re; r.im = -im; return r; }
+    complex_t operator * (complex_t y) { return complex_t(re * y.re - im * y.im, im * y.re + re * y.im); }
+    
+    complex_t operator / (complex_t y)
+    {
+	long double abs_y_re = y.re < 0 ? -y.re : y.re;
+	long double abs_y_im = y.im < 0 ? -y.im : y.im;
+	long double r, den;
+
+	if (abs_y_re < abs_y_im)
+	{
+	    r = y.re / y.im;
+	    den = y.im + r * y.re;
+	    return complex_t((re * r + im) / den,
+			     (im * r - re) / den);
+	}
+	else
+	{
+	    r = y.im / y.re;
+	    den = y.re + r * y.im;
+	    return complex_t((re + r * im) / den,
+			     (im - r * re) / den);
+	}
+    }
+
+    operator bool () { return re || im; }
+
+    int operator == (complex_t y) { return re == y.re && im == y.im; }
+    int operator != (complex_t y) { return re != y.re || im != y.im; }
+};
+
+inline complex_t operator * (long double x, complex_t y) { return complex_t(x) * y; }
+inline complex_t operator * (complex_t x, long double y) { return x * complex_t(y); }
+inline complex_t operator / (complex_t x, long double y) { return x / complex_t(y); }
+
+
+inline long double creall(complex_t x)
+{
+    return x.re;
+}
+
+inline long double cimagl(complex_t x)
+{
+    return x.im;
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/cond.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,390 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "id.h"
+#include "init.h"
+#include "declaration.h"
+#include "identifier.h"
+#include "expression.h"
+#include "cond.h"
+#include "module.h"
+#include "template.h"
+#include "lexer.h"
+#ifdef _DH
+#include "mtype.h"
+#include "scope.h"
+#endif
+
+int findCondition(Array *ids, Identifier *ident)
+{
+    if (ids)
+    {
+	for (int i = 0; i < ids->dim; i++)
+	{
+	    char *id = (char *)ids->data[i];
+
+	    if (strcmp(id, ident->toChars()) == 0)
+		return TRUE;
+	}
+    }
+
+    return FALSE;
+}
+
+/* ============================================================ */
+
+Condition::Condition(Loc loc)
+{
+    this->loc = loc;
+    inc = 0;
+}
+
+/* ============================================================ */
+
+DVCondition::DVCondition(Module *mod, unsigned level, Identifier *ident)
+	: Condition(0)
+{
+    this->mod = mod;
+    this->level = level;
+    this->ident = ident;
+}
+
+Condition *DVCondition::syntaxCopy()
+{
+    return this;	// don't need to copy
+}
+
+/* ============================================================ */
+
+void DebugCondition::setGlobalLevel(unsigned level)
+{
+    global.params.debuglevel = level;
+}
+
+void DebugCondition::addGlobalIdent(char *ident)
+{
+    if (!global.params.debugids)
+	global.params.debugids = new Array();
+    global.params.debugids->push(ident);
+}
+
+
+DebugCondition::DebugCondition(Module *mod, unsigned level, Identifier *ident)
+    : DVCondition(mod, level, ident)
+{
+}
+
+int DebugCondition::include(Scope *sc, ScopeDsymbol *s)
+{
+    //printf("DebugCondition::include() level = %d, debuglevel = %d\n", level, global.params.debuglevel);
+    if (inc == 0)
+    {
+	inc = 2;
+	if (ident)
+	{
+	    if (findCondition(mod->debugids, ident))
+		inc = 1;
+	    else if (findCondition(global.params.debugids, ident))
+		inc = 1;
+	    else
+	    {	if (!mod->debugidsNot)
+		    mod->debugidsNot = new Array();
+		mod->debugidsNot->push(ident->toChars());
+	    }
+	}
+	else if (level <= global.params.debuglevel || level <= mod->debuglevel)
+	    inc = 1;
+    }
+    return (inc == 1);
+}
+
+void DebugCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    if (ident)
+	buf->printf("debug (%s)", ident->toChars());
+    else
+	buf->printf("debug (%u)", level);
+}
+
+/* ============================================================ */
+
+void VersionCondition::setGlobalLevel(unsigned level)
+{
+    global.params.versionlevel = level;
+}
+
+void VersionCondition::checkPredefined(Loc loc, char *ident)
+{
+    static char* reserved[] =
+    {
+	"DigitalMars", "X86", "X86_64",
+	"Windows", "Win32", "Win64",
+	"linux",
+	"LittleEndian", "BigEndian",
+	"all",
+	"none",
+    };
+
+    for (unsigned i = 0; i < sizeof(reserved) / sizeof(reserved[0]); i++)
+    {
+	if (strcmp(ident, reserved[i]) == 0)
+	    goto Lerror;
+    }
+
+    if (ident[0] == 'D' && ident[1] == '_')
+	goto Lerror;
+
+    return;
+
+  Lerror:
+    error(loc, "version identifier '%s' is reserved and cannot be set", ident);
+}
+
+void VersionCondition::addGlobalIdent(char *ident)
+{
+    checkPredefined(0, ident);
+    addPredefinedGlobalIdent(ident);
+}
+
+void VersionCondition::addPredefinedGlobalIdent(char *ident)
+{
+    if (!global.params.versionids)
+	global.params.versionids = new Array();
+    global.params.versionids->push(ident);
+}
+
+
+VersionCondition::VersionCondition(Module *mod, unsigned level, Identifier *ident)
+    : DVCondition(mod, level, ident)
+{
+}
+
+int VersionCondition::include(Scope *sc, ScopeDsymbol *s)
+{
+    //printf("VersionCondition::include() level = %d, versionlevel = %d\n", level, global.params.versionlevel);
+    //if (ident) printf("\tident = '%s'\n", ident->toChars());
+    if (inc == 0)
+    {
+	inc = 2;
+	if (ident)
+	{
+	    if (findCondition(mod->versionids, ident))
+		inc = 1;
+	    else if (findCondition(global.params.versionids, ident))
+		inc = 1;
+	    else
+	    {
+		if (!mod->versionidsNot)
+		    mod->versionidsNot = new Array();
+		mod->versionidsNot->push(ident->toChars());
+	    }
+	}
+	else if (level <= global.params.versionlevel || level <= mod->versionlevel)
+	    inc = 1;
+    }
+    return (inc == 1);
+}
+
+void VersionCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    if (ident)
+	buf->printf("version (%s)", ident->toChars());
+    else
+	buf->printf("version (%u)", level);
+}
+
+
+/**************************** StaticIfCondition *******************************/
+
+StaticIfCondition::StaticIfCondition(Loc loc, Expression *exp)
+    : Condition(loc)
+{
+    this->exp = exp;
+}
+
+Condition *StaticIfCondition::syntaxCopy()
+{
+    return new StaticIfCondition(loc, exp->syntaxCopy());
+}
+
+int StaticIfCondition::include(Scope *sc, ScopeDsymbol *s)
+{
+#if 0
+    printf("StaticIfCondition::include(sc = %p, s = %p)\n", sc, s);
+    if (s)
+    {
+	printf("\ts = '%s', kind = %s\n", s->toChars(), s->kind());
+    }
+#endif
+    if (inc == 0)
+    {
+	if (!sc)
+	{
+	    error(loc, "static if conditional cannot be at global scope");
+	    inc = 2;
+	    return 0;
+	}
+
+	sc = sc->push(sc->scopesym);
+	sc->sd = s;			// s gets any addMember()
+	sc->flags |= SCOPEstaticif;
+	Expression *e = exp->semantic(sc);
+	sc->pop();
+	e = e->optimize(WANTvalue | WANTinterpret);
+	if (e->isBool(TRUE))
+	    inc = 1;
+	else if (e->isBool(FALSE))
+	    inc = 2;
+	else
+	{
+	    e->error("expression %s is not constant or does not evaluate to a bool", e->toChars());
+	    inc = 2;
+	}
+    }
+    return (inc == 1);
+}
+
+void StaticIfCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("static if(");
+    exp->toCBuffer(buf, hgs);
+    buf->writeByte(')');
+}
+
+
+/**************************** IftypeCondition *******************************/
+
+IftypeCondition::IftypeCondition(Loc loc, Type *targ, Identifier *id, enum TOK tok, Type *tspec)
+    : Condition(loc)
+{
+    this->targ = targ;
+    this->id = id;
+    this->tok = tok;
+    this->tspec = tspec;
+}
+
+Condition *IftypeCondition::syntaxCopy()
+{
+    return new IftypeCondition(loc,
+	targ->syntaxCopy(),
+	id,
+	tok,
+	tspec ? tspec->syntaxCopy() : NULL);
+}
+
+int IftypeCondition::include(Scope *sc, ScopeDsymbol *sd)
+{
+    //printf("IftypeCondition::include()\n");
+    if (inc == 0)
+    {
+	if (!sc)
+	{
+	    error(loc, "iftype conditional cannot be at global scope");
+	    inc = 2;
+	    return 0;
+	}
+	unsigned errors = global.errors;
+	global.gag++;			// suppress printing of error messages
+	targ = targ->semantic(loc, sc);
+	global.gag--;
+	if (errors != global.errors)	// if any errors happened
+	{   inc = 2;			// then condition is false
+	    global.errors = errors;
+	}
+	else if (id && tspec)
+	{
+	    /* Evaluate to TRUE if targ matches tspec.
+	     * If TRUE, declare id as an alias for the specialized type.
+	     */
+
+	    MATCH m;
+	    TemplateTypeParameter tp(loc, id, NULL, NULL);
+
+	    TemplateParameters parameters;
+	    parameters.setDim(1);
+	    parameters.data[0] = (void *)&tp;
+
+	    Objects dedtypes;
+	    dedtypes.setDim(1);
+
+	    m = targ->deduceType(NULL, tspec, &parameters, &dedtypes);
+	    if (m == MATCHnomatch ||
+		(m != MATCHexact && tok == TOKequal))
+		inc = 2;
+	    else
+	    {
+		inc = 1;
+		Type *tded = (Type *)dedtypes.data[0];
+		if (!tded)
+		    tded = targ;
+		Dsymbol *s = new AliasDeclaration(loc, id, tded);
+		s->semantic(sc);
+		sc->insert(s);
+		if (sd)
+		    s->addMember(sc, sd, 1);
+	    }
+	}
+	else if (id)
+	{
+	    /* Declare id as an alias for type targ. Evaluate to TRUE
+	     */
+	    Dsymbol *s = new AliasDeclaration(loc, id, targ);
+	    s->semantic(sc);
+	    sc->insert(s);
+	    if (sd)
+		s->addMember(sc, sd, 1);
+	    inc = 1;
+	}
+	else if (tspec)
+	{
+	    /* Evaluate to TRUE if targ matches tspec
+	     */
+	    tspec = tspec->semantic(loc, sc);
+	    //printf("targ  = %s\n", targ->toChars());
+	    //printf("tspec = %s\n", tspec->toChars());
+	    if (tok == TOKcolon)
+	    {   if (targ->implicitConvTo(tspec))
+		    inc = 1;
+		else
+		    inc = 2;
+	    }
+	    else /* == */
+	    {	if (targ->equals(tspec))
+		    inc = 1;
+		else
+		    inc = 2;
+	    }
+	}
+	else
+	     inc = 1;
+	//printf("inc = %d\n", inc);
+    }
+    return (inc == 1);
+}
+
+void IftypeCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("iftype(");
+    targ->toCBuffer(buf, id, hgs);
+    if (tspec)
+    {
+	if (tok == TOKcolon)
+	    buf->writestring(" : ");
+	else
+	    buf->writestring(" == ");
+	tspec->toCBuffer(buf, NULL, hgs);
+    }
+    buf->writeByte(')');
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/cond.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,106 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#ifndef DMD_DEBCOND_H
+#define DMD_DEBCOND_H
+
+struct Expression;
+struct Identifier;
+struct OutBuffer;
+struct Module;
+struct Scope;
+struct ScopeDsymbol;
+#ifdef _DH
+#include "lexer.h" // dmdhg
+#endif
+enum TOK;
+#ifdef _DH
+struct HdrGenState;
+#endif
+
+int findCondition(Array *ids, Identifier *ident);
+
+struct Condition
+{
+    Loc loc;
+    int inc;		// 0: not computed yet
+			// 1: include
+			// 2: do not include
+
+    Condition(Loc loc);
+
+    virtual Condition *syntaxCopy() = 0;
+    virtual int include(Scope *sc, ScopeDsymbol *s) = 0;
+    virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs) = 0;
+};
+
+struct DVCondition : Condition
+{
+    unsigned level;
+    Identifier *ident;
+    Module *mod;
+
+    DVCondition(Module *mod, unsigned level, Identifier *ident);
+
+    Condition *syntaxCopy();
+};
+
+struct DebugCondition : DVCondition
+{
+    static void setGlobalLevel(unsigned level);
+    static void addGlobalIdent(char *ident);
+    static void addPredefinedGlobalIdent(char *ident);
+
+    DebugCondition(Module *mod, unsigned level, Identifier *ident);
+
+    int include(Scope *sc, ScopeDsymbol *s);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+struct VersionCondition : DVCondition
+{
+    static void setGlobalLevel(unsigned level);
+    static void checkPredefined(Loc loc, char *ident);
+    static void addGlobalIdent(char *ident);
+    static void addPredefinedGlobalIdent(char *ident);
+
+    VersionCondition(Module *mod, unsigned level, Identifier *ident);
+
+    int include(Scope *sc, ScopeDsymbol *s);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+struct StaticIfCondition : Condition
+{
+    Expression *exp;
+
+    StaticIfCondition(Loc loc, Expression *exp);
+    Condition *syntaxCopy();
+    int include(Scope *sc, ScopeDsymbol *s);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+struct IftypeCondition : Condition
+{
+    /* iftype (targ id tok tspec)
+     */
+    Type *targ;
+    Identifier *id;	// can be NULL
+    enum TOK tok;	// ':' or '=='
+    Type *tspec;	// can be NULL
+
+    IftypeCondition(Loc loc, Type *targ, Identifier *id, enum TOK tok, Type *tspec);
+    Condition *syntaxCopy();
+    int include(Scope *sc, ScopeDsymbol *s);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/constfold.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,1461 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <math.h>
+
+#if __DMC__
+#include <complex.h>
+#endif
+
+#include "mem.h"
+#include "root.h"
+
+#include "mtype.h"
+#include "expression.h"
+#include "aggregate.h"
+#include "declaration.h"
+
+#ifdef IN_GCC
+#include "d-gcc-real.h"
+
+/* %% fix? */
+extern "C" bool real_isnan (const real_t *);
+#endif
+
+static real_t zero;	// work around DMC bug for now
+
+#define LOG 0
+
+Expression *expType(Type *type, Expression *e)
+{
+    if (type != e->type)
+    {
+	e = e->copy();
+	e->type = type;
+    }
+    return e;
+}
+
+/* ================================== isConst() ============================== */
+
+int Expression::isConst()
+{
+    //printf("Expression::isConst(): %s\n", toChars());
+    return 0;
+}
+
+int IntegerExp::isConst()
+{
+    return 1;
+}
+
+int RealExp::isConst()
+{
+    return 1;
+}
+
+int ComplexExp::isConst()
+{
+    return 1;
+}
+
+int SymOffExp::isConst()
+{
+    return 2;
+}
+
+/* =============================== constFold() ============================== */
+
+/* The constFold() functions were redundant with the optimize() ones,
+ * and so have been folded in with them.
+ */
+
+/* ========================================================================== */
+
+Expression *Neg(Type *type, Expression *e1)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    if (e1->type->isreal())
+    {
+	e = new RealExp(loc, -e1->toReal(), type);
+    }
+    else if (e1->type->isimaginary())
+    {
+	e = new RealExp(loc, -e1->toImaginary(), type);
+    }
+    else if (e1->type->iscomplex())
+    {
+	e = new ComplexExp(loc, -e1->toComplex(), type);
+    }
+    else
+	e = new IntegerExp(loc, -e1->toInteger(), type);
+    return e;
+}
+
+Expression *Com(Type *type, Expression *e1)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    e = new IntegerExp(loc, ~e1->toInteger(), type);
+    return e;
+}
+
+Expression *Not(Type *type, Expression *e1)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    e = new IntegerExp(loc, e1->isBool(0), type);
+    return e;
+}
+
+Expression *Bool(Type *type, Expression *e1)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    e = new IntegerExp(loc, e1->isBool(1), type);
+    return e;
+}
+
+Expression *Add(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+#if LOG
+    printf("Add(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
+#endif
+    if (type->isreal())
+    {
+	e = new RealExp(loc, e1->toReal() + e2->toReal(), type);
+    }
+    else if (type->isimaginary())
+    {
+	e = new RealExp(loc, e1->toImaginary() + e2->toImaginary(), type);
+    }
+    else if (type->iscomplex())
+    {
+	// This rigamarole is necessary so that -0.0 doesn't get
+	// converted to +0.0 by doing an extraneous add with +0.0
+	complex_t c1;
+	real_t r1;
+	real_t i1;
+
+	complex_t c2;
+	real_t r2;
+	real_t i2;
+
+	complex_t v;
+	int x;
+
+	if (e1->type->isreal())
+	{   r1 = e1->toReal();
+	    x = 0;
+	}
+	else if (e1->type->isimaginary())
+	{   i1 = e1->toImaginary();
+	    x = 3;
+	}
+	else
+	{   c1 = e1->toComplex();
+	    x = 6;
+	}
+
+	if (e2->type->isreal())
+	{   r2 = e2->toReal();
+	}
+	else if (e2->type->isimaginary())
+	{   i2 = e2->toImaginary();
+	    x += 1;
+	}
+	else
+	{   c2 = e2->toComplex();
+	    x += 2;
+	}
+
+	switch (x)
+	{
+#if __DMC__
+	    case 0+0:	v = (complex_t) (r1 + r2);	break;
+	    case 0+1:	v = r1 + i2 * I;		break;
+	    case 0+2:	v = r1 + c2;			break;
+	    case 3+0:	v = i1 * I + r2;		break;
+	    case 3+1:	v = (complex_t) ((i1 + i2) * I); break;
+	    case 3+2:	v = i1 * I + c2;		break;
+	    case 6+0:	v = c1 + r2;			break;
+	    case 6+1:	v = c1 + i2 * I;		break;
+	    case 6+2:	v = c1 + c2;			break;
+#else
+	    case 0+0:	v = complex_t(r1 + r2, 0);	break;
+	    case 0+1:	v = complex_t(r1, i2);		break;
+	    case 0+2:	v = complex_t(r1 + creall(c2), cimagl(c2));	break;
+	    case 3+0:	v = complex_t(r2, i1);		break;
+	    case 3+1:	v = complex_t(0, i1 + i2);	break;
+	    case 3+2:	v = complex_t(creall(c2), i1 + cimagl(c2));	break;
+	    case 6+0:	v = complex_t(creall(c1) + r2, cimagl(c2));	break;
+	    case 6+1:	v = complex_t(creall(c1), cimagl(c1) + i2);	break;
+	    case 6+2:	v = c1 + c2;			break;
+#endif
+	    default: assert(0);
+	}
+	e = new ComplexExp(loc, v, type);
+    }
+    else if (e1->op == TOKsymoff)
+    {
+	SymOffExp *soe = (SymOffExp *)e1;
+	e = new SymOffExp(loc, soe->var, soe->offset + e2->toInteger());
+	e->type = type;
+    }
+    else if (e2->op == TOKsymoff)
+    {
+	SymOffExp *soe = (SymOffExp *)e2;
+	e = new SymOffExp(loc, soe->var, soe->offset + e1->toInteger());
+	e->type = type;
+    }
+    else
+	e = new IntegerExp(loc, e1->toInteger() + e2->toInteger(), type);
+    return e;
+}
+
+
+Expression *Min(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    if (type->isreal())
+    {
+	e = new RealExp(loc, e1->toReal() - e2->toReal(), type);
+    }
+    else if (type->isimaginary())
+    {
+	e = new RealExp(loc, e1->toImaginary() - e2->toImaginary(), type);
+    }
+    else if (type->iscomplex())
+    {
+	// This rigamarole is necessary so that -0.0 doesn't get
+	// converted to +0.0 by doing an extraneous add with +0.0
+	complex_t c1;
+	real_t r1;
+	real_t i1;
+
+	complex_t c2;
+	real_t r2;
+	real_t i2;
+
+	complex_t v;
+	int x;
+
+	if (e1->type->isreal())
+	{   r1 = e1->toReal();
+	    x = 0;
+	}
+	else if (e1->type->isimaginary())
+	{   i1 = e1->toImaginary();
+	    x = 3;
+	}
+	else
+	{   c1 = e1->toComplex();
+	    x = 6;
+	}
+
+	if (e2->type->isreal())
+	{   r2 = e2->toReal();
+	}
+	else if (e2->type->isimaginary())
+	{   i2 = e2->toImaginary();
+	    x += 1;
+	}
+	else
+	{   c2 = e2->toComplex();
+	    x += 2;
+	}
+
+	switch (x)
+	{
+#if __DMC__
+	    case 0+0:	v = (complex_t) (r1 - r2);	break;
+	    case 0+1:	v = r1 - i2 * I;		break;
+	    case 0+2:	v = r1 - c2;			break;
+	    case 3+0:	v = i1 * I - r2;		break;
+	    case 3+1:	v = (complex_t) ((i1 - i2) * I); break;
+	    case 3+2:	v = i1 * I - c2;		break;
+	    case 6+0:	v = c1 - r2;			break;
+	    case 6+1:	v = c1 - i2 * I;		break;
+	    case 6+2:	v = c1 - c2;			break;
+#else
+	    case 0+0:	v = complex_t(r1 - r2, 0);	break;
+	    case 0+1:	v = complex_t(r1, -i2);		break;
+	    case 0+2:	v = complex_t(r1 - creall(c2), -cimagl(c2));	break;
+	    case 3+0:	v = complex_t(-r2, i1);		break;
+	    case 3+1:	v = complex_t(0, i1 - i2);	break;
+	    case 3+2:	v = complex_t(-creall(c2), i1 - cimagl(c2));	break;
+	    case 6+0:	v = complex_t(creall(c1) - r2, cimagl(c1));	break;
+	    case 6+1:	v = complex_t(creall(c1), cimagl(c1) - i2);	break;
+	    case 6+2:	v = c1 - c2;			break;
+#endif
+	    default: assert(0);
+	}
+	e = new ComplexExp(loc, v, type);
+    }
+    else if (e1->op == TOKsymoff)
+    {
+	SymOffExp *soe = (SymOffExp *)e1;
+	e = new SymOffExp(loc, soe->var, soe->offset - e2->toInteger());
+	e->type = type;
+    }
+    else
+    {
+	e = new IntegerExp(loc, e1->toInteger() - e2->toInteger(), type);
+    }
+    return e;
+}
+
+Expression *Mul(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    if (type->isfloating())
+    {   complex_t c;
+#ifdef IN_GCC
+	real_t r;
+#else
+	d_float80 r;
+#endif
+
+	if (e1->type->isreal())
+	{
+#if __DMC__
+	    c = e1->toReal() * e2->toComplex();
+#else
+	    r = e1->toReal();
+	    c = e2->toComplex();
+	    c = complex_t(r * creall(c), r * cimagl(c));
+#endif
+	}
+	else if (e1->type->isimaginary())
+	{
+#if __DMC__
+	    c = e1->toImaginary() * I * e2->toComplex();
+#else
+	    r = e1->toImaginary();
+	    c = e2->toComplex();
+	    c = complex_t(-r * cimagl(c), r * creall(c));
+#endif
+	}
+	else if (e2->type->isreal())
+	{
+#if __DMC__
+	    c = e2->toReal() * e1->toComplex();
+#else
+	    r = e2->toReal();
+	    c = e1->toComplex();
+	    c = complex_t(r * creall(c), r * cimagl(c));
+#endif
+	}
+	else if (e2->type->isimaginary())
+	{
+#if __DMC__
+	    c = e1->toComplex() * e2->toImaginary() * I;
+#else
+	    r = e2->toImaginary();
+	    c = e1->toComplex();
+	    c = complex_t(-r * cimagl(c), r * creall(c));
+#endif
+	}
+	else
+	    c = e1->toComplex() * e2->toComplex();
+
+	if (type->isreal())
+	    e = new RealExp(loc, creall(c), type);
+	else if (type->isimaginary())
+	    e = new RealExp(loc, cimagl(c), type);
+	else if (type->iscomplex())
+	    e = new ComplexExp(loc, c, type);
+	else
+	    assert(0);
+    }
+    else
+    {
+	e = new IntegerExp(loc, e1->toInteger() * e2->toInteger(), type);
+    }
+    return e;
+}
+
+Expression *Div(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    if (type->isfloating())
+    {   complex_t c;
+#ifdef IN_GCC
+	real_t r;
+#else
+	d_float80 r;
+#endif
+
+	//e1->type->print();
+	//e2->type->print();
+	if (e2->type->isreal())
+	{
+	    if (e1->type->isreal())
+	    {
+		e = new RealExp(loc, e1->toReal() / e2->toReal(), type);
+		return e;
+	    }
+#if __DMC__
+	    //r = e2->toReal();
+	    //c = e1->toComplex();
+	    //printf("(%Lg + %Lgi) / %Lg\n", creall(c), cimagl(c), r);
+
+	    c = e1->toComplex() / e2->toReal();
+#else
+	    r = e2->toReal();
+	    c = e1->toComplex();
+	    c = complex_t(creall(c) / r, cimagl(c) / r);
+#endif
+	}
+	else if (e2->type->isimaginary())
+	{
+#if __DMC__
+	    //r = e2->toImaginary();
+	    //c = e1->toComplex();
+	    //printf("(%Lg + %Lgi) / %Lgi\n", creall(c), cimagl(c), r);
+
+	    c = e1->toComplex() / (e2->toImaginary() * I);
+#else
+	    r = e2->toImaginary();
+	    c = e1->toComplex();
+	    c = complex_t(cimagl(c) / r, -creall(c) / r);
+#endif
+	}
+	else
+	{
+	    c = e1->toComplex() / e2->toComplex();
+	}
+
+	if (type->isreal())
+	    e = new RealExp(loc, creall(c), type);
+	else if (type->isimaginary())
+	    e = new RealExp(loc, cimagl(c), type);
+	else if (type->iscomplex())
+	    e = new ComplexExp(loc, c, type);
+	else
+	    assert(0);
+    }
+    else
+    {   sinteger_t n1;
+	sinteger_t n2;
+	sinteger_t n;
+
+	n1 = e1->toInteger();
+	n2 = e2->toInteger();
+	if (n2 == 0)
+	{   e2->error("divide by 0");
+	    e2 = new IntegerExp(0, 1, e2->type);
+	    n2 = 1;
+	}
+	if (e1->type->isunsigned() || e2->type->isunsigned())
+	    n = ((d_uns64) n1) / ((d_uns64) n2);
+	else
+	    n = n1 / n2;
+	e = new IntegerExp(loc, n, type);
+    }
+    return e;
+}
+
+Expression *Mod(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    if (type->isfloating())
+    {
+	complex_t c;
+
+	if (e2->type->isreal())
+	{   real_t r2 = e2->toReal();
+
+#ifdef __DMC__
+	    c = fmodl(e1->toReal(), r2) + fmodl(e1->toImaginary(), r2) * I;
+#elif defined(IN_GCC)
+	    c = complex_t(e1->toReal() % r2, e1->toImaginary() % r2);
+#else
+	    c = complex_t(fmodl(e1->toReal(), r2), fmodl(e1->toImaginary(), r2));
+#endif
+	}
+	else if (e2->type->isimaginary())
+	{   real_t i2 = e2->toImaginary();
+
+#ifdef __DMC__
+	    c = fmodl(e1->toReal(), i2) + fmodl(e1->toImaginary(), i2) * I;
+#elif defined(IN_GCC)
+	    c = complex_t(e1->toReal() % i2, e1->toImaginary() % i2);
+#else
+	    c = complex_t(fmodl(e1->toReal(), i2), fmodl(e1->toImaginary(), i2));
+#endif
+	}
+	else
+	    assert(0);
+
+	if (type->isreal())
+	    e = new RealExp(loc, creall(c), type);
+	else if (type->isimaginary())
+	    e = new RealExp(loc, cimagl(c), type);
+	else if (type->iscomplex())
+	    e = new ComplexExp(loc, c, type);
+	else
+	    assert(0);
+    }
+    else
+    {   sinteger_t n1;
+	sinteger_t n2;
+	sinteger_t n;
+
+	n1 = e1->toInteger();
+	n2 = e2->toInteger();
+	if (n2 == 0)
+	{   e2->error("divide by 0");
+	    e2 = new IntegerExp(0, 1, e2->type);
+	    n2 = 1;
+	}
+	if (e1->type->isunsigned() || e2->type->isunsigned())
+	    n = ((d_uns64) n1) % ((d_uns64) n2);
+	else
+	    n = n1 % n2;
+	e = new IntegerExp(loc, n, type);
+    }
+    return e;
+}
+
+Expression *Shl(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    e = new IntegerExp(loc, e1->toInteger() << e2->toInteger(), type);
+    return e;
+}
+
+Expression *Shr(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+    unsigned count;
+    integer_t value;
+
+    value = e1->toInteger();
+    count = e2->toInteger();
+    switch (e1->type->toBasetype()->ty)
+    {
+	case Tint8:
+		value = (d_int8)(value) >> count;
+		break;
+
+	case Tuns8:
+		value = (d_uns8)(value) >> count;
+		break;
+
+	case Tint16:
+		value = (d_int16)(value) >> count;
+		break;
+
+	case Tuns16:
+		value = (d_uns16)(value) >> count;
+		break;
+
+	case Tint32:
+		value = (d_int32)(value) >> count;
+		break;
+
+	case Tuns32:
+		value = (d_uns32)(value) >> count;
+		break;
+
+	case Tint64:
+		value = (d_int64)(value) >> count;
+		break;
+
+	case Tuns64:
+		value = (d_uns64)(value) >> count;
+		break;
+
+	default:
+		assert(0);
+    }
+    e = new IntegerExp(loc, value, type);
+    return e;
+}
+
+Expression *Ushr(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+    unsigned count;
+    integer_t value;
+
+    value = e1->toInteger();
+    count = e2->toInteger();
+    switch (e1->type->toBasetype()->ty)
+    {
+	case Tint8:
+	case Tuns8:
+		assert(0);		// no way to trigger this
+		value = (value & 0xFF) >> count;
+		break;
+
+	case Tint16:
+	case Tuns16:
+		assert(0);		// no way to trigger this
+		value = (value & 0xFFFF) >> count;
+		break;
+
+	case Tint32:
+	case Tuns32:
+		value = (value & 0xFFFFFFFF) >> count;
+		break;
+
+	case Tint64:
+	case Tuns64:
+		value = (d_uns64)(value) >> count;
+		break;
+
+	default:
+		assert(0);
+    }
+    e = new IntegerExp(loc, value, type);
+    return e;
+}
+
+Expression *And(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    e = new IntegerExp(loc, e1->toInteger() & e2->toInteger(), type);
+    return e;
+}
+
+Expression *Or(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    e = new IntegerExp(loc, e1->toInteger() | e2->toInteger(), type);
+    return e;
+}
+
+Expression *Xor(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    e = new IntegerExp(loc, e1->toInteger() ^ e2->toInteger(), type);
+    return e;
+}
+
+/* Also returns EXP_CANT_INTERPRET if cannot be computed.
+ */
+Expression *Equal(enum TOK op, Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+    int cmp;
+    real_t r1;
+    real_t r2;
+
+    //printf("Equal(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
+
+    assert(op == TOKequal || op == TOKnotequal);
+
+    if (e1->op == TOKstring && e2->op == TOKstring)
+    {	StringExp *es1 = (StringExp *)e1;
+	StringExp *es2 = (StringExp *)e2;
+
+	assert(es1->sz == es2->sz);
+	if (es1->len == es2->len &&
+	    memcmp(es1->string, es2->string, es1->sz * es1->len) == 0)
+	    cmp = 1;
+	else
+	    cmp = 0;
+    }
+    else if (e1->op == TOKarrayliteral && e2->op == TOKarrayliteral)
+    {   ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1;
+	ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
+
+	if ((!es1->elements || !es1->elements->dim) &&
+	    (!es2->elements || !es2->elements->dim))
+	    cmp = 1;		// both arrays are empty
+	else if (!es1->elements || !es2->elements)
+	    cmp = 0;
+	else if (es1->elements->dim != es2->elements->dim)
+	    cmp = 0;
+	else
+	{
+	    for (size_t i = 0; i < es1->elements->dim; i++)
+	    {   Expression *ee1 = (Expression *)es1->elements->data[i];
+		Expression *ee2 = (Expression *)es2->elements->data[i];
+
+		Expression *v = Equal(TOKequal, Type::tint32, ee1, ee2);
+		if (v == EXP_CANT_INTERPRET)
+		    return EXP_CANT_INTERPRET;
+		cmp = v->toInteger();
+		if (cmp == 0)
+		    break;
+	    }
+	}
+    }
+    else if (e1->op == TOKstructliteral && e2->op == TOKstructliteral)
+    {   StructLiteralExp *es1 = (StructLiteralExp *)e1;
+	StructLiteralExp *es2 = (StructLiteralExp *)e2;
+
+	if (es1->sd != es2->sd)
+	    cmp = 0;
+	else if ((!es1->elements || !es1->elements->dim) &&
+	    (!es2->elements || !es2->elements->dim))
+	    cmp = 1;		// both arrays are empty
+	else if (!es1->elements || !es2->elements)
+	    cmp = 0;
+	else if (es1->elements->dim != es2->elements->dim)
+	    cmp = 0;
+	else
+	{
+	    cmp = 1;
+	    for (size_t i = 0; i < es1->elements->dim; i++)
+	    {   Expression *ee1 = (Expression *)es1->elements->data[i];
+		Expression *ee2 = (Expression *)es2->elements->data[i];
+
+		if (ee1 == ee2)
+		    continue;
+		if (!ee1 || !ee2)
+		{   cmp = 0;
+		    break;
+		}
+		Expression *v = Equal(TOKequal, Type::tint32, ee1, ee2);
+		if (v == EXP_CANT_INTERPRET)
+		    return EXP_CANT_INTERPRET;
+		cmp = v->toInteger();
+		if (cmp == 0)
+		    break;
+	    }
+	}
+    }
+#if 0 // Should handle this
+    else if (e1->op == TOKarrayliteral && e2->op == TOKstring)
+    {
+    }
+#endif
+    else if (e1->isConst() != 1 || e2->isConst() != 1)
+	return EXP_CANT_INTERPRET;
+    else if (e1->type->isreal())
+    {
+	r1 = e1->toReal();
+	r2 = e2->toReal();
+	goto L1;
+    }
+    else if (e1->type->isimaginary())
+    {
+	r1 = e1->toImaginary();
+	r2 = e2->toImaginary();
+     L1:
+#if __DMC__
+	cmp = (r1 == r2);
+#else
+	if (isnan(r1) || isnan(r2))	// if unordered
+	{
+	    cmp = 0;
+	}
+	else
+	{
+	    cmp = (r1 == r2);
+	}
+#endif
+    }
+    else if (e1->type->iscomplex())
+    {
+	cmp = e1->toComplex() == e2->toComplex();
+    }
+    else if (e1->type->isintegral())
+    {
+	cmp = (e1->toInteger() == e2->toInteger());
+    }
+    else
+	return EXP_CANT_INTERPRET;
+    if (op == TOKnotequal)
+	cmp ^= 1;
+    e = new IntegerExp(loc, cmp, type);
+    return e;
+}
+
+Expression *Identity(enum TOK op, Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+    int cmp;
+
+    if (e1->op == TOKsymoff && e2->op == TOKsymoff)
+    {
+	SymOffExp *es1 = (SymOffExp *)e1;
+	SymOffExp *es2 = (SymOffExp *)e2;
+
+	cmp = (es1->var == es2->var && es1->offset == es2->offset);
+    }
+    else if (e1->isConst() == 1 && e2->isConst() == 1)
+	return Equal((op == TOKidentity) ? TOKequal : TOKnotequal,
+		type, e1, e2);
+    else
+	assert(0);
+    if (op == TOKnotidentity)
+	cmp ^= 1;
+    return new IntegerExp(loc, cmp, type);
+}
+
+
+Expression *Cmp(enum TOK op, Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+    integer_t n;
+    real_t r1;
+    real_t r2;
+
+    if (e1->type->isreal())
+    {
+	r1 = e1->toReal();
+	r2 = e2->toReal();
+	goto L1;
+    }
+    else if (e1->type->isimaginary())
+    {
+	r1 = e1->toImaginary();
+	r2 = e2->toImaginary();
+     L1:
+#if __DMC__
+	// DMC is the only compiler I know of that handles NAN arguments
+	// correctly in comparisons.
+	switch (op)
+	{
+	    case TOKlt:	   n = r1 <  r2;	break;
+	    case TOKle:	   n = r1 <= r2;	break;
+	    case TOKgt:	   n = r1 >  r2;	break;
+	    case TOKge:	   n = r1 >= r2;	break;
+
+	    case TOKleg:   n = r1 <>=  r2;	break;
+	    case TOKlg:	   n = r1 <>   r2;	break;
+	    case TOKunord: n = r1 !<>= r2;	break;
+	    case TOKue:	   n = r1 !<>  r2;	break;
+	    case TOKug:	   n = r1 !<=  r2;	break;
+	    case TOKuge:   n = r1 !<   r2;	break;
+	    case TOKul:	   n = r1 !>=  r2;	break;
+	    case TOKule:   n = r1 !>   r2;	break;
+
+	    default:
+		assert(0);
+	}
+#else
+	// Don't rely on compiler, handle NAN arguments separately
+#if IN_GCC
+	if (real_isnan(&r1) || real_isnan(&r2))	// if unordered
+#else
+	if (isnan(r1) || isnan(r2))	// if unordered
+#endif
+	{
+	    switch (op)
+	    {
+		case TOKlt:	n = 0;	break;
+		case TOKle:	n = 0;	break;
+		case TOKgt:	n = 0;	break;
+		case TOKge:	n = 0;	break;
+
+		case TOKleg:	n = 0;	break;
+		case TOKlg:	n = 0;	break;
+		case TOKunord:	n = 1;	break;
+		case TOKue:	n = 1;	break;
+		case TOKug:	n = 1;	break;
+		case TOKuge:	n = 1;	break;
+		case TOKul:	n = 1;	break;
+		case TOKule:	n = 1;	break;
+
+		default:
+		    assert(0);
+	    }
+	}
+	else
+	{
+	    switch (op)
+	    {
+		case TOKlt:	n = r1 <  r2;	break;
+		case TOKle:	n = r1 <= r2;	break;
+		case TOKgt:	n = r1 >  r2;	break;
+		case TOKge:	n = r1 >= r2;	break;
+
+		case TOKleg:	n = 1;		break;
+		case TOKlg:	n = r1 != r2;	break;
+		case TOKunord:	n = 0;		break;
+		case TOKue:	n = r1 == r2;	break;
+		case TOKug:	n = r1 >  r2;	break;
+		case TOKuge:	n = r1 >= r2;	break;
+		case TOKul:	n = r1 <  r2;	break;
+		case TOKule:	n = r1 <= r2;	break;
+
+		default:
+		    assert(0);
+	    }
+	}
+#endif
+    }
+    else if (e1->type->iscomplex())
+    {
+	assert(0);
+    }
+    else
+    {   sinteger_t n1;
+	sinteger_t n2;
+
+	n1 = e1->toInteger();
+	n2 = e2->toInteger();
+	if (e1->type->isunsigned() || e2->type->isunsigned())
+	{
+	    switch (op)
+	    {
+		case TOKlt:	n = ((d_uns64) n1) <  ((d_uns64) n2);	break;
+		case TOKle:	n = ((d_uns64) n1) <= ((d_uns64) n2);	break;
+		case TOKgt:	n = ((d_uns64) n1) >  ((d_uns64) n2);	break;
+		case TOKge:	n = ((d_uns64) n1) >= ((d_uns64) n2);	break;
+
+		case TOKleg:	n = 1;					break;
+		case TOKlg:	n = ((d_uns64) n1) != ((d_uns64) n2);	break;
+		case TOKunord:	n = 0;					break;
+		case TOKue:	n = ((d_uns64) n1) == ((d_uns64) n2);	break;
+		case TOKug:	n = ((d_uns64) n1) >  ((d_uns64) n2);	break;
+		case TOKuge:	n = ((d_uns64) n1) >= ((d_uns64) n2);	break;
+		case TOKul:	n = ((d_uns64) n1) <  ((d_uns64) n2);	break;
+		case TOKule:	n = ((d_uns64) n1) <= ((d_uns64) n2);	break;
+
+		default:
+		    assert(0);
+	    }
+	}
+	else
+	{
+	    switch (op)
+	    {
+		case TOKlt:	n = n1 <  n2;	break;
+		case TOKle:	n = n1 <= n2;	break;
+		case TOKgt:	n = n1 >  n2;	break;
+		case TOKge:	n = n1 >= n2;	break;
+
+		case TOKleg:	n = 1;		break;
+		case TOKlg:	n = n1 != n2;	break;
+		case TOKunord:	n = 0;		break;
+		case TOKue:	n = n1 == n2;	break;
+		case TOKug:	n = n1 >  n2;	break;
+		case TOKuge:	n = n1 >= n2;	break;
+		case TOKul:	n = n1 <  n2;	break;
+		case TOKule:	n = n1 <= n2;	break;
+
+		default:
+		    assert(0);
+	    }
+	}
+    }
+    e = new IntegerExp(loc, n, type);
+    return e;
+}
+
+/* Also returns EXP_CANT_INTERPRET if cannot be computed.
+ *  to:	type to cast to
+ *  type: type to paint the result
+ */
+
+Expression *Cast(Type *type, Type *to, Expression *e1)
+{   Expression *e = EXP_CANT_INTERPRET;
+    Loc loc = e1->loc;
+
+    //printf("Cast(type = %s, to = %s, e1 = %s)\n", type->toChars(), to->toChars(), e1->toChars());
+    //printf("e1->type = %s\n", e1->type->toChars());
+    if (type->equals(e1->type) && to->equals(type))
+	return e1;
+
+    if (e1->isConst() != 1)
+	return EXP_CANT_INTERPRET;
+
+    Type *tb = to->toBasetype();
+    if (tb->ty == Tbool)
+	e = new IntegerExp(loc, e1->toInteger() != 0, type);
+    else if (type->isintegral())
+    {
+	if (e1->type->isfloating())
+	{   integer_t result;
+	    real_t r = e1->toReal();
+
+	    switch (type->toBasetype()->ty)
+	    {
+		case Tint8:	result = (d_int8)r;	break;
+		case Tchar:
+		case Tuns8:	result = (d_uns8)r;	break;
+		case Tint16:	result = (d_int16)r;	break;
+		case Twchar:
+		case Tuns16:	result = (d_uns16)r;	break;
+		case Tint32:	result = (d_int32)r;	break;
+		case Tdchar:
+		case Tuns32:	result = (d_uns32)r;	break;
+		case Tint64:	result = (d_int64)r;	break;
+		case Tuns64:	result = (d_uns64)r;	break;
+		default:
+		    assert(0);
+	    }
+
+	    e = new IntegerExp(loc, result, type);
+	}
+	else if (type->isunsigned())
+	    e = new IntegerExp(loc, e1->toUInteger(), type);
+	else
+	    e = new IntegerExp(loc, e1->toInteger(), type);
+    }
+    else if (tb->isreal())
+    {   real_t value = e1->toReal();
+
+	e = new RealExp(loc, value, type);
+    }
+    else if (tb->isimaginary())
+    {   real_t value = e1->toImaginary();
+
+	e = new RealExp(loc, value, type);
+    }
+    else if (tb->iscomplex())
+    {   complex_t value = e1->toComplex();
+
+	e = new ComplexExp(loc, value, type);
+    }
+    else if (tb->isscalar())
+	e = new IntegerExp(loc, e1->toInteger(), type);
+    else if (tb->ty == Tvoid)
+	e = EXP_CANT_INTERPRET;
+    else if (tb->ty == Tstruct && e1->op == TOKint64)
+    {	// Struct = 0;
+	StructDeclaration *sd = tb->toDsymbol(NULL)->isStructDeclaration();
+	assert(sd);
+	Expressions *elements = new Expressions;
+	for (size_t i = 0; i < sd->fields.dim; i++)
+	{   Dsymbol *s = (Dsymbol *)sd->fields.data[i];
+	    VarDeclaration *v = s->isVarDeclaration();
+	    assert(v);
+
+	    Expression *exp = new IntegerExp(0);
+	    exp = Cast(v->type, v->type, exp);
+	    if (exp == EXP_CANT_INTERPRET)
+		return exp;
+	    elements->push(exp);
+	}
+	e = new StructLiteralExp(loc, sd, elements);
+	e->type = type;
+    }
+    else
+    {
+	error("cannot cast %s to %s", e1->type->toChars(), type->toChars());
+	e = new IntegerExp(loc, 0, type);
+    }
+    return e;
+}
+
+
+Expression *ArrayLength(Type *type, Expression *e1)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    if (e1->op == TOKstring)
+    {	StringExp *es1 = (StringExp *)e1;
+
+	e = new IntegerExp(loc, es1->len, type);
+    }
+    else if (e1->op == TOKarrayliteral)
+    {	ArrayLiteralExp *ale = (ArrayLiteralExp *)e1;
+	size_t dim;
+
+	dim = ale->elements ? ale->elements->dim : 0;
+	e = new IntegerExp(loc, dim, type);
+    }
+    else if (e1->op == TOKassocarrayliteral)
+    {	AssocArrayLiteralExp *ale = (AssocArrayLiteralExp *)e1;
+	size_t dim = ale->keys->dim;
+
+	e = new IntegerExp(loc, dim, type);
+    }
+    else
+	e = EXP_CANT_INTERPRET;
+    return e;
+}
+
+/* Also return EXP_CANT_INTERPRET if this fails
+ */
+Expression *Index(Type *type, Expression *e1, Expression *e2)
+{   Expression *e = EXP_CANT_INTERPRET;
+    Loc loc = e1->loc;
+
+    //printf("Index(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
+    assert(e1->type);
+    if (e1->op == TOKstring && e2->op == TOKint64)
+    {	StringExp *es1 = (StringExp *)e1;
+	uinteger_t i = e2->toInteger();
+
+	if (i >= es1->len)
+	    e1->error("string index %ju is out of bounds [0 .. %zu]", i, es1->len);
+	else
+	{   integer_t value;
+
+	    switch (es1->sz)
+	    {
+		case 1:
+		    value = ((unsigned char *)es1->string)[i];
+		    break;
+
+		case 2:
+		    value = ((unsigned short *)es1->string)[i];
+		    break;
+
+		case 4:
+		    value = ((unsigned int *)es1->string)[i];
+		    break;
+
+		default:
+		    assert(0);
+		    break;
+	    }
+	    e = new IntegerExp(loc, value, type);
+	}
+    }
+    else if (e1->type->toBasetype()->ty == Tsarray && e2->op == TOKint64)
+    {	TypeSArray *tsa = (TypeSArray *)e1->type->toBasetype();
+	uinteger_t length = tsa->dim->toInteger();
+	uinteger_t i = e2->toInteger();
+
+	if (i >= length)
+	{   e2->error("array index %ju is out of bounds %s[0 .. %ju]", i, e1->toChars(), length);
+	}
+	else if (e1->op == TOKarrayliteral && !e1->checkSideEffect(2))
+	{   ArrayLiteralExp *ale = (ArrayLiteralExp *)e1;
+	    e = (Expression *)ale->elements->data[i];
+	    e->type = type;
+	}
+    }
+    else if (e1->type->toBasetype()->ty == Tarray && e2->op == TOKint64)
+    {
+	uinteger_t i = e2->toInteger();
+
+	if (e1->op == TOKarrayliteral && !e1->checkSideEffect(2))
+	{   ArrayLiteralExp *ale = (ArrayLiteralExp *)e1;
+	    if (i >= ale->elements->dim)
+	    {   e2->error("array index %ju is out of bounds %s[0 .. %u]", i, e1->toChars(), ale->elements->dim);
+	    }
+	    else
+	    {	e = (Expression *)ale->elements->data[i];
+		e->type = type;
+	    }
+	}
+    }
+    else if (e1->op == TOKassocarrayliteral && !e1->checkSideEffect(2))
+    {
+	AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)e1;
+	/* Search the keys backwards, in case there are duplicate keys
+	 */
+	for (size_t i = ae->keys->dim; i;)
+	{
+	    i--;
+	    Expression *ekey = (Expression *)ae->keys->data[i];
+	    Expression *ex = Equal(TOKequal, Type::tbool, ekey, e2);
+	    if (ex == EXP_CANT_INTERPRET)
+		return ex;
+	    if (ex->isBool(TRUE))
+	    {	e = (Expression *)ae->values->data[i];
+		e->type = type;
+		break;
+	    }
+	}
+    }
+    return e;
+}
+
+/* Also return EXP_CANT_INTERPRET if this fails
+ */
+Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr)
+{   Expression *e = EXP_CANT_INTERPRET;
+    Loc loc = e1->loc;
+
+#if LOG
+    printf("Slice()\n");
+    if (lwr)
+    {	printf("\te1 = %s\n", e1->toChars());
+	printf("\tlwr = %s\n", lwr->toChars());
+	printf("\tupr = %s\n", upr->toChars());
+    }
+#endif
+    if (e1->op == TOKstring && lwr->op == TOKint64 && upr->op == TOKint64)
+    {	StringExp *es1 = (StringExp *)e1;
+	uinteger_t ilwr = lwr->toInteger();
+	uinteger_t iupr = upr->toInteger();
+
+	if (iupr > es1->len || ilwr > iupr)
+	    e1->error("string slice [%ju .. %ju] is out of bounds", ilwr, iupr);
+	else
+	{   integer_t value;
+	    void *s;
+	    size_t len = iupr - ilwr;
+	    int sz = es1->sz;
+	    StringExp *es;
+
+	    s = mem.malloc((len + 1) * sz);
+	    memcpy((unsigned char *)s, (unsigned char *)es1->string + ilwr * sz, len * sz);
+	    memset((unsigned char *)s + len * sz, 0, sz);
+
+	    es = new StringExp(loc, s, len, es1->postfix);
+	    es->sz = sz;
+	    es->committed = 1;
+	    es->type = type;
+	    e = es;
+	}
+    }
+    else if (e1->op == TOKarrayliteral &&
+	    lwr->op == TOKint64 && upr->op == TOKint64 &&
+	    !e1->checkSideEffect(2))
+    {	ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1;
+	uinteger_t ilwr = lwr->toInteger();
+	uinteger_t iupr = upr->toInteger();
+
+	if (iupr > es1->elements->dim || ilwr > iupr)
+	    e1->error("array slice [%ju .. %ju] is out of bounds", ilwr, iupr);
+	else
+	{
+	    Expressions *elements = new Expressions();
+	    elements->setDim(iupr - ilwr);
+	    memcpy(elements->data,
+		   es1->elements->data + ilwr,
+		   (iupr - ilwr) * sizeof(es1->elements->data[0]));
+	    e = new ArrayLiteralExp(e1->loc, elements);
+	    e->type = type;
+	}
+    }
+    return e;
+}
+
+/* Also return EXP_CANT_INTERPRET if this fails
+ */
+Expression *Cat(Type *type, Expression *e1, Expression *e2)
+{   Expression *e = EXP_CANT_INTERPRET;
+    Loc loc = e1->loc;
+    Type *t;
+
+    //printf("Cat(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
+
+    if (e1->op == TOKnull && e2->op == TOKint64)
+    {	e = e2;
+	goto L2;
+    }
+    else if (e1->op == TOKint64 && e2->op == TOKnull)
+    {	e = e1;
+     L2:
+	Type *tn = e->type->toBasetype();
+	if (tn->ty == Tchar || tn->ty == Twchar || tn->ty == Tdchar)
+	{
+	    // Create a StringExp
+	    void *s;
+	    StringExp *es;
+	    size_t len = 1;
+	    int sz = tn->size();
+	    integer_t v = e->toInteger();
+
+	    s = mem.malloc((len + 1) * sz);
+	    memcpy((unsigned char *)s, &v, sz);
+
+	    // Add terminating 0
+	    memset((unsigned char *)s + len * sz, 0, sz);
+
+	    es = new StringExp(loc, s, len);
+	    es->sz = sz;
+	    es->committed = 1;
+	    e = es;
+	}
+	else
+	{   // Create an ArrayLiteralExp
+	    Expressions *elements = new Expressions();
+	    elements->push(e);
+	    e = new ArrayLiteralExp(e->loc, elements);
+	}
+	e->type = type;
+	return e;
+    }
+    else if (e1->op == TOKstring && e2->op == TOKstring)
+    {
+	// Concatenate the strings
+	void *s;
+	StringExp *es1 = (StringExp *)e1;
+	StringExp *es2 = (StringExp *)e2;
+	StringExp *es;
+	Type *t;
+	size_t len = es1->len + es2->len;
+	int sz = es1->sz;
+
+	assert(sz == es2->sz);
+	s = mem.malloc((len + 1) * sz);
+	memcpy(s, es1->string, es1->len * sz);
+	memcpy((unsigned char *)s + es1->len * sz, es2->string, es2->len * sz);
+
+	// Add terminating 0
+	memset((unsigned char *)s + len * sz, 0, sz);
+
+	es = new StringExp(loc, s, len);
+	es->sz = sz;
+	es->committed = es1->committed | es2->committed;
+	if (es1->committed)
+	    t = es1->type;
+	else
+	    t = es2->type;
+	es->type = type;
+	e = es;
+    }
+    else if (e1->op == TOKstring && e2->op == TOKint64)
+    {
+	// Concatenate the strings
+	void *s;
+	StringExp *es1 = (StringExp *)e1;
+	StringExp *es;
+	Type *t;
+	size_t len = es1->len + 1;
+	int sz = es1->sz;
+	integer_t v = e2->toInteger();
+
+	s = mem.malloc((len + 1) * sz);
+	memcpy(s, es1->string, es1->len * sz);
+	memcpy((unsigned char *)s + es1->len * sz, &v, sz);
+
+	// Add terminating 0
+	memset((unsigned char *)s + len * sz, 0, sz);
+
+	es = new StringExp(loc, s, len);
+	es->sz = sz;
+	es->committed = es1->committed;
+	t = es1->type;
+	es->type = type;
+	e = es;
+    }
+    else if (e1->op == TOKint64 && e2->op == TOKstring)
+    {
+	// Concatenate the strings
+	void *s;
+	StringExp *es2 = (StringExp *)e2;
+	StringExp *es;
+	Type *t;
+	size_t len = 1 + es2->len;
+	int sz = es2->sz;
+	integer_t v = e1->toInteger();
+
+	s = mem.malloc((len + 1) * sz);
+	memcpy((unsigned char *)s, &v, sz);
+	memcpy((unsigned char *)s + sz, es2->string, es2->len * sz);
+
+	// Add terminating 0
+	memset((unsigned char *)s + len * sz, 0, sz);
+
+	es = new StringExp(loc, s, len);
+	es->sz = sz;
+	es->committed = es2->committed;
+	t = es2->type;
+	es->type = type;
+	e = es;
+    }
+    else if (e1->op == TOKarrayliteral && e2->op == TOKarrayliteral &&
+	e1->type->equals(e2->type))
+    {
+	// Concatenate the arrays
+	ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1;
+	ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
+
+	es1 = new ArrayLiteralExp(es1->loc, (Expressions *)es1->elements->copy());
+	es1->elements->insert(es1->elements->dim, es2->elements);
+	e = es1;
+
+	if (type->toBasetype()->ty == Tsarray)
+	{
+	    e->type = new TypeSArray(e1->type->toBasetype()->next, new IntegerExp(0, es1->elements->dim, Type::tindex));
+	    e->type = e->type->semantic(loc, NULL);
+	}
+	else
+	    e->type = type;
+    }
+    else if (e1->op == TOKarrayliteral &&
+	e1->type->toBasetype()->next->equals(e2->type))
+    {
+	ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1;
+
+	es1 = new ArrayLiteralExp(es1->loc, (Expressions *)es1->elements->copy());
+	es1->elements->push(e2);
+	e = es1;
+
+	if (type->toBasetype()->ty == Tsarray)
+	{
+	    e->type = new TypeSArray(e2->type, new IntegerExp(0, es1->elements->dim, Type::tindex));
+	    e->type = e->type->semantic(loc, NULL);
+	}
+	else
+	    e->type = type;
+    }
+    else if (e2->op == TOKarrayliteral &&
+	e2->type->toBasetype()->next->equals(e1->type))
+    {
+	ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
+
+	es2 = new ArrayLiteralExp(es2->loc, (Expressions *)es2->elements->copy());
+	es2->elements->shift(e1);
+	e = es2;
+
+	if (type->toBasetype()->ty == Tsarray)
+	{
+	    e->type = new TypeSArray(e1->type, new IntegerExp(0, es2->elements->dim, Type::tindex));
+	    e->type = e->type->semantic(loc, NULL);
+	}
+	else
+	    e->type = type;
+    }
+    else if (e1->op == TOKnull && e2->op == TOKstring)
+    {
+	t = e1->type;
+	e = e2;
+	goto L1;
+    }
+    else if (e1->op == TOKstring && e2->op == TOKnull)
+    {	e = e1;
+	t = e2->type;
+      L1:
+	Type *tb = t->toBasetype();
+	if (tb->ty == Tarray && tb->next->equals(e->type))
+	{   Expressions *expressions = new Expressions();
+	    expressions->push(e);
+	    e = new ArrayLiteralExp(loc, expressions);
+	    e->type = t;
+	}
+	if (!e->type->equals(type))
+	{   StringExp *se = (StringExp *)e->copy();
+	    e = se->castTo(NULL, type);
+	}
+    }
+    return e;
+}
+
+Expression *Ptr(Type *type, Expression *e1)
+{
+    //printf("Ptr(e1 = %s)\n", e1->toChars());
+    if (e1->op == TOKadd)
+    {	AddExp *ae = (AddExp *)e1;
+	if (ae->e1->op == TOKaddress && ae->e2->op == TOKint64)
+	{   AddrExp *ade = (AddrExp *)ae->e1;
+	    if (ade->e1->op == TOKstructliteral)
+	    {	StructLiteralExp *se = (StructLiteralExp *)ade->e1;
+		unsigned offset = ae->e2->toInteger();
+		Expression *e = se->getField(type, offset);
+		if (!e)
+		    e = EXP_CANT_INTERPRET;
+		return e;
+	    }
+	}
+    }
+    return EXP_CANT_INTERPRET;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/dchar.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,482 @@
+
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <assert.h>
+
+#include "dchar.h"
+#include "mem.h"
+
+#if M_UNICODE
+
+// Converts a char string to Unicode
+
+dchar *Dchar::dup(char *p)
+{
+    dchar *s;
+    size_t len;
+
+    if (!p)
+	return NULL;
+    len = strlen(p);
+    s = (dchar *)mem.malloc((len + 1) * sizeof(dchar));
+    for (unsigned i = 0; i < len; i++)
+    {
+	s[i] = (dchar)(p[i] & 0xFF);
+    }
+    s[len] = 0;
+    return s;
+}
+
+dchar *Dchar::memchr(dchar *p, int c, int count)
+{
+    int u;
+
+    for (u = 0; u < count; u++)
+    {
+	if (p[u] == c)
+	    return p + u;
+    }
+    return NULL;
+}
+
+#if _WIN32 && __DMC__
+__declspec(naked)
+unsigned Dchar::calcHash(const dchar *str, unsigned len)
+{
+    __asm
+    {
+	mov	ECX,4[ESP]
+	mov	EDX,8[ESP]
+	xor	EAX,EAX
+	test	EDX,EDX
+	je	L92
+
+LC8:	cmp	EDX,1
+	je	L98
+	cmp	EDX,2
+	je	LAE
+
+	add	EAX,[ECX]
+//	imul	EAX,EAX,025h
+	lea	EAX,[EAX][EAX*8]
+	add	ECX,4
+	sub	EDX,2
+	jmp	LC8
+
+L98:	mov	DX,[ECX]
+	and	EDX,0FFFFh
+	add	EAX,EDX
+	ret
+
+LAE:	add	EAX,[ECX]
+L92:	ret
+    }
+}
+#else
+hash_t Dchar::calcHash(const dchar *str, size_t len)
+{
+    unsigned hash = 0;
+
+    for (;;)
+    {
+	switch (len)
+	{
+	    case 0:
+		return hash;
+
+	    case 1:
+		hash += *(const uint16_t *)str;
+		return hash;
+
+	    case 2:
+		hash += *(const uint32_t *)str;
+		return hash;
+
+	    default:
+		hash += *(const uint32_t *)str;
+		hash *= 37;
+		str += 2;
+		len -= 2;
+		break;
+	}
+    }
+}
+#endif
+
+hash_t Dchar::icalcHash(const dchar *str, size_t len)
+{
+    hash_t hash = 0;
+
+    for (;;)
+    {
+	switch (len)
+	{
+	    case 0:
+		return hash;
+
+	    case 1:
+		hash += *(const uint16_t *)str | 0x20;
+		return hash;
+
+	    case 2:
+		hash += *(const uint32_t *)str | 0x200020;
+		return hash;
+
+	    default:
+		hash += *(const uint32_t *)str | 0x200020;
+		hash *= 37;
+		str += 2;
+		len -= 2;
+		break;
+	}
+    }
+}
+
+#elif MCBS
+
+hash_t Dchar::calcHash(const dchar *str, size_t len)
+{
+    hash_t hash = 0;
+
+    while (1)
+    {
+	switch (len)
+	{
+	    case 0:
+		return hash;
+
+	    case 1:
+		hash *= 37;
+		hash += *(const uint8_t *)str;
+		return hash;
+
+	    case 2:
+		hash *= 37;
+		hash += *(const uint16_t *)str;
+		return hash;
+
+	    case 3:
+		hash *= 37;
+		hash += (*(const uint16_t *)str << 8) +
+			((const uint8_t *)str)[2];
+		return hash;
+
+	    default:
+		hash *= 37;
+		hash += *(const uint32_t *)str;
+		str += 4;
+		len -= 4;
+		break;
+	}
+    }
+}
+
+#elif UTF8
+
+// Specification is: http://anubis.dkuug.dk/JTC1/SC2/WG2/docs/n1335
+
+char Dchar::mblen[256] =
+{
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+    2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+    3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
+    4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1,
+};
+
+dchar *Dchar::dec(dchar *pstart, dchar *p)
+{
+    while ((p[-1] & 0xC0) == 0x80)
+	p--;
+    return p;
+}
+
+int Dchar::get(dchar *p)
+{
+    unsigned c;
+    unsigned char *q = (unsigned char *)p;
+
+    c = q[0];
+    switch (mblen[c])
+    {
+	case 2:
+	    c = ((c    - 0xC0) << 6) |
+		 (q[1] - 0x80);
+	    break;
+
+	case 3:
+	    c = ((c    - 0xE0) << 12) |
+		((q[1] - 0x80) <<  6) |
+		 (q[2] - 0x80);
+	    break;
+
+	case 4:
+	    c = ((c    - 0xF0) << 18) |
+		((q[1] - 0x80) << 12) |
+		((q[2] - 0x80) <<  6) |
+		 (q[3] - 0x80);
+	    break;
+
+	case 5:
+	    c = ((c    - 0xF8) << 24) |
+		((q[1] - 0x80) << 18) |
+		((q[2] - 0x80) << 12) |
+		((q[3] - 0x80) <<  6) |
+		 (q[4] - 0x80);
+	    break;
+
+	case 6:
+	    c = ((c    - 0xFC) << 30) |
+		((q[1] - 0x80) << 24) |
+		((q[2] - 0x80) << 18) |
+		((q[3] - 0x80) << 12) |
+		((q[4] - 0x80) <<  6) |
+		 (q[5] - 0x80);
+	    break;
+    }
+    return c;
+}
+
+dchar *Dchar::put(dchar *p, unsigned c)
+{
+    if (c <= 0x7F)
+    {
+	*p++ = c;
+    }
+    else if (c <= 0x7FF)
+    {
+	p[0] = 0xC0 + (c >> 6);
+	p[1] = 0x80 + (c & 0x3F);
+	p += 2;
+    }
+    else if (c <= 0xFFFF)
+    {
+	p[0] = 0xE0 + (c >> 12);
+	p[1] = 0x80 + ((c >> 6) & 0x3F);
+	p[2] = 0x80 + (c & 0x3F);
+	p += 3;
+    }
+    else if (c <= 0x1FFFFF)
+    {
+	p[0] = 0xF0 + (c >> 18);
+	p[1] = 0x80 + ((c >> 12) & 0x3F);
+	p[2] = 0x80 + ((c >> 6) & 0x3F);
+	p[3] = 0x80 + (c & 0x3F);
+	p += 4;
+    }
+    else if (c <= 0x3FFFFFF)
+    {
+	p[0] = 0xF8 + (c >> 24);
+	p[1] = 0x80 + ((c >> 18) & 0x3F);
+	p[2] = 0x80 + ((c >> 12) & 0x3F);
+	p[3] = 0x80 + ((c >> 6) & 0x3F);
+	p[4] = 0x80 + (c & 0x3F);
+	p += 5;
+    }
+    else if (c <= 0x7FFFFFFF)
+    {
+	p[0] = 0xFC + (c >> 30);
+	p[1] = 0x80 + ((c >> 24) & 0x3F);
+	p[2] = 0x80 + ((c >> 18) & 0x3F);
+	p[3] = 0x80 + ((c >> 12) & 0x3F);
+	p[4] = 0x80 + ((c >> 6) & 0x3F);
+	p[5] = 0x80 + (c & 0x3F);
+	p += 6;
+    }
+    else
+	assert(0);		// not a UCS-4 character
+    return p;
+}
+
+hash_t Dchar::calcHash(const dchar *str, size_t len)
+{
+    hash_t hash = 0;
+
+    while (1)
+    {
+	switch (len)
+	{
+	    case 0:
+		return hash;
+
+	    case 1:
+		hash *= 37;
+		hash += *(const uint8_t *)str;
+		return hash;
+
+	    case 2:
+		hash *= 37;
+#if __I86__
+		hash += *(const uint16_t *)str;
+#else
+		hash += str[0] * 256 + str[1];
+#endif
+		return hash;
+
+	    case 3:
+		hash *= 37;
+#if __I86__
+		hash += (*(const uint16_t *)str << 8) +
+			((const uint8_t *)str)[2];
+#else
+		hash += (str[0] * 256 + str[1]) * 256 + str[2];
+#endif
+		return hash;
+
+	    default:
+		hash *= 37;
+#if __I86__
+		hash += *(const uint32_t *)str;
+#else
+		hash += ((str[0] * 256 + str[1]) * 256 + str[2]) * 256 + str[3];
+#endif
+
+		str += 4;
+		len -= 4;
+		break;
+	}
+    }
+}
+
+#else // ascii
+
+hash_t Dchar::calcHash(const dchar *str, size_t len)
+{
+    hash_t hash = 0;
+
+    while (1)
+    {
+	switch (len)
+	{
+	    case 0:
+		return hash;
+
+	    case 1:
+		hash *= 37;
+		hash += *(const uint8_t *)str;
+		return hash;
+
+	    case 2:
+		hash *= 37;
+#if __I86__
+		hash += *(const uint16_t *)str;
+#else
+		hash += str[0] * 256 + str[1];
+#endif
+		return hash;
+
+	    case 3:
+		hash *= 37;
+#if __I86__
+		hash += (*(const uint16_t *)str << 8) +
+			((const uint8_t *)str)[2];
+#else
+		hash += (str[0] * 256 + str[1]) * 256 + str[2];
+#endif
+		return hash;
+
+	    default:
+		hash *= 37;
+#if __I86__
+		hash += *(const uint32_t *)str;
+#else
+		hash += ((str[0] * 256 + str[1]) * 256 + str[2]) * 256 + str[3];
+#endif
+		str += 4;
+		len -= 4;
+		break;
+	}
+    }
+}
+
+hash_t Dchar::icalcHash(const dchar *str, size_t len)
+{
+    hash_t hash = 0;
+
+    while (1)
+    {
+	switch (len)
+	{
+	    case 0:
+		return hash;
+
+	    case 1:
+		hash *= 37;
+		hash += *(const uint8_t *)str | 0x20;
+		return hash;
+
+	    case 2:
+		hash *= 37;
+		hash += *(const uint16_t *)str | 0x2020;
+		return hash;
+
+	    case 3:
+		hash *= 37;
+		hash += ((*(const uint16_t *)str << 8) +
+			 ((const uint8_t *)str)[2]) | 0x202020;
+		return hash;
+
+	    default:
+		hash *= 37;
+		hash += *(const uint32_t *)str | 0x20202020;
+		str += 4;
+		len -= 4;
+		break;
+	}
+    }
+}
+
+#endif
+
+#if 0
+#include <stdio.h>
+
+void main()
+{
+    // Print out values to hardcode into Dchar::mblen[]
+    int c;
+    int s;
+
+    for (c = 0; c < 256; c++)
+    {
+	s = 1;
+	if (c >= 0xC0 && c <= 0xDF)
+	    s = 2;
+	if (c >= 0xE0 && c <= 0xEF)
+	    s = 3;
+	if (c >= 0xF0 && c <= 0xF7)
+	    s = 4;
+	if (c >= 0xF8 && c <= 0xFB)
+	    s = 5;
+	if (c >= 0xFC && c <= 0xFD)
+	    s = 6;
+
+	printf("%d", s);
+	if ((c & 15) == 15)
+	    printf(",\n");
+	else
+	    printf(",");
+    }
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/dchar.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,194 @@
+
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+
+#ifndef DCHAR_H
+#define DCHAR_H
+
+#if __GNUC__ && !_WIN32
+#include "gnuc.h"
+#endif
+
+#if _MSC_VER
+    // Disable useless warnings about unreferenced functions
+    #pragma warning (disable : 4514)
+#endif
+
+//#include "root.h"
+typedef size_t hash_t;
+
+#undef TEXT
+
+// NOTE: All functions accepting pointer arguments must not be NULL
+
+#if M_UNICODE
+
+#include <string.h>
+#include <wchar.h>
+
+typedef wchar_t dchar;
+#define TEXT(x)		L##x
+
+#define Dchar_mbmax	1
+
+struct Dchar
+{
+    static dchar *inc(dchar *p) { return p + 1; }
+    static dchar *dec(dchar *pstart, dchar *p) { (void)pstart; return p - 1; }
+    static int len(const dchar *p) { return wcslen(p); }
+    static dchar get(dchar *p) { return *p; }
+    static dchar getprev(dchar *pstart, dchar *p) { (void)pstart; return p[-1]; }
+    static dchar *put(dchar *p, dchar c) { *p = c; return p + 1; }
+    static int cmp(dchar *s1, dchar *s2)
+    {
+#if __DMC__
+	if (!*s1 && !*s2)	// wcscmp is broken
+	    return 0;
+#endif
+	return wcscmp(s1, s2);
+#if 0
+	return (*s1 == *s2)
+	    ? wcscmp(s1, s2)
+	    : ((int)*s1 - (int)*s2);
+#endif
+    }
+    static int memcmp(const dchar *s1, const dchar *s2, int nchars) { return ::memcmp(s1, s2, nchars * sizeof(dchar)); }
+    static int isDigit(dchar c) { return '0' <= c && c <= '9'; }
+    static int isAlpha(dchar c) { return iswalpha(c); }
+    static int isUpper(dchar c) { return iswupper(c); }
+    static int isLower(dchar c) { return iswlower(c); }
+    static int isLocaleUpper(dchar c) { return isUpper(c); }
+    static int isLocaleLower(dchar c) { return isLower(c); }
+    static int toLower(dchar c) { return isUpper(c) ? towlower(c) : c; }
+    static int toLower(dchar *p) { return toLower(*p); }
+    static int toUpper(dchar c) { return isLower(c) ? towupper(c) : c; }
+    static dchar *dup(dchar *p) { return ::_wcsdup(p); }	// BUG: out of memory?
+    static dchar *dup(char *p);
+    static dchar *chr(dchar *p, unsigned c) { return wcschr(p, (dchar)c); }
+    static dchar *rchr(dchar *p, unsigned c) { return wcsrchr(p, (dchar)c); }
+    static dchar *memchr(dchar *p, int c, int count);
+    static dchar *cpy(dchar *s1, dchar *s2) { return wcscpy(s1, s2); }
+    static dchar *str(dchar *s1, dchar *s2) { return wcsstr(s1, s2); }
+    static hash_t calcHash(const dchar *str, size_t len);
+
+    // Case insensitive versions
+    static int icmp(dchar *s1, dchar *s2) { return wcsicmp(s1, s2); }
+    static int memicmp(const dchar *s1, const dchar *s2, int nchars) { return ::wcsnicmp(s1, s2, nchars); }
+    static hash_t icalcHash(const dchar *str, size_t len);
+};
+
+#elif MCBS
+
+#include <limits.h>
+#include <mbstring.h>
+
+typedef char dchar;
+#define TEXT(x)		x
+
+#define Dchar_mbmax	MB_LEN_MAX
+
+#elif UTF8
+
+typedef char dchar;
+#define TEXT(x)		x
+
+#define Dchar_mbmax	6
+
+struct Dchar
+{
+    static char mblen[256];
+
+    static dchar *inc(dchar *p) { return p + mblen[*p & 0xFF]; }
+    static dchar *dec(dchar *pstart, dchar *p);
+    static int len(const dchar *p) { return strlen(p); }
+    static int get(dchar *p);
+    static int getprev(dchar *pstart, dchar *p)
+	{ return *dec(pstart, p) & 0xFF; }
+    static dchar *put(dchar *p, unsigned c);
+    static int cmp(dchar *s1, dchar *s2) { return strcmp(s1, s2); }
+    static int memcmp(const dchar *s1, const dchar *s2, int nchars) { return ::memcmp(s1, s2, nchars); }
+    static int isDigit(dchar c) { return '0' <= c && c <= '9'; }
+    static int isAlpha(dchar c) { return c <= 0x7F ? isalpha(c) : 0; }
+    static int isUpper(dchar c) { return c <= 0x7F ? isupper(c) : 0; }
+    static int isLower(dchar c) { return c <= 0x7F ? islower(c) : 0; }
+    static int isLocaleUpper(dchar c) { return isUpper(c); }
+    static int isLocaleLower(dchar c) { return isLower(c); }
+    static int toLower(dchar c) { return isUpper(c) ? tolower(c) : c; }
+    static int toLower(dchar *p) { return toLower(*p); }
+    static int toUpper(dchar c) { return isLower(c) ? toupper(c) : c; }
+    static dchar *dup(dchar *p) { return ::strdup(p); }	// BUG: out of memory?
+    static dchar *chr(dchar *p, int c) { return strchr(p, c); }
+    static dchar *rchr(dchar *p, int c) { return strrchr(p, c); }
+    static dchar *memchr(dchar *p, int c, int count)
+	{ return (dchar *)::memchr(p, c, count); }
+    static dchar *cpy(dchar *s1, dchar *s2) { return strcpy(s1, s2); }
+    static dchar *str(dchar *s1, dchar *s2) { return strstr(s1, s2); }
+    static hash_t calcHash(const dchar *str, size_t len);
+
+    // Case insensitive versions
+    static int icmp(dchar *s1, dchar *s2) { return _mbsicmp(s1, s2); }
+    static int memicmp(const dchar *s1, const dchar *s2, int nchars) { return ::_mbsnicmp(s1, s2, nchars); }
+};
+
+#else
+
+#include <string.h>
+
+#ifndef GCC_SAFE_DMD
+#include <ctype.h>
+#endif
+
+typedef char dchar;
+#define TEXT(x)		x
+
+#define Dchar_mbmax	1
+
+struct Dchar
+{
+    static dchar *inc(dchar *p) { return p + 1; }
+    static dchar *dec(dchar *pstart, dchar *p) { return p - 1; }
+    static int len(const dchar *p) { return strlen(p); }
+    static int get(dchar *p) { return *p & 0xFF; }
+    static int getprev(dchar *pstart, dchar *p) { return p[-1] & 0xFF; }
+    static dchar *put(dchar *p, unsigned c) { *p = c; return p + 1; }
+    static int cmp(dchar *s1, dchar *s2) { return strcmp(s1, s2); }
+    static int memcmp(const dchar *s1, const dchar *s2, int nchars) { return ::memcmp(s1, s2, nchars); }
+    static int isDigit(dchar c) { return '0' <= c && c <= '9'; }
+#ifndef GCC_SAFE_DMD
+    static int isAlpha(dchar c) { return isalpha(c); }
+    static int isUpper(dchar c) { return isupper(c); }
+    static int isLower(dchar c) { return islower(c); }
+    static int isLocaleUpper(dchar c) { return isupper(c); }
+    static int isLocaleLower(dchar c) { return islower(c); }
+    static int toLower(dchar c) { return isupper(c) ? tolower(c) : c; }
+    static int toLower(dchar *p) { return toLower(*p); }
+    static int toUpper(dchar c) { return islower(c) ? toupper(c) : c; }
+    static dchar *dup(dchar *p) { return ::strdup(p); }	// BUG: out of memory?
+#endif
+    static dchar *chr(dchar *p, int c) { return strchr(p, c); }
+    static dchar *rchr(dchar *p, int c) { return strrchr(p, c); }
+    static dchar *memchr(dchar *p, int c, int count)
+	{ return (dchar *)::memchr(p, c, count); }
+    static dchar *cpy(dchar *s1, dchar *s2) { return strcpy(s1, s2); }
+    static dchar *str(dchar *s1, dchar *s2) { return strstr(s1, s2); }
+    static hash_t calcHash(const dchar *str, size_t len);
+
+    // Case insensitive versions
+#ifdef __GNUC__
+    static int icmp(dchar *s1, dchar *s2) { return strcasecmp(s1, s2); }
+#else
+    static int icmp(dchar *s1, dchar *s2) { return stricmp(s1, s2); }
+#endif
+    static int memicmp(const dchar *s1, const dchar *s2, int nchars) { return ::memicmp(s1, s2, nchars); }
+    static hash_t icalcHash(const dchar *str, size_t len);
+};
+
+#endif
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/declaration.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,1260 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "init.h"
+#include "declaration.h"
+#include "attrib.h"
+#include "mtype.h"
+#include "template.h"
+#include "scope.h"
+#include "aggregate.h"
+#include "module.h"
+#include "id.h"
+#include "expression.h"
+#include "hdrgen.h"
+
+/********************************* Declaration ****************************/
+
+Declaration::Declaration(Identifier *id)
+    : Dsymbol(id)
+{
+    type = NULL;
+    storage_class = STCundefined;
+    protection = PROTundefined;
+    linkage = LINKdefault;
+}
+
+void Declaration::semantic(Scope *sc)
+{
+}
+
+char *Declaration::kind()
+{
+    return "declaration";
+}
+
+unsigned Declaration::size(Loc loc)
+{
+    assert(type);
+    return type->size();
+}
+
+int Declaration::isStaticConstructor()
+{
+    return FALSE;
+}
+
+int Declaration::isStaticDestructor()
+{
+    return FALSE;
+}
+
+int Declaration::isDelete()
+{
+    return FALSE;
+}
+
+int Declaration::isDataseg()
+{
+    return FALSE;
+}
+
+int Declaration::isCodeseg()
+{
+    return FALSE;
+}
+
+enum PROT Declaration::prot()
+{
+    return protection;
+}
+
+/********************************* TupleDeclaration ****************************/
+
+TupleDeclaration::TupleDeclaration(Loc loc, Identifier *id, Objects *objects)
+    : Declaration(id)
+{
+    this->type = NULL;
+    this->objects = objects;
+    this->isexp = 0;
+    this->tupletype = NULL;
+}
+
+Dsymbol *TupleDeclaration::syntaxCopy(Dsymbol *s)
+{
+    assert(0);
+    return NULL;
+}
+
+char *TupleDeclaration::kind()
+{
+    return "tuple";
+}
+
+Type *TupleDeclaration::getType()
+{
+    /* If this tuple represents a type, return that type
+     */
+
+    //printf("TupleDeclaration::getType() %s\n", toChars());
+    if (isexp)
+	return NULL;
+    if (!tupletype)
+    {
+	/* It's only a type tuple if all the Object's are types
+	 */
+	for (size_t i = 0; i < objects->dim; i++)
+	{   Object *o = (Object *)objects->data[i];
+
+	    if (o->dyncast() != DYNCAST_TYPE)
+	    {
+		//printf("\tnot[%d], %p, %d\n", i, o, o->dyncast());
+		return NULL;
+	    }
+	}
+
+	/* We know it's a type tuple, so build the TypeTuple
+	 */
+	Arguments *args = new Arguments();
+	args->setDim(objects->dim);
+	OutBuffer buf;
+	for (size_t i = 0; i < objects->dim; i++)
+	{   Type *t = (Type *)objects->data[i];
+
+	    //printf("type = %s\n", t->toChars());
+#if 0
+	    buf.printf("_%s_%d", ident->toChars(), i);
+	    char *name = (char *)buf.extractData();
+	    Identifier *id = new Identifier(name, TOKidentifier);
+	    Argument *arg = new Argument(STCin, t, id, NULL);
+#else
+	    Argument *arg = new Argument(STCin, t, NULL, NULL);
+#endif
+	    args->data[i] = (void *)arg;
+	}
+
+	tupletype = new TypeTuple(args);
+    }
+
+    return tupletype;
+}
+
+int TupleDeclaration::needThis()
+{
+    //printf("TupleDeclaration::needThis(%s)\n", toChars());
+    for (size_t i = 0; i < objects->dim; i++)
+    {   Object *o = (Object *)objects->data[i];
+	if (o->dyncast() == DYNCAST_EXPRESSION)
+	{   Expression *e = (Expression *)o;
+	    if (e->op == TOKdsymbol)
+	    {	DsymbolExp *ve = (DsymbolExp *)e;
+		Declaration *d = ve->s->isDeclaration();
+		if (d && d->needThis())
+		{
+		    return 1;
+		}
+	    }
+	}
+    }
+    return 0;
+}
+
+/********************************* TypedefDeclaration ****************************/
+
+TypedefDeclaration::TypedefDeclaration(Loc loc, Identifier *id, Type *basetype, Initializer *init)
+    : Declaration(id)
+{
+    this->type = new TypeTypedef(this);
+    this->basetype = basetype->toBasetype();
+    this->init = init;
+#ifdef _DH
+    this->htype = NULL;
+    this->hbasetype = NULL;
+#endif
+    this->sem = 0;
+    this->inuse = 0;
+    this->loc = loc;
+    this->sinit = NULL;
+}
+
+Dsymbol *TypedefDeclaration::syntaxCopy(Dsymbol *s)
+{
+    Type *basetype = this->basetype->syntaxCopy();
+
+    Initializer *init = NULL;
+    if (this->init)
+	init = this->init->syntaxCopy();
+
+    assert(!s);
+    TypedefDeclaration *st;
+    st = new TypedefDeclaration(loc, ident, basetype, init);
+#ifdef _DH
+    // Syntax copy for header file
+    if (!htype)      // Don't overwrite original
+    {	if (type)    // Make copy for both old and new instances
+	{   htype = type->syntaxCopy();
+	    st->htype = type->syntaxCopy();
+	}
+    }
+    else            // Make copy of original for new instance
+        st->htype = htype->syntaxCopy();
+    if (!hbasetype)
+    {	if (basetype)
+	{   hbasetype = basetype->syntaxCopy();
+	    st->hbasetype = basetype->syntaxCopy();
+	}
+    }
+    else
+        st->hbasetype = hbasetype->syntaxCopy();
+#endif
+    return st;
+}
+
+void TypedefDeclaration::semantic(Scope *sc)
+{
+    //printf("TypedefDeclaration::semantic(%s) sem = %d\n", toChars(), sem);
+    if (sem == 0)
+    {	sem = 1;
+	basetype = basetype->semantic(loc, sc);
+	sem = 2;
+	type = type->semantic(loc, sc);
+	if (sc->parent->isFuncDeclaration() && init)
+	    semantic2(sc);
+    }
+    else if (sem == 1)
+    {
+	error("circular definition");
+    }
+}
+
+void TypedefDeclaration::semantic2(Scope *sc)
+{
+    //printf("TypedefDeclaration::semantic2(%s) sem = %d\n", toChars(), sem);
+    if (sem == 2)
+    {	sem = 3;
+	if (init)
+	{
+	    init = init->semantic(sc, basetype);
+
+	    ExpInitializer *ie = init->isExpInitializer();
+	    if (ie)
+	    {
+		if (ie->exp->type == basetype)
+		    ie->exp->type = type;
+	    }
+	}
+    }
+}
+
+char *TypedefDeclaration::kind()
+{
+    return "typedef";
+}
+
+Type *TypedefDeclaration::getType()
+{
+    return type;
+}
+
+void TypedefDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("typedef ");
+    basetype->toCBuffer(buf, ident, hgs);
+    if (init)
+    {
+	buf->writestring(" = ");
+	init->toCBuffer(buf, hgs);
+    }
+    buf->writeByte(';');
+    buf->writenl();
+}
+
+/********************************* AliasDeclaration ****************************/
+
+AliasDeclaration::AliasDeclaration(Loc loc, Identifier *id, Type *type)
+    : Declaration(id)
+{
+    //printf("AliasDeclaration(id = '%s', type = %p)\n", id->toChars(), type);
+    //printf("type = '%s'\n", type->toChars());
+    this->loc = loc;
+    this->type = type;
+    this->aliassym = NULL;
+#ifdef _DH
+    this->htype = NULL;
+    this->haliassym = NULL;
+#endif
+    this->overnext = NULL;
+    this->inSemantic = 0;
+    assert(type);
+}
+
+AliasDeclaration::AliasDeclaration(Loc loc, Identifier *id, Dsymbol *s)
+    : Declaration(id)
+{
+    //printf("AliasDeclaration(id = '%s', s = %p)\n", id->toChars(), s);
+    assert(s != this);
+    this->loc = loc;
+    this->type = NULL;
+    this->aliassym = s;
+#ifdef _DH
+    this->htype = NULL;
+    this->haliassym = NULL;
+#endif
+    this->overnext = NULL;
+    this->inSemantic = 0;
+    assert(s);
+}
+
+Dsymbol *AliasDeclaration::syntaxCopy(Dsymbol *s)
+{
+    assert(!s);
+    AliasDeclaration *sa;
+    if (type)
+	sa = new AliasDeclaration(loc, ident, type->syntaxCopy());
+    else
+	sa = new AliasDeclaration(loc, ident, aliassym->syntaxCopy(NULL));
+#ifdef _DH
+    // Syntax copy for header file
+    if (!htype)	    // Don't overwrite original
+    {	if (type)	// Make copy for both old and new instances
+	{   htype = type->syntaxCopy();
+	    sa->htype = type->syntaxCopy();
+	}
+    }
+    else			// Make copy of original for new instance
+	sa->htype = htype->syntaxCopy();
+    if (!haliassym)
+    {	if (aliassym)
+	{   haliassym = aliassym->syntaxCopy(s);
+	    sa->haliassym = aliassym->syntaxCopy(s);
+	}
+    }
+    else
+	sa->haliassym = haliassym->syntaxCopy(s);
+#endif
+    return sa;
+}
+
+void AliasDeclaration::semantic(Scope *sc)
+{
+    //printf("AliasDeclaration::semantic() %s\n", toChars());
+    if (aliassym)
+    {
+	if (aliassym->isTemplateInstance())
+	    aliassym->semantic(sc);
+	return;
+    }
+    this->inSemantic = 1;
+
+    if (storage_class & STCconst)
+	error("cannot be const");
+
+    storage_class |= sc->stc & STCdeprecated;
+
+    // Given:
+    //	alias foo.bar.abc def;
+    // it is not knowable from the syntax whether this is an alias
+    // for a type or an alias for a symbol. It is up to the semantic()
+    // pass to distinguish.
+    // If it is a type, then type is set and getType() will return that
+    // type. If it is a symbol, then aliassym is set and type is NULL -
+    // toAlias() will return aliasssym.
+
+    Dsymbol *s;
+    Type *t;
+    Expression *e;
+
+    /* This section is needed because resolve() will:
+     *   const x = 3;
+     *   alias x y;
+     * try to alias y to 3.
+     */
+    s = type->toDsymbol(sc);
+    if (s)
+	goto L2;			// it's a symbolic alias
+
+    //printf("alias type is %s\n", type->toChars());
+    type->resolve(loc, sc, &e, &t, &s);
+    if (s)
+    {
+	goto L2;
+    }
+    else if (e)
+    {
+	// Try to convert Expression to Dsymbol
+        if (e->op == TOKvar)
+	{   s = ((VarExp *)e)->var;
+	    goto L2;
+	}
+        else if (e->op == TOKfunction)
+	{   s = ((FuncExp *)e)->fd;
+	    goto L2;
+	}
+        else
+	{   error("cannot alias an expression %s", e->toChars());
+	    t = e->type;
+	}
+    }
+    else if (t)
+	type = t;
+    if (overnext)
+	ScopeDsymbol::multiplyDefined(0, this, overnext);
+    this->inSemantic = 0;
+    return;
+
+  L2:
+    //printf("alias is a symbol %s %s\n", s->kind(), s->toChars());
+    type = NULL;
+    VarDeclaration *v = s->isVarDeclaration();
+    if (v && v->linkage == LINKdefault)
+    {
+	error("forward reference of %s", v->toChars());
+	s = NULL;
+    }
+    else
+    {
+	FuncDeclaration *f = s->toAlias()->isFuncDeclaration();
+	if (f)
+	{
+	    if (overnext)
+	    {
+		FuncAliasDeclaration *fa = new FuncAliasDeclaration(f);
+		if (!fa->overloadInsert(overnext))
+		    ScopeDsymbol::multiplyDefined(0, f, overnext);
+		overnext = NULL;
+		s = fa;
+		s->parent = sc->parent;
+	    }
+	}
+	if (overnext)
+	    ScopeDsymbol::multiplyDefined(0, s, overnext);
+	if (s == this)
+	{
+	    assert(global.errors);
+	    s = NULL;
+	}
+    }
+    aliassym = s;
+    this->inSemantic = 0;
+}
+
+int AliasDeclaration::overloadInsert(Dsymbol *s)
+{
+    /* Don't know yet what the aliased symbol is, so assume it can
+     * be overloaded and check later for correctness.
+     */
+
+    //printf("AliasDeclaration::overloadInsert('%s')\n", s->toChars());
+    if (overnext == NULL)
+    {	overnext = s;
+	return TRUE;
+    }
+    else
+    {
+	return overnext->overloadInsert(s);
+    }
+}
+
+char *AliasDeclaration::kind()
+{
+    return "alias";
+}
+
+Type *AliasDeclaration::getType()
+{
+    return type;
+}
+
+Dsymbol *AliasDeclaration::toAlias()
+{
+    //printf("AliasDeclaration::toAlias('%s', this = %p, aliassym = %p, kind = '%s')\n", toChars(), this, aliassym, aliassym ? aliassym->kind() : "");
+    assert(this != aliassym);
+    //static int count; if (++count == 10) *(char*)0=0;
+    if (inSemantic)
+    {	error("recursive alias declaration");
+//	return this;
+    }
+    Dsymbol *s = aliassym ? aliassym->toAlias() : this;
+    return s;
+}
+
+void AliasDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("alias ");
+#if 0 && _DH
+    if (hgs->hdrgen)
+    {
+	if (haliassym)
+	{
+	    haliassym->toCBuffer(buf, hgs);
+	    buf->writeByte(' ');
+	    buf->writestring(ident->toChars());
+	}
+	else
+	    htype->toCBuffer(buf, ident, hgs);
+    }
+    else
+#endif
+    {
+	if (aliassym)
+	{
+	    aliassym->toCBuffer(buf, hgs);
+	    buf->writeByte(' ');
+	    buf->writestring(ident->toChars());
+	}
+	else
+	    type->toCBuffer(buf, ident, hgs);
+    }
+    buf->writeByte(';');
+    buf->writenl();
+}
+
+/********************************* VarDeclaration ****************************/
+
+VarDeclaration::VarDeclaration(Loc loc, Type *type, Identifier *id, Initializer *init)
+    : Declaration(id)
+{
+    //printf("VarDeclaration('%s')\n", id->toChars());
+#ifdef DEBUG
+    if (!type && !init)
+    {	printf("VarDeclaration('%s')\n", id->toChars());
+	//*(char*)0=0;
+    }
+#endif
+    assert(type || init);
+    this->type = type;
+    this->init = init;
+#ifdef _DH
+    this->htype = NULL;
+    this->hinit = NULL;
+#endif
+    this->loc = loc;
+    offset = 0;
+    noauto = 0;
+    nestedref = 0;
+    inuse = 0;
+    ctorinit = 0;
+    aliassym = NULL;
+    onstack = 0;
+    canassign = 0;
+    value = NULL;
+}
+
+Dsymbol *VarDeclaration::syntaxCopy(Dsymbol *s)
+{
+    //printf("VarDeclaration::syntaxCopy(%s)\n", toChars());
+
+    VarDeclaration *sv;
+    if (s)
+    {	sv = (VarDeclaration *)s;
+    }
+    else
+    {
+	Initializer *init = NULL;
+	if (this->init)
+	{   init = this->init->syntaxCopy();
+	    //init->isExpInitializer()->exp->print();
+	    //init->isExpInitializer()->exp->dump(0);
+	}
+
+	sv = new VarDeclaration(loc, type ? type->syntaxCopy() : NULL, ident, init);
+	sv->storage_class = storage_class;
+    }
+#ifdef _DH
+    // Syntax copy for header file
+    if (!htype)      // Don't overwrite original
+    {	if (type)    // Make copy for both old and new instances
+	{   htype = type->syntaxCopy();
+	    sv->htype = type->syntaxCopy();
+	}
+    }
+    else            // Make copy of original for new instance
+        sv->htype = htype->syntaxCopy();
+    if (!hinit)
+    {	if (init)
+	{   hinit = init->syntaxCopy();
+	    sv->hinit = init->syntaxCopy();
+	}
+    }
+    else
+        sv->hinit = hinit->syntaxCopy();
+#endif
+    return sv;
+}
+
+void VarDeclaration::semantic(Scope *sc)
+{
+    //printf("VarDeclaration::semantic('%s', parent = '%s')\n", toChars(), sc->parent->toChars());
+    //printf("type = %s\n", type->toChars());
+    //printf("linkage = %d\n", sc->linkage);
+    //if (strcmp(toChars(), "mul") == 0) halt();
+
+    storage_class |= sc->stc;
+    if (storage_class & STCextern && init)
+	error("extern symbols cannot have initializers");
+
+    /* If auto type inference, do the inference
+     */
+    int inferred = 0;
+    if (!type)
+    {	inuse++;
+	type = init->inferType(sc);
+	inuse--;
+	inferred = 1;
+
+	/* This is a kludge to support the existing syntax for RAII
+	 * declarations.
+	 */
+	storage_class &= ~STCauto;
+    }
+    else
+	type = type->semantic(loc, sc);
+
+    type->checkDeprecated(loc, sc);
+    linkage = sc->linkage;
+    this->parent = sc->parent;
+    //printf("this = %p, parent = %p, '%s'\n", this, parent, parent->toChars());
+    protection = sc->protection;
+    //printf("sc->stc = %x\n", sc->stc);
+    //printf("storage_class = %x\n", storage_class);
+
+    Dsymbol *parent = toParent();
+    FuncDeclaration *fd = parent->isFuncDeclaration();
+
+    Type *tb = type->toBasetype();
+    if (tb->ty == Tvoid && !(storage_class & STClazy))
+    {	error("voids have no value");
+	type = Type::terror;
+	tb = type;
+    }
+    if (tb->ty == Tfunction)
+    {	error("cannot be declared to be a function");
+	type = Type::terror;
+	tb = type;
+    }
+    if (tb->ty == Tstruct)
+    {	TypeStruct *ts = (TypeStruct *)tb;
+
+	if (!ts->sym->members)
+	{
+	    error("no definition of struct %s", ts->toChars());
+	}
+    }
+
+    if (tb->ty == Ttuple)
+    {   /* Instead, declare variables for each of the tuple elements
+	 * and add those.
+	 */
+	TypeTuple *tt = (TypeTuple *)tb;
+	size_t nelems = Argument::dim(tt->arguments);
+	Objects *exps = new Objects();
+	exps->setDim(nelems);
+
+	for (size_t i = 0; i < nelems; i++)
+	{   Argument *arg = Argument::getNth(tt->arguments, i);
+
+	    OutBuffer buf;
+	    buf.printf("_%s_field_%zu", ident->toChars(), i);
+	    buf.writeByte(0);
+	    char *name = (char *)buf.extractData();
+	    Identifier *id = new Identifier(name, TOKidentifier);
+
+	    VarDeclaration *v = new VarDeclaration(loc, arg->type, id, NULL);
+	    //printf("declaring field %s of type %s\n", v->toChars(), v->type->toChars());
+	    v->semantic(sc);
+
+	    if (sc->scopesym)
+	    {	//printf("adding %s to %s\n", v->toChars(), sc->scopesym->toChars());
+		if (sc->scopesym->members)
+		    sc->scopesym->members->push(v);
+	    }
+
+	    Expression *e = new DsymbolExp(loc, v);
+	    exps->data[i] = e;
+	}
+	TupleDeclaration *v2 = new TupleDeclaration(loc, ident, exps);
+	v2->isexp = 1;
+	aliassym = v2;
+	return;
+    }
+
+    if (storage_class & STCconst && !init && !fd)
+	// Initialize by constructor only
+	storage_class = (storage_class & ~STCconst) | STCctorinit;
+
+    if (isConst())
+    {
+    }
+    else if (isStatic())
+    {
+    }
+    else if (isSynchronized())
+    {
+	error("variable %s cannot be synchronized", toChars());
+    }
+    else if (isOverride())
+    {
+	error("override cannot be applied to variable");
+    }
+    else if (isAbstract())
+    {
+	error("abstract cannot be applied to variable");
+    }
+    else if (storage_class & STCtemplateparameter)
+    {
+    }
+    else
+    {
+	AggregateDeclaration *aad = sc->anonAgg;
+	if (!aad)
+	    aad = parent->isAggregateDeclaration();
+	if (aad)
+	{
+	    aad->addField(sc, this);
+	}
+
+	InterfaceDeclaration *id = parent->isInterfaceDeclaration();
+	if (id)
+	{
+	    error("field not allowed in interface");
+	}
+
+	TemplateInstance *ti = parent->isTemplateInstance();
+	if (ti)
+	{
+	    // Take care of nested templates
+	    while (1)
+	    {
+		TemplateInstance *ti2 = ti->tempdecl->parent->isTemplateInstance();
+		if (!ti2)
+		    break;
+		ti = ti2;
+	    }
+
+	    // If it's a member template
+	    AggregateDeclaration *ad = ti->tempdecl->isMember();
+	    if (ad && storage_class != STCundefined)
+	    {
+		error("cannot use template to add field to aggregate '%s'", ad->toChars());
+	    }
+	}
+    }
+
+    if (type->isauto() && !noauto)
+    {
+	if (storage_class & (STCfield | STCout | STCref | STCstatic) || !fd)
+	{
+	    error("globals, statics, fields, ref and out parameters cannot be auto");
+	}
+
+	if (!(storage_class & (STCauto | STCscope)))
+	{
+	    if (!(storage_class & STCparameter) && ident != Id::withSym)
+		error("reference to scope class must be scope");
+	}
+    }
+
+    if (!init && !sc->inunion && !isStatic() && !isConst() && fd &&
+	!(storage_class & (STCfield | STCin | STCforeach)))
+    {
+	// Provide a default initializer
+	//printf("Providing default initializer for '%s'\n", toChars());
+	if (type->ty == Tstruct &&
+	    ((TypeStruct *)type)->sym->zeroInit == 1)
+	{
+	    Expression *e = new IntegerExp(loc, 0, Type::tint32);
+	    Expression *e1;
+	    e1 = new VarExp(loc, this);
+	    e = new AssignExp(loc, e1, e);
+	    e->type = e1->type;
+	    init = new ExpInitializer(loc, e/*->type->defaultInit()*/);
+	    return;
+	}
+	else if (type->ty == Ttypedef)
+	{   TypeTypedef *td = (TypeTypedef *)type;
+	    if (td->sym->init)
+	    {	init = td->sym->init;
+		ExpInitializer *ie = init->isExpInitializer();
+		if (ie)
+		    // Make copy so we can modify it
+		    init = new ExpInitializer(ie->loc, ie->exp);
+	    }
+	    else
+		init = getExpInitializer();
+	}
+	else
+	{
+	    init = getExpInitializer();
+	}
+    }
+
+    if (init)
+    {
+	ArrayInitializer *ai = init->isArrayInitializer();
+	if (ai && type->toBasetype()->ty == Taarray)
+	{
+	    init = ai->toAssocArrayInitializer();
+	}
+
+	ExpInitializer *ei = init->isExpInitializer();
+
+	// See if we can allocate on the stack
+	if (ei && isScope() && ei->exp->op == TOKnew)
+	{   NewExp *ne = (NewExp *)ei->exp;
+	    if (!(ne->newargs && ne->newargs->dim))
+	    {	ne->onstack = 1;
+		onstack = 1;
+		if (type->isBaseOf(ne->newtype->semantic(loc, sc), NULL))
+		    onstack = 2;
+	    }
+	}
+
+	// If inside function, there is no semantic3() call
+	if (sc->func)
+	{
+	    // If local variable, use AssignExp to handle all the various
+	    // possibilities.
+	    if (fd && !isStatic() && !isConst() && !init->isVoidInitializer())
+	    {
+		Expression *e1;
+		Type *t;
+		int dim;
+
+		//printf("fd = '%s', var = '%s'\n", fd->toChars(), toChars());
+		if (!ei)
+		{
+		    Expression *e = init->toExpression();
+		    if (!e)
+		    {
+			init = init->semantic(sc, type);
+			e = init->toExpression();
+			if (!e)
+			{   error("is not a static and cannot have static initializer");
+			    return;
+			}
+		    }
+		    ei = new ExpInitializer(init->loc, e);
+		    init = ei;
+		}
+
+		e1 = new VarExp(loc, this);
+
+		t = type->toBasetype();
+		if (t->ty == Tsarray)
+		{
+		    dim = ((TypeSArray *)t)->dim->toInteger();
+		    // If multidimensional static array, treat as one large array
+		    while (1)
+		    {
+			t = t->next->toBasetype();
+			if (t->ty != Tsarray)
+			    break;
+			if (t->next->toBasetype()->ty == Tbit)
+			    // t->size() gives size in bytes, convert to bits
+			    dim *= t->size() * 8;
+			else
+			    dim *= ((TypeSArray *)t)->dim->toInteger();
+			e1->type = new TypeSArray(t->next, new IntegerExp(0, dim, Type::tindex));
+		    }
+		    e1 = new SliceExp(loc, e1, NULL, NULL);
+		}
+		else if (t->ty == Tstruct)
+		{
+		    ei->exp = ei->exp->semantic(sc);
+		    if (!ei->exp->implicitConvTo(type))
+			ei->exp = new CastExp(loc, ei->exp, type);
+		}
+		ei->exp = new AssignExp(loc, e1, ei->exp);
+		ei->exp->op = TOKconstruct;
+		canassign++;
+		ei->exp = ei->exp->semantic(sc);
+		canassign--;
+		ei->exp->optimize(WANTvalue);
+	    }
+	    else
+	    {
+		init = init->semantic(sc, type);
+		if (fd && isConst() && !isStatic())
+		{   // Make it static
+		    storage_class |= STCstatic;
+		}
+	    }
+	}
+	else if (isConst() || isFinal())
+	{
+	    /* Because we may need the results of a const declaration in a
+	     * subsequent type, such as an array dimension, before semantic2()
+	     * gets ordinarily run, try to run semantic2() now.
+	     * Ignore failure.
+	     */
+
+	    if (ei && !global.errors && !inferred)
+	    {
+		unsigned errors = global.errors;
+		global.gag++;
+		//printf("+gag\n");
+		Expression *e = ei->exp->syntaxCopy();
+		inuse++;
+		e = e->semantic(sc);
+		inuse--;
+		e = e->implicitCastTo(sc, type);
+		global.gag--;
+		//printf("-gag\n");
+		if (errors != global.errors)	// if errors happened
+		{
+		    if (global.gag == 0)
+			global.errors = errors;	// act as if nothing happened
+		}
+		else
+		{
+		    e = e->optimize(WANTvalue | WANTinterpret);
+		    if (e->op == TOKint64 || e->op == TOKstring)
+		    {
+			ei->exp = e;		// no errors, keep result
+		    }
+		}
+	    }
+	}
+    }
+}
+
+ExpInitializer *VarDeclaration::getExpInitializer()
+{
+    ExpInitializer *ei;
+
+    if (init)
+	ei = init->isExpInitializer();
+    else
+    {
+	Expression *e = type->defaultInit();
+	if (e)
+	    ei = new ExpInitializer(loc, e);
+	else
+	    ei = NULL;
+    }
+    return ei;
+}
+
+void VarDeclaration::semantic2(Scope *sc)
+{
+    //printf("VarDeclaration::semantic2('%s')\n", toChars());
+    if (init && !toParent()->isFuncDeclaration())
+    {	inuse++;
+#if 0
+	ExpInitializer *ei = init->isExpInitializer();
+	if (ei)
+	{
+	    ei->exp->dump(0);
+	    printf("type = %p\n", ei->exp->type);
+	}
+#endif
+	init = init->semantic(sc, type);
+	inuse--;
+    }
+}
+
+char *VarDeclaration::kind()
+{
+    return "variable";
+}
+
+Dsymbol *VarDeclaration::toAlias()
+{
+    //printf("VarDeclaration::toAlias('%s', this = %p, aliassym = %p)\n", toChars(), this, aliassym);
+    assert(this != aliassym);
+    Dsymbol *s = aliassym ? aliassym->toAlias() : this;
+    return s;
+}
+
+void VarDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    if (storage_class & STCconst)
+	buf->writestring("const ");
+    if (storage_class & STCstatic)
+	buf->writestring("static ");
+    if (type)
+	type->toCBuffer(buf, ident, hgs);
+    else
+	buf->writestring(ident->toChars());
+    if (init)
+    {	buf->writestring(" = ");
+	init->toCBuffer(buf, hgs);
+    }
+    buf->writeByte(';');
+    buf->writenl();
+}
+
+int VarDeclaration::needThis()
+{
+    //printf("VarDeclaration::needThis(%s, x%x)\n", toChars(), storage_class);
+    return storage_class & STCfield;
+}
+
+int VarDeclaration::isImportedSymbol()
+{
+    if (protection == PROTexport && !init && (isStatic() || isConst() || parent->isModule()))
+	return TRUE;
+    return FALSE;
+}
+
+void VarDeclaration::checkCtorConstInit()
+{
+    if (ctorinit == 0 && isCtorinit() && !(storage_class & STCfield))
+	error("missing initializer in static constructor for const variable");
+}
+
+/************************************
+ * Check to see if variable is a reference to an enclosing function
+ * or not.
+ */
+
+void VarDeclaration::checkNestedReference(Scope *sc, Loc loc)
+{
+    if (!isDataseg() && parent != sc->parent && parent)
+    {
+	FuncDeclaration *fdv = toParent()->isFuncDeclaration();
+	FuncDeclaration *fdthis = sc->parent->isFuncDeclaration();
+
+	if (fdv && fdthis)
+	{
+	    if (loc.filename)
+		fdthis->getLevel(loc, fdv);
+	    nestedref = 1;
+	    fdv->nestedFrameRef = 1;
+	    //printf("var %s in function %s is nested ref\n", toChars(), fdv->toChars());
+	}
+    }
+}
+
+/*******************************
+ * Does symbol go into data segment?
+ */
+
+int VarDeclaration::isDataseg()
+{
+#if 0
+    printf("VarDeclaration::isDataseg(%p, '%s')\n", this, toChars());
+    printf("%x, %p, %p\n", storage_class & (STCstatic | STCconst), parent->isModule(), parent->isTemplateInstance());
+    printf("parent = '%s'\n", parent->toChars());
+#endif
+    Dsymbol *parent = this->toParent();
+    if (!parent && !(storage_class & (STCstatic | STCconst)))
+    {	error("forward referenced");
+	type = Type::terror;
+	return 0;
+    }
+    return (storage_class & (STCstatic | STCconst) ||
+	   parent->isModule() ||
+	   parent->isTemplateInstance());
+}
+
+int VarDeclaration::hasPointers()
+{
+    return (!isDataseg() && type->hasPointers());
+}
+
+/******************************************
+ * If a variable has an auto destructor call, return call for it.
+ * Otherwise, return NULL.
+ */
+
+Expression *VarDeclaration::callAutoDtor()
+{   Expression *e = NULL;
+
+    if (storage_class & (STCauto | STCscope) && !noauto)
+    {
+	for (ClassDeclaration *cd = type->isClassHandle();
+	     cd;
+	     cd = cd->baseClass)
+	{
+	    /* We can do better if there's a way with onstack
+	     * classes to determine if there's no way the monitor
+	     * could be set.
+	     */
+	    if (1 || onstack || cd->dtors.dim)	// if any destructors
+	    {
+		// delete this;
+		Expression *ec;
+
+		ec = new VarExp(loc, this);
+		e = new DeleteExp(loc, ec);
+		e->type = Type::tvoid;
+		break;
+	    }
+	}
+    }
+    return e;
+}
+
+
+/********************************* ClassInfoDeclaration ****************************/
+
+ClassInfoDeclaration::ClassInfoDeclaration(ClassDeclaration *cd)
+    : VarDeclaration(0, ClassDeclaration::classinfo->type, cd->ident, NULL)
+{
+    this->cd = cd;
+    storage_class = STCstatic;
+}
+
+Dsymbol *ClassInfoDeclaration::syntaxCopy(Dsymbol *s)
+{
+    assert(0);		// should never be produced by syntax
+    return NULL;
+}
+
+void ClassInfoDeclaration::semantic(Scope *sc)
+{
+}
+
+/********************************* ModuleInfoDeclaration ****************************/
+
+ModuleInfoDeclaration::ModuleInfoDeclaration(Module *mod)
+    : VarDeclaration(0, Module::moduleinfo->type, mod->ident, NULL)
+{
+    this->mod = mod;
+    storage_class = STCstatic;
+}
+
+Dsymbol *ModuleInfoDeclaration::syntaxCopy(Dsymbol *s)
+{
+    assert(0);		// should never be produced by syntax
+    return NULL;
+}
+
+void ModuleInfoDeclaration::semantic(Scope *sc)
+{
+}
+
+/********************************* TypeInfoDeclaration ****************************/
+
+TypeInfoDeclaration::TypeInfoDeclaration(Type *tinfo, int internal)
+    : VarDeclaration(0, Type::typeinfo->type, tinfo->getTypeInfoIdent(internal), NULL)
+{
+    this->tinfo = tinfo;
+    storage_class = STCstatic;
+    protection = PROTpublic;
+    linkage = LINKc;
+}
+
+Dsymbol *TypeInfoDeclaration::syntaxCopy(Dsymbol *s)
+{
+    assert(0);		// should never be produced by syntax
+    return NULL;
+}
+
+void TypeInfoDeclaration::semantic(Scope *sc)
+{
+    assert(linkage == LINKc);
+}
+
+/***************************** TypeInfoStructDeclaration **********************/
+
+TypeInfoStructDeclaration::TypeInfoStructDeclaration(Type *tinfo)
+    : TypeInfoDeclaration(tinfo, 0)
+{
+}
+
+/***************************** TypeInfoClassDeclaration ***********************/
+
+TypeInfoClassDeclaration::TypeInfoClassDeclaration(Type *tinfo)
+    : TypeInfoDeclaration(tinfo, 0)
+{
+}
+
+/***************************** TypeInfoInterfaceDeclaration *******************/
+
+TypeInfoInterfaceDeclaration::TypeInfoInterfaceDeclaration(Type *tinfo)
+    : TypeInfoDeclaration(tinfo, 0)
+{
+}
+
+/***************************** TypeInfoTypedefDeclaration *********************/
+
+TypeInfoTypedefDeclaration::TypeInfoTypedefDeclaration(Type *tinfo)
+    : TypeInfoDeclaration(tinfo, 0)
+{
+}
+
+/***************************** TypeInfoPointerDeclaration *********************/
+
+TypeInfoPointerDeclaration::TypeInfoPointerDeclaration(Type *tinfo)
+    : TypeInfoDeclaration(tinfo, 0)
+{
+}
+
+/***************************** TypeInfoArrayDeclaration ***********************/
+
+TypeInfoArrayDeclaration::TypeInfoArrayDeclaration(Type *tinfo)
+    : TypeInfoDeclaration(tinfo, 0)
+{
+}
+
+/***************************** TypeInfoStaticArrayDeclaration *****************/
+
+TypeInfoStaticArrayDeclaration::TypeInfoStaticArrayDeclaration(Type *tinfo)
+    : TypeInfoDeclaration(tinfo, 0)
+{
+}
+
+/***************************** TypeInfoAssociativeArrayDeclaration ************/
+
+TypeInfoAssociativeArrayDeclaration::TypeInfoAssociativeArrayDeclaration(Type *tinfo)
+    : TypeInfoDeclaration(tinfo, 0)
+{
+}
+
+/***************************** TypeInfoEnumDeclaration ***********************/
+
+TypeInfoEnumDeclaration::TypeInfoEnumDeclaration(Type *tinfo)
+    : TypeInfoDeclaration(tinfo, 0)
+{
+}
+
+/***************************** TypeInfoFunctionDeclaration ********************/
+
+TypeInfoFunctionDeclaration::TypeInfoFunctionDeclaration(Type *tinfo)
+    : TypeInfoDeclaration(tinfo, 0)
+{
+}
+
+/***************************** TypeInfoDelegateDeclaration ********************/
+
+TypeInfoDelegateDeclaration::TypeInfoDelegateDeclaration(Type *tinfo)
+    : TypeInfoDeclaration(tinfo, 0)
+{
+}
+
+/***************************** TypeInfoTupleDeclaration **********************/
+
+TypeInfoTupleDeclaration::TypeInfoTupleDeclaration(Type *tinfo)
+    : TypeInfoDeclaration(tinfo, 0)
+{
+}
+
+/********************************* ThisDeclaration ****************************/
+
+// For the "this" parameter to member functions
+
+ThisDeclaration::ThisDeclaration(Type *t)
+   : VarDeclaration(0, t, Id::This, NULL)
+{
+    noauto = 1;
+}
+
+Dsymbol *ThisDeclaration::syntaxCopy(Dsymbol *s)
+{
+    assert(0);		// should never be produced by syntax
+    return NULL;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/declaration.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,670 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#ifndef DMD_DECLARATION_H
+#define DMD_DECLARATION_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include "dsymbol.h"
+#include "lexer.h"
+#include "mtype.h"
+
+namespace llvm {
+    class Value;
+}
+
+struct Expression;
+struct Statement;
+struct LabelDsymbol;
+struct Initializer;
+struct Module;
+struct InlineScanState;
+struct ForeachStatement;
+struct FuncDeclaration;
+struct ExpInitializer;
+struct StructDeclaration;
+struct TupleType;
+struct InterState;
+
+enum PROT;
+enum LINK;
+enum TOK;
+enum MATCH;
+
+enum STC
+{
+    STCundefined    = 0,
+    STCstatic	    = 1,
+    STCextern	    = 2,
+    STCconst	    = 4,
+    STCfinal	    = 8,
+    STCabstract     = 0x10,
+    STCparameter    = 0x20,
+    STCfield	    = 0x40,
+    STCoverride	    = 0x80,
+    STCauto         = 0x100,
+    STCsynchronized = 0x200,
+    STCdeprecated   = 0x400,
+    STCin           = 0x800,		// in parameter
+    STCout          = 0x1000,		// out parameter
+    STClazy	    = 0x2000,		// lazy parameter
+    STCforeach      = 0x4000,		// variable for foreach loop
+    STCcomdat       = 0x8000,		// should go into COMDAT record
+    STCvariadic     = 0x10000,		// variadic function argument
+    STCctorinit     = 0x20000,		// can only be set inside constructor
+    STCtemplateparameter = 0x40000,	// template parameter
+    STCscope	    = 0x80000,		// template parameter
+    STCinvariant    = 0x100000,
+    STCref	    = 0x200000,
+};
+
+struct Match
+{
+    int count;			// number of matches found
+    MATCH last;			// match level of lastf
+    FuncDeclaration *lastf;	// last matching function we found
+    FuncDeclaration *nextf;	// current matching function
+    FuncDeclaration *anyf;	// pick a func, any func, to use for error recovery
+};
+
+void overloadResolveX(Match *m, FuncDeclaration *f, Expressions *arguments);
+int overloadApply(FuncDeclaration *fstart,
+	int (*fp)(void *, FuncDeclaration *),
+	void *param);
+
+/**************************************************************/
+
+struct Declaration : Dsymbol
+{
+    Type *type;
+    unsigned storage_class;
+    enum PROT protection;
+    enum LINK linkage;
+
+    Declaration(Identifier *id);
+    void semantic(Scope *sc);
+    char *kind();
+    unsigned size(Loc loc);
+
+    void emitComment(Scope *sc);
+    void toDocBuffer(OutBuffer *buf);
+
+    char *mangle();
+    int isStatic() { return storage_class & STCstatic; }
+    virtual int isStaticConstructor();
+    virtual int isStaticDestructor();
+    virtual int isDelete();
+    virtual int isDataseg();
+    virtual int isCodeseg();
+    int isCtorinit()     { return storage_class & STCctorinit; }
+    int isFinal()        { return storage_class & STCfinal; }
+    int isAbstract()     { return storage_class & STCabstract; }
+    int isConst()        { return storage_class & STCconst; }
+    int isAuto()         { return storage_class & STCauto; }
+    int isScope()        { return storage_class & (STCscope | STCauto); }
+    int isSynchronized() { return storage_class & STCsynchronized; }
+    int isParameter()    { return storage_class & STCparameter; }
+    int isDeprecated()   { return storage_class & STCdeprecated; }
+    int isOverride()     { return storage_class & STCoverride; }
+
+    int isIn()    { return storage_class & STCin; }
+    int isOut()   { return storage_class & STCout; }
+    int isRef()   { return storage_class & STCref; }
+
+    enum PROT prot();
+
+    Declaration *isDeclaration() { return this; }
+
+    virtual void toObjFile();           // compile to .obj file
+
+    // llvm stuff
+    llvm::Value* llvmValue;
+};
+
+/**************************************************************/
+
+struct TupleDeclaration : Declaration
+{
+    Objects *objects;
+    int isexp;			// 1: expression tuple
+
+    TypeTuple *tupletype;	// !=NULL if this is a type tuple
+
+    TupleDeclaration(Loc loc, Identifier *ident, Objects *objects);
+    Dsymbol *syntaxCopy(Dsymbol *);
+    char *kind();
+    Type *getType();
+    int needThis();
+
+    TupleDeclaration *isTupleDeclaration() { return this; }
+};
+
+/**************************************************************/
+
+struct TypedefDeclaration : Declaration
+{
+    Type *basetype;
+    Initializer *init;
+    int sem;			// 0: semantic() has not been run
+				// 1: semantic() is in progress
+				// 2: semantic() has been run
+				// 3: semantic2() has been run
+    int inuse;			// used to detect typedef cycles
+
+    TypedefDeclaration(Loc loc, Identifier *ident, Type *basetype, Initializer *init);
+    Dsymbol *syntaxCopy(Dsymbol *);
+    void semantic(Scope *sc);
+    void semantic2(Scope *sc);
+    char *mangle();
+    char *kind();
+    Type *getType();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+#ifdef _DH
+    Type *htype;
+    Type *hbasetype;
+#endif
+
+    void toDocBuffer(OutBuffer *buf);
+
+    void toObjFile();			// compile to .obj file
+    void toDebug();
+    int cvMember(unsigned char *p);
+
+    TypedefDeclaration *isTypedefDeclaration() { return this; }
+
+    Symbol *sinit;
+    Symbol *toInitializer();
+};
+
+/**************************************************************/
+
+struct AliasDeclaration : Declaration
+{
+    Dsymbol *aliassym;
+    Dsymbol *overnext;		// next in overload list
+    int inSemantic;
+
+    AliasDeclaration(Loc loc, Identifier *ident, Type *type);
+    AliasDeclaration(Loc loc, Identifier *ident, Dsymbol *s);
+    Dsymbol *syntaxCopy(Dsymbol *);
+    void semantic(Scope *sc);
+    int overloadInsert(Dsymbol *s);
+    char *kind();
+    Type *getType();
+    Dsymbol *toAlias();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+#ifdef _DH
+    Type *htype;
+    Dsymbol *haliassym;
+#endif
+
+    void toDocBuffer(OutBuffer *buf);
+
+    AliasDeclaration *isAliasDeclaration() { return this; }
+};
+
+/**************************************************************/
+
+struct VarDeclaration : Declaration
+{
+    Initializer *init;
+    unsigned offset;
+    int noauto;			// no auto semantics
+    int nestedref;		// referenced by a lexically nested function
+    int inuse;
+    int ctorinit;		// it has been initialized in a ctor
+    int onstack;		// 1: it has been allocated on the stack
+				// 2: on stack, run destructor anyway
+    int canassign;		// it can be assigned to
+    Dsymbol *aliassym;		// if redone as alias to another symbol
+    Expression *value;		// when interpreting, this is the value
+				// (NULL if value not determinable)
+
+    VarDeclaration(Loc loc, Type *t, Identifier *id, Initializer *init);
+    Dsymbol *syntaxCopy(Dsymbol *);
+    void semantic(Scope *sc);
+    void semantic2(Scope *sc);
+    char *kind();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+#ifdef _DH
+    Type *htype;
+    Initializer *hinit;
+#endif
+    int needThis();
+    int isImportedSymbol();
+    int isDataseg();
+    int hasPointers();
+    Expression *callAutoDtor();
+    ExpInitializer *getExpInitializer();
+    void checkCtorConstInit();
+    void checkNestedReference(Scope *sc, Loc loc);
+    Dsymbol *toAlias();
+
+    Symbol *toSymbol();
+    void toObjFile();			// compile to .obj file
+    int cvMember(unsigned char *p);
+
+    // Eliminate need for dynamic_cast
+    VarDeclaration *isVarDeclaration() { return (VarDeclaration *)this; }
+};
+
+/**************************************************************/
+
+// This is a shell around a back end symbol
+
+struct SymbolDeclaration : Declaration
+{
+    Symbol *sym;
+    StructDeclaration *dsym;
+
+    SymbolDeclaration(Loc loc, Symbol *s, StructDeclaration *dsym);
+
+    Symbol *toSymbol();
+
+    // Eliminate need for dynamic_cast
+    SymbolDeclaration *isSymbolDeclaration() { return (SymbolDeclaration *)this; }
+};
+
+struct ClassInfoDeclaration : VarDeclaration
+{
+    ClassDeclaration *cd;
+
+    ClassInfoDeclaration(ClassDeclaration *cd);
+    Dsymbol *syntaxCopy(Dsymbol *);
+    void semantic(Scope *sc);
+
+    void emitComment(Scope *sc);
+
+    Symbol *toSymbol();
+};
+
+struct ModuleInfoDeclaration : VarDeclaration
+{
+    Module *mod;
+
+    ModuleInfoDeclaration(Module *mod);
+    Dsymbol *syntaxCopy(Dsymbol *);
+    void semantic(Scope *sc);
+
+    void emitComment(Scope *sc);
+
+    Symbol *toSymbol();
+};
+
+struct TypeInfoDeclaration : VarDeclaration
+{
+    Type *tinfo;
+
+    TypeInfoDeclaration(Type *tinfo, int internal);
+    Dsymbol *syntaxCopy(Dsymbol *);
+    void semantic(Scope *sc);
+
+    void emitComment(Scope *sc);
+
+    Symbol *toSymbol();
+    void toObjFile();			// compile to .obj file
+    virtual void toDt(dt_t **pdt);
+
+    virtual TypeInfoDeclaration* isTypeInfoDeclaration() { return this; }
+};
+
+struct TypeInfoStructDeclaration : TypeInfoDeclaration
+{
+    TypeInfoStructDeclaration(Type *tinfo);
+
+    void toDt(dt_t **pdt);
+};
+
+struct TypeInfoClassDeclaration : TypeInfoDeclaration
+{
+    TypeInfoClassDeclaration(Type *tinfo);
+
+    void toDt(dt_t **pdt);
+};
+
+struct TypeInfoInterfaceDeclaration : TypeInfoDeclaration
+{
+    TypeInfoInterfaceDeclaration(Type *tinfo);
+
+    void toDt(dt_t **pdt);
+};
+
+struct TypeInfoTypedefDeclaration : TypeInfoDeclaration
+{
+    TypeInfoTypedefDeclaration(Type *tinfo);
+
+    void toDt(dt_t **pdt);
+};
+
+struct TypeInfoPointerDeclaration : TypeInfoDeclaration
+{
+    TypeInfoPointerDeclaration(Type *tinfo);
+
+    void toDt(dt_t **pdt);
+};
+
+struct TypeInfoArrayDeclaration : TypeInfoDeclaration
+{
+    TypeInfoArrayDeclaration(Type *tinfo);
+
+    void toDt(dt_t **pdt);
+};
+
+struct TypeInfoStaticArrayDeclaration : TypeInfoDeclaration
+{
+    TypeInfoStaticArrayDeclaration(Type *tinfo);
+
+    void toDt(dt_t **pdt);
+};
+
+struct TypeInfoAssociativeArrayDeclaration : TypeInfoDeclaration
+{
+    TypeInfoAssociativeArrayDeclaration(Type *tinfo);
+
+    void toDt(dt_t **pdt);
+};
+
+struct TypeInfoEnumDeclaration : TypeInfoDeclaration
+{
+    TypeInfoEnumDeclaration(Type *tinfo);
+
+    void toDt(dt_t **pdt);
+};
+
+struct TypeInfoFunctionDeclaration : TypeInfoDeclaration
+{
+    TypeInfoFunctionDeclaration(Type *tinfo);
+
+    void toDt(dt_t **pdt);
+};
+
+struct TypeInfoDelegateDeclaration : TypeInfoDeclaration
+{
+    TypeInfoDelegateDeclaration(Type *tinfo);
+
+    void toDt(dt_t **pdt);
+};
+
+struct TypeInfoTupleDeclaration : TypeInfoDeclaration
+{
+    TypeInfoTupleDeclaration(Type *tinfo);
+
+    void toDt(dt_t **pdt);
+};
+
+struct ThisDeclaration : VarDeclaration
+{
+    ThisDeclaration(Type *t);
+    Dsymbol *syntaxCopy(Dsymbol *);
+};
+
+enum ILS
+{
+    ILSuninitialized,	// not computed yet
+    ILSno,		// cannot inline
+    ILSyes,		// can inline
+};
+
+/**************************************************************/
+
+struct FuncDeclaration : Declaration
+{
+    Array *fthrows;			// Array of Type's of exceptions (not used)
+    Statement *frequire;
+    Statement *fensure;
+    Statement *fbody;
+
+    Identifier *outId;			// identifier for out statement
+    VarDeclaration *vresult;		// variable corresponding to outId
+    LabelDsymbol *returnLabel;		// where the return goes
+
+    DsymbolTable *localsymtab;		// used to prevent symbols in different
+					// scopes from having the same name
+    VarDeclaration *vthis;		// 'this' parameter (member and nested)
+    VarDeclaration *v_arguments;	// '_arguments' parameter
+#if IN_GCC
+    VarDeclaration *v_argptr;	        // '_argptr' variable
+#endif
+    Dsymbols *parameters;		// Array of VarDeclaration's for parameters
+    DsymbolTable *labtab;		// statement label symbol table
+    Declaration *overnext;		// next in overload list
+    Loc endloc;				// location of closing curly bracket
+    int vtblIndex;			// for member functions, index into vtbl[]
+    int naked;				// !=0 if naked
+    int inlineAsm;			// !=0 if has inline assembler
+    ILS inlineStatus;
+    int inlineNest;			// !=0 if nested inline
+    int cantInterpret;			// !=0 if cannot interpret function
+    int semanticRun;			// !=0 if semantic3() had been run
+    int nestedFrameRef;			// !=0 if nested variables referenced frame ptr
+    ForeachStatement *fes;		// if foreach body, this is the foreach
+    int introducing;			// !=0 if 'introducing' function
+    Type *tintro;			// if !=NULL, then this is the type
+					// of the 'introducing' function
+					// this one is overriding
+    int inferRetType;			// !=0 if return type is to be inferred
+    Scope *scope;		// !=NULL means context to use
+
+    // Things that should really go into Scope
+    int hasReturnExp;			// 1 if there's a return exp; statement
+					// 2 if there's a throw statement
+					// 4 if there's an assert(0)
+					// 8 if there's inline asm
+
+    // Support for NRVO (named return value optimization)
+    int nrvo_can;			// !=0 means we can do it
+    VarDeclaration *nrvo_var;		// variable to replace with shidden
+    Symbol *shidden;			// hidden pointer passed to function
+
+    FuncDeclaration(Loc loc, Loc endloc, Identifier *id, enum STC storage_class, Type *type);
+    Dsymbol *syntaxCopy(Dsymbol *);
+    void semantic(Scope *sc);
+    void semantic2(Scope *sc);
+    void semantic3(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    void bodyToCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    int overrides(FuncDeclaration *fd);
+    int overloadInsert(Dsymbol *s);
+    FuncDeclaration *overloadExactMatch(Type *t);
+    FuncDeclaration *overloadResolve(Loc loc, Expressions *arguments);
+    LabelDsymbol *searchLabel(Identifier *ident);
+    AggregateDeclaration *isThis();
+    AggregateDeclaration *isMember2();
+    int getLevel(Loc loc, FuncDeclaration *fd);	// lexical nesting level difference
+    void appendExp(Expression *e);
+    void appendState(Statement *s);
+    char *mangle();
+    int isMain();
+    int isWinMain();
+    int isDllMain();
+    int isExport();
+    int isImportedSymbol();
+    int isAbstract();
+    int isCodeseg();
+    virtual int isNested();
+    int needThis();
+    virtual int isVirtual();
+    virtual int addPreInvariant();
+    virtual int addPostInvariant();
+    Expression *interpret(InterState *istate, Expressions *arguments);
+    void inlineScan();
+    int canInline(int hasthis, int hdrscan = 0);
+    Expression *doInline(InlineScanState *iss, Expression *ethis, Array *arguments);
+    char *kind();
+    void toDocBuffer(OutBuffer *buf);
+
+    static FuncDeclaration *genCfunc(Type *treturn, char *name);
+    static FuncDeclaration *genCfunc(Type *treturn, Identifier *id);
+
+    Symbol *toSymbol();
+    Symbol *toThunkSymbol(int offset);	// thunk version
+    void toObjFile();			// compile to .obj file
+    int cvMember(unsigned char *p);
+
+    FuncDeclaration *isFuncDeclaration() { return this; }
+};
+
+struct FuncAliasDeclaration : FuncDeclaration
+{
+    FuncDeclaration *funcalias;
+
+    FuncAliasDeclaration(FuncDeclaration *funcalias);
+
+    FuncAliasDeclaration *isFuncAliasDeclaration() { return this; }
+    char *kind();
+    Symbol *toSymbol();
+};
+
+struct FuncLiteralDeclaration : FuncDeclaration
+{
+    enum TOK tok;			// TOKfunction or TOKdelegate
+
+    FuncLiteralDeclaration(Loc loc, Loc endloc, Type *type, enum TOK tok,
+	ForeachStatement *fes);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    Dsymbol *syntaxCopy(Dsymbol *);
+    int isNested();
+
+    FuncLiteralDeclaration *isFuncLiteralDeclaration() { return this; }
+    char *kind();
+};
+
+struct CtorDeclaration : FuncDeclaration
+{   Arguments *arguments;
+    int varargs;
+
+    CtorDeclaration(Loc loc, Loc endloc, Arguments *arguments, int varargs);
+    Dsymbol *syntaxCopy(Dsymbol *);
+    void semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    char *kind();
+    char *toChars();
+    int isVirtual();
+    int addPreInvariant();
+    int addPostInvariant();
+    void toDocBuffer(OutBuffer *buf);
+
+    CtorDeclaration *isCtorDeclaration() { return this; }
+};
+
+struct DtorDeclaration : FuncDeclaration
+{
+    DtorDeclaration(Loc loc, Loc endloc);
+    Dsymbol *syntaxCopy(Dsymbol *);
+    void semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    int isVirtual();
+    int addPreInvariant();
+    int addPostInvariant();
+    int overloadInsert(Dsymbol *s);
+    void emitComment(Scope *sc);
+
+    DtorDeclaration *isDtorDeclaration() { return this; }
+};
+
+struct StaticCtorDeclaration : FuncDeclaration
+{
+    StaticCtorDeclaration(Loc loc, Loc endloc);
+    Dsymbol *syntaxCopy(Dsymbol *);
+    void semantic(Scope *sc);
+    AggregateDeclaration *isThis();
+    int isStaticConstructor();
+    int isVirtual();
+    int addPreInvariant();
+    int addPostInvariant();
+    void emitComment(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    StaticCtorDeclaration *isStaticCtorDeclaration() { return this; }
+};
+
+struct StaticDtorDeclaration : FuncDeclaration
+{
+    StaticDtorDeclaration(Loc loc, Loc endloc);
+    Dsymbol *syntaxCopy(Dsymbol *);
+    void semantic(Scope *sc);
+    AggregateDeclaration *isThis();
+    int isStaticDestructor();
+    int isVirtual();
+    int addPreInvariant();
+    int addPostInvariant();
+    void emitComment(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    StaticDtorDeclaration *isStaticDtorDeclaration() { return this; }
+};
+
+struct InvariantDeclaration : FuncDeclaration
+{
+    InvariantDeclaration(Loc loc, Loc endloc);
+    Dsymbol *syntaxCopy(Dsymbol *);
+    void semantic(Scope *sc);
+    int isVirtual();
+    int addPreInvariant();
+    int addPostInvariant();
+    void emitComment(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    InvariantDeclaration *isInvariantDeclaration() { return this; }
+};
+
+
+struct UnitTestDeclaration : FuncDeclaration
+{
+    UnitTestDeclaration(Loc loc, Loc endloc);
+    Dsymbol *syntaxCopy(Dsymbol *);
+    void semantic(Scope *sc);
+    AggregateDeclaration *isThis();
+    int isVirtual();
+    int addPreInvariant();
+    int addPostInvariant();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    UnitTestDeclaration *isUnitTestDeclaration() { return this; }
+};
+
+struct NewDeclaration : FuncDeclaration
+{   Arguments *arguments;
+    int varargs;
+
+    NewDeclaration(Loc loc, Loc endloc, Arguments *arguments, int varargs);
+    Dsymbol *syntaxCopy(Dsymbol *);
+    void semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    char *kind();
+    int isVirtual();
+    int addPreInvariant();
+    int addPostInvariant();
+
+    NewDeclaration *isNewDeclaration() { return this; }
+};
+
+
+struct DeleteDeclaration : FuncDeclaration
+{   Arguments *arguments;
+
+    DeleteDeclaration(Loc loc, Loc endloc, Arguments *arguments);
+    Dsymbol *syntaxCopy(Dsymbol *);
+    void semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    char *kind();
+    int isDelete();
+    int isVirtual();
+    int addPreInvariant();
+    int addPostInvariant();
+#ifdef _DH
+    DeleteDeclaration *isDeleteDeclaration() { return this; }
+#endif
+};
+
+#endif /* DMD_DECLARATION_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/delegatize.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,214 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "mars.h"
+#include "expression.h"
+#include "statement.h"
+#include "mtype.h"
+#include "utf.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "scope.h"
+
+/********************************************
+ * Convert from expression to delegate that returns the expression,
+ * i.e. convert:
+ *	expr
+ * to:
+ *	t delegate() { return expr; }
+ */
+
+Expression *Expression::toDelegate(Scope *sc, Type *t)
+{
+    //printf("Expression::toDelegate(t = %s) %s\n", t->toChars(), toChars());
+    TypeFunction *tf = new TypeFunction(NULL, t, 0, LINKd);
+    FuncLiteralDeclaration *fld =
+	new FuncLiteralDeclaration(loc, loc, tf, TOKdelegate, NULL);
+    Expression *e;
+#if 1
+    sc = sc->push();
+    sc->parent = fld;		// set current function to be the delegate
+    e = this;
+    e->scanForNestedRef(sc);
+    sc = sc->pop();
+#else
+    e = this->syntaxCopy();
+#endif
+    Statement *s = new ReturnStatement(loc, e);
+    fld->fbody = s;
+    e = new FuncExp(loc, fld);
+    e = e->semantic(sc);
+    return e;
+}
+
+/******************************
+ * Perform scanForNestedRef() on an array of Expressions.
+ */
+
+void arrayExpressionScanForNestedRef(Scope *sc, Expressions *a)
+{
+    //printf("arrayExpressionScanForNestedRef(%p)\n", a);
+    if (a)
+    {
+	for (int i = 0; i < a->dim; i++)
+	{   Expression *e = (Expression *)a->data[i];
+
+	    if (e)
+	    {
+		e->scanForNestedRef(sc);
+	    }
+	}
+    }
+}
+
+void Expression::scanForNestedRef(Scope *sc)
+{
+    //printf("Expression::scanForNestedRef(%s)\n", toChars());
+}
+
+void SymOffExp::scanForNestedRef(Scope *sc)
+{
+    //printf("SymOffExp::scanForNestedRef(%s)\n", toChars());
+    VarDeclaration *v = var->isVarDeclaration();
+    if (v)
+	v->checkNestedReference(sc, 0);
+}
+
+void VarExp::scanForNestedRef(Scope *sc)
+{
+    //printf("VarExp::scanForNestedRef(%s)\n", toChars());
+    VarDeclaration *v = var->isVarDeclaration();
+    if (v)
+	v->checkNestedReference(sc, 0);
+}
+
+void ThisExp::scanForNestedRef(Scope *sc)
+{
+    assert(var);
+    var->isVarDeclaration()->checkNestedReference(sc, 0);
+}
+
+void SuperExp::scanForNestedRef(Scope *sc)
+{
+    ThisExp::scanForNestedRef(sc);
+}
+
+void FuncExp::scanForNestedRef(Scope *sc)
+{
+    //printf("FuncExp::scanForNestedRef(%s)\n", toChars());
+    //fd->parent = sc->parent;
+}
+
+void DeclarationExp::scanForNestedRef(Scope *sc)
+{
+    //printf("DeclarationExp::scanForNestedRef() %s\n", toChars());
+    declaration->parent = sc->parent;
+}
+
+void NewExp::scanForNestedRef(Scope *sc)
+{
+    //printf("NewExp::scanForNestedRef(Scope *sc): %s\n", toChars());
+
+    if (thisexp)
+	thisexp->scanForNestedRef(sc);
+    arrayExpressionScanForNestedRef(sc, newargs);
+    arrayExpressionScanForNestedRef(sc, arguments);
+}
+
+void UnaExp::scanForNestedRef(Scope *sc)
+{
+    e1->scanForNestedRef(sc);
+}
+
+void BinExp::scanForNestedRef(Scope *sc)
+{
+    e1->scanForNestedRef(sc);
+    e2->scanForNestedRef(sc);
+}
+
+void CallExp::scanForNestedRef(Scope *sc)
+{
+    //printf("CallExp::scanForNestedRef(Scope *sc): %s\n", toChars());
+    e1->scanForNestedRef(sc);
+    arrayExpressionScanForNestedRef(sc, arguments);
+}
+
+
+void IndexExp::scanForNestedRef(Scope *sc)
+{
+    e1->scanForNestedRef(sc);
+
+    if (lengthVar)
+    {	//printf("lengthVar\n");
+	lengthVar->parent = sc->parent;
+    }
+    e2->scanForNestedRef(sc);
+}
+
+
+void SliceExp::scanForNestedRef(Scope *sc)
+{
+    e1->scanForNestedRef(sc);
+
+    if (lengthVar)
+    {	//printf("lengthVar\n");
+	lengthVar->parent = sc->parent;
+    }
+    if (lwr)
+	lwr->scanForNestedRef(sc);
+    if (upr)
+	upr->scanForNestedRef(sc);
+}
+
+
+void ArrayLiteralExp::scanForNestedRef(Scope *sc)
+{
+    arrayExpressionScanForNestedRef(sc, elements);
+}
+
+
+void AssocArrayLiteralExp::scanForNestedRef(Scope *sc)
+{
+    arrayExpressionScanForNestedRef(sc, keys);
+    arrayExpressionScanForNestedRef(sc, values);
+}
+
+
+void StructLiteralExp::scanForNestedRef(Scope *sc)
+{
+    arrayExpressionScanForNestedRef(sc, elements);
+}
+
+
+void TupleExp::scanForNestedRef(Scope *sc)
+{
+    arrayExpressionScanForNestedRef(sc, exps);
+}
+
+
+void ArrayExp::scanForNestedRef(Scope *sc)
+{
+    e1->scanForNestedRef(sc);
+    arrayExpressionScanForNestedRef(sc, arguments);
+}
+
+
+void CondExp::scanForNestedRef(Scope *sc)
+{
+    econd->scanForNestedRef(sc);
+    e1->scanForNestedRef(sc);
+    e2->scanForNestedRef(sc);
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/doc.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,1925 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+// This implements the Ddoc capability.
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <ctype.h>
+#include <assert.h>
+
+#if IN_GCC || IN_LLVM
+#include "mem.h"
+#else
+#if _WIN32
+#include "..\root\mem.h"
+#elif linux
+#include "../root/mem.h"
+#else
+#error "fix this"
+#endif
+#endif
+
+#include "root.h"
+
+#include "mars.h"
+#include "dsymbol.h"
+#include "macro.h"
+#include "template.h"
+#include "lexer.h"
+#include "aggregate.h"
+#include "declaration.h"
+#include "enum.h"
+#include "id.h"
+#include "module.h"
+#include "scope.h"
+#include "hdrgen.h"
+#include "doc.h"
+#include "mtype.h"
+
+struct Escape
+{
+    char *strings[256];
+
+    static char *escapeChar(unsigned c);
+};
+
+struct Section
+{
+    unsigned char *name;
+    unsigned namelen;
+
+    unsigned char *body;
+    unsigned bodylen;
+
+    int nooutput;
+
+    virtual void write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf);
+};
+
+struct ParamSection : Section
+{
+    void write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf);
+};
+
+struct MacroSection : Section
+{
+    void write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf);
+};
+
+struct DocComment
+{
+    Array sections;		// Section*[]
+
+    Section *summary;
+    Section *copyright;
+    Section *macros;
+    Macro **pmacrotable;
+    Escape **pescapetable;
+
+    DocComment();
+
+    static DocComment *parse(Scope *sc, Dsymbol *s, unsigned char *comment);
+    static void parseMacros(Escape **pescapetable, Macro **pmacrotable, unsigned char *m, unsigned mlen);
+    static void parseEscapes(Escape **pescapetable, unsigned char *textstart, unsigned textlen);
+
+    void parseSections(unsigned char *comment);
+    void writeSections(Scope *sc, Dsymbol *s, OutBuffer *buf);
+};
+
+
+int cmp(char *stringz, void *s, size_t slen);
+int icmp(char *stringz, void *s, size_t slen);
+int isDitto(unsigned char *comment);
+unsigned char *skipwhitespace(unsigned char *p);
+unsigned skiptoident(OutBuffer *buf, unsigned i);
+unsigned skippastident(OutBuffer *buf, unsigned i);
+void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset);
+void highlightCode(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset);
+void highlightCode2(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset);
+Argument *isFunctionParameter(Dsymbol *s, unsigned char *p, unsigned len);
+
+static unsigned char ddoc_default[] = "\
+DDOC =	<html><head>\n\
+	<META http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">\n\
+	<title>$(TITLE)</title>\n\
+	</head><body>\n\
+	<h1>$(TITLE)</h1>\n\
+	$(BODY)\n\
+	<hr>$(SMALL Page generated by $(LINK2 http://www.digitalmars.com/d/ddoc.html, Ddoc). $(COPYRIGHT))\n\
+	</body></html>\n\
+\n\
+B =	<b>$0</b>\n\
+I =	<i>$0</i>\n\
+U =	<u>$0</u>\n\
+P =	<p>$0</p>\n\
+DL =	<dl>$0</dl>\n\
+DT =	<dt>$0</dt>\n\
+DD =	<dd>$0</dd>\n\
+TABLE =	<table>$0</table>\n\
+TR =	<tr>$0</tr>\n\
+TH =	<th>$0</th>\n\
+TD =	<td>$0</td>\n\
+OL =	<ol>$0</ol>\n\
+UL =	<ul>$0</ul>\n\
+LI =	<li>$0</li>\n\
+BIG =	<big>$0</big>\n\
+SMALL =	<small>$0</small>\n\
+BR =	<br>\n\
+LINK =	<a href=\"$0\">$0</a>\n\
+LINK2 =	<a href=\"$1\">$+</a>\n\
+\n\
+RED =	<font color=red>$0</font>\n\
+BLUE =	<font color=blue>$0</font>\n\
+GREEN =	<font color=green>$0</font>\n\
+YELLOW =<font color=yellow>$0</font>\n\
+BLACK =	<font color=black>$0</font>\n\
+WHITE =	<font color=white>$0</font>\n\
+\n\
+D_CODE = <pre class=\"d_code\">$0</pre>\n\
+D_COMMENT = $(GREEN $0)\n\
+D_STRING  = $(RED $0)\n\
+D_KEYWORD = $(BLUE $0)\n\
+D_PSYMBOL = $(U $0)\n\
+D_PARAM	  = $(I $0)\n\
+\n\
+DDOC_COMMENT   = <!-- $0 -->\n\
+DDOC_DECL      = $(DT $(BIG $0))\n\
+DDOC_DECL_DD   = $(DD $0)\n\
+DDOC_DITTO     = $(BR)$0\n\
+DDOC_SECTIONS  = $0\n\
+DDOC_SUMMARY   = $0$(BR)$(BR)\n\
+DDOC_DESCRIPTION = $0$(BR)$(BR)\n\
+DDOC_AUTHORS   = $(B Authors:)$(BR)\n$0$(BR)$(BR)\n\
+DDOC_BUGS      = $(RED BUGS:)$(BR)\n$0$(BR)$(BR)\n\
+DDOC_COPYRIGHT = $(B Copyright:)$(BR)\n$0$(BR)$(BR)\n\
+DDOC_DATE      = $(B Date:)$(BR)\n$0$(BR)$(BR)\n\
+DDOC_DEPRECATED = $(RED Deprecated:)$(BR)\n$0$(BR)$(BR)\n\
+DDOC_EXAMPLES  = $(B Examples:)$(BR)\n$0$(BR)$(BR)\n\
+DDOC_HISTORY   = $(B History:)$(BR)\n$0$(BR)$(BR)\n\
+DDOC_LICENSE   = $(B License:)$(BR)\n$0$(BR)$(BR)\n\
+DDOC_RETURNS   = $(B Returns:)$(BR)\n$0$(BR)$(BR)\n\
+DDOC_SEE_ALSO  = $(B See Also:)$(BR)\n$0$(BR)$(BR)\n\
+DDOC_STANDARDS = $(B Standards:)$(BR)\n$0$(BR)$(BR)\n\
+DDOC_THROWS    = $(B Throws:)$(BR)\n$0$(BR)$(BR)\n\
+DDOC_VERSION   = $(B Version:)$(BR)\n$0$(BR)$(BR)\n\
+DDOC_SECTION_H = $(B $0)$(BR)\n\
+DDOC_SECTION   = $0$(BR)$(BR)\n\
+DDOC_MEMBERS   = $(DL $0)\n\
+DDOC_MODULE_MEMBERS = $(DDOC_MEMBERS $0)\n\
+DDOC_CLASS_MEMBERS  = $(DDOC_MEMBERS $0)\n\
+DDOC_STRUCT_MEMBERS = $(DDOC_MEMBERS $0)\n\
+DDOC_ENUM_MEMBERS   = $(DDOC_MEMBERS $0)\n\
+DDOC_TEMPLATE_MEMBERS = $(DDOC_MEMBERS $0)\n\
+DDOC_PARAMS    = $(B Params:)$(BR)\n$(TABLE $0)$(BR)\n\
+DDOC_PARAM_ROW = $(TR $0)\n\
+DDOC_PARAM_ID  = $(TD $0)\n\
+DDOC_PARAM_DESC = $(TD $0)\n\
+DDOC_BLANKLINE	= $(BR)$(BR)\n\
+\n\
+DDOC_PSYMBOL	= $(U $0)\n\
+DDOC_KEYWORD	= $(B $0)\n\
+DDOC_PARAM	= $(I $0)\n\
+\n\
+ESCAPES = /</&lt;/\n\
+	  />/&gt;/\n\
+	  /&/&amp;/\n\
+";
+
+static char ddoc_decl_s[] = "$(DDOC_DECL ";
+static char ddoc_decl_e[] = ")\n";
+
+static char ddoc_decl_dd_s[] = "$(DDOC_DECL_DD ";
+static char ddoc_decl_dd_e[] = ")\n";
+
+
+/****************************************************
+ */
+
+void Module::gendocfile()
+{
+    static OutBuffer mbuf;
+    static int mbuf_done;
+
+    OutBuffer buf;
+
+    //printf("Module::gendocfile()\n");
+
+    if (!mbuf_done)		// if not already read the ddoc files
+    {	mbuf_done = 1;
+
+	// Use our internal default
+	mbuf.write(ddoc_default, sizeof(ddoc_default) - 1);
+
+	// Override with DDOCFILE specified in the sc.ini file
+	char *p = getenv("DDOCFILE");
+	if (p)
+	    global.params.ddocfiles->shift(p);
+
+	// Override with the ddoc macro files from the command line
+	for (int i = 0; i < global.params.ddocfiles->dim; i++)
+	{
+	    FileName f((char *)global.params.ddocfiles->data[i], 0);
+	    File file(&f);
+	    file.readv();
+	    // BUG: convert file contents to UTF-8 before use
+
+	    //printf("file: '%.*s'\n", file.len, file.buffer);
+	    mbuf.write(file.buffer, file.len);
+	}
+    }
+    DocComment::parseMacros(&escapetable, &macrotable, mbuf.data, mbuf.offset);
+
+    Scope *sc = Scope::createGlobal(this);	// create root scope
+    sc->docbuf = &buf;
+
+    DocComment *dc = DocComment::parse(sc, this, comment);
+    dc->pmacrotable = &macrotable;
+    dc->pescapetable = &escapetable;
+
+    // Generate predefined macros
+
+    // Set the title to be the name of the module
+    {	char *p = toPrettyChars();
+	Macro::define(&macrotable, (unsigned char *)"TITLE", 5, (unsigned char *)p, strlen(p));
+    }
+
+    time_t t;
+    time(&t);
+    char *p = ctime(&t);
+    p = mem.strdup(p);
+    Macro::define(&macrotable, (unsigned char *)"DATETIME", 8, (unsigned char *)p, strlen(p));
+    Macro::define(&macrotable, (unsigned char *)"YEAR", 4, (unsigned char *)p + 20, 4);
+
+    char *docfilename = docfile->toChars();
+    Macro::define(&macrotable, (unsigned char *)"DOCFILENAME", 11, (unsigned char *)docfilename, strlen(docfilename));
+
+    if (dc->copyright)
+    {
+	dc->copyright->nooutput = 1;
+	Macro::define(&macrotable, (unsigned char *)"COPYRIGHT", 9, dc->copyright->body, dc->copyright->bodylen);
+    }
+
+    buf.printf("$(DDOC_COMMENT Generated by Ddoc from %s)\n", srcfile->toChars());
+
+    if (isDocFile)
+    {
+	size_t commentlen = strlen((char *)comment);
+	if (dc->macros)
+	{
+	    commentlen = dc->macros->name - comment;
+	    dc->macros->write(dc, sc, this, sc->docbuf);
+	}
+	sc->docbuf->write(comment, commentlen);
+	highlightText(NULL, this, sc->docbuf, 0);
+    }
+    else
+    {
+
+	dc->writeSections(sc, this, sc->docbuf);
+	emitMemberComments(sc);
+    }
+
+    //printf("BODY= '%.*s'\n", buf.offset, buf.data);
+    Macro::define(&macrotable, (unsigned char *)"BODY", 4, buf.data, buf.offset);
+
+    OutBuffer buf2;
+    buf2.writestring("$(DDOC)\n");
+    unsigned end = buf2.offset;
+    macrotable->expand(&buf2, 0, &end, NULL, 0);
+
+#if 1
+    /* Remove all the escape sequences from buf2,
+     * and make CR-LF the newline.
+     */
+    {
+	buf.setsize(0);
+	buf.reserve(buf2.offset);
+	unsigned char *p = buf2.data;
+	for (unsigned j = 0; j < buf2.offset; j++)
+	{
+	    unsigned char c = p[j];
+	    if (c == 0xFF && j + 1 < buf2.offset)
+	    {
+		j++;
+		continue;
+	    }
+	    if (c == '\n')
+		buf.writeByte('\r');
+	    else if (c == '\r')
+	    {
+		buf.writestring("\r\n");
+		if (j + 1 < buf2.offset && p[j + 1] == '\n')
+		{
+		    j++;
+		}
+		continue;
+	    }
+	    buf.writeByte(c);
+	}
+    }
+
+    // Transfer image to file
+    assert(docfile);
+    docfile->setbuffer(buf.data, buf.offset);
+    docfile->ref = 1;
+    char *pt = FileName::path(docfile->toChars());
+    if (*pt)
+	FileName::ensurePathExists(pt);
+    mem.free(pt);
+    docfile->writev();
+#else
+    /* Remove all the escape sequences from buf2
+     */
+    {	unsigned i = 0;
+	unsigned char *p = buf2.data;
+	for (unsigned j = 0; j < buf2.offset; j++)
+	{
+	    if (p[j] == 0xFF && j + 1 < buf2.offset)
+	    {
+		j++;
+		continue;
+	    }
+	    p[i] = p[j];
+	    i++;
+	}
+	buf2.setsize(i);
+    }
+
+    // Transfer image to file
+    docfile->setbuffer(buf2.data, buf2.offset);
+    docfile->ref = 1;
+    char *pt = FileName::path(docfile->toChars());
+    if (*pt)
+	FileName::ensurePathExists(pt);
+    mem.free(pt);
+    docfile->writev();
+#endif
+}
+
+/******************************* emitComment **********************************/
+
+/*
+ * Emit doc comment to documentation file
+ */
+
+void Dsymbol::emitDitto(Scope *sc)
+{
+    OutBuffer *buf = sc->docbuf;
+    unsigned o;
+    OutBuffer b;
+
+    b.writestring("$(DDOC_DITTO ");
+    o = b.offset;
+    toDocBuffer(&b);
+    highlightCode(sc, this, &b, o);
+    b.writeByte(')');
+    buf->spread(sc->lastoffset, b.offset);
+    memcpy(buf->data + sc->lastoffset, b.data, b.offset);
+    sc->lastoffset += b.offset;
+}
+
+void ScopeDsymbol::emitMemberComments(Scope *sc)
+{
+    //printf("ScopeDsymbol::emitMemberComments()\n");
+    OutBuffer *buf = sc->docbuf;
+
+    if (members)
+    {	char *m = "$(DDOC_MEMBERS \n";
+
+	if (isModule())
+	    m = "$(DDOC_MODULE_MEMBERS \n";
+	else if (isClassDeclaration())
+	    m = "$(DDOC_CLASS_MEMBERS \n";
+	else if (isStructDeclaration())
+	    m = "$(DDOC_STRUCT_MEMBERS \n";
+	else if (isEnumDeclaration())
+	    m = "$(DDOC_ENUM_MEMBERS \n";
+	else if (isTemplateDeclaration())
+	    m = "$(DDOC_TEMPLATE_MEMBERS \n";
+
+	// BUG: if no members are actually printed, we should not emit DDOC_MEMBERS
+	buf->writestring(m);
+	sc = sc->push(this);
+	for (int i = 0; i < members->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)members->data[i];
+	    //printf("\ts = '%s'\n", s->toChars());
+	    s->emitComment(sc);
+	}
+	sc->pop();
+	buf->writestring(")\n");
+    }
+}
+
+void emitProtection(OutBuffer *buf, PROT prot)
+{
+    char *p;
+
+    switch (prot)
+    {
+	case PROTpackage:	p = "package";	 break;
+	case PROTprotected:	p = "protected"; break;
+	case PROTexport:	p = "export";	 break;
+	default:		p = NULL;	 break;
+    }
+    if (p)
+	buf->printf("%s ", p);
+}
+
+void Dsymbol::emitComment(Scope *sc)		   { }
+void InvariantDeclaration::emitComment(Scope *sc)  { }
+void DtorDeclaration::emitComment(Scope *sc)	   { }
+void StaticCtorDeclaration::emitComment(Scope *sc) { }
+void StaticDtorDeclaration::emitComment(Scope *sc) { }
+void ClassInfoDeclaration::emitComment(Scope *sc)  { }
+void ModuleInfoDeclaration::emitComment(Scope *sc) { }
+void TypeInfoDeclaration::emitComment(Scope *sc)   { }
+
+
+void Declaration::emitComment(Scope *sc)
+{
+    //printf("Declaration::emitComment(%p '%s'), comment = '%s'\n", this, toChars(), comment);
+    //printf("type = %p\n", type);
+
+    if (protection == PROTprivate || !ident ||
+	(!type && !isCtorDeclaration() && !isAliasDeclaration()))
+	return;
+    if (!comment)
+	return;
+
+    OutBuffer *buf = sc->docbuf;
+    DocComment *dc = DocComment::parse(sc, this, comment);
+    unsigned o;
+
+    if (!dc)
+    {
+	emitDitto(sc);
+	return;
+    }
+    dc->pmacrotable = &sc->module->macrotable;
+
+    buf->writestring(ddoc_decl_s);
+	o = buf->offset;
+	toDocBuffer(buf);
+	highlightCode(sc, this, buf, o);
+	sc->lastoffset = buf->offset;
+    buf->writestring(ddoc_decl_e);
+
+    buf->writestring(ddoc_decl_dd_s);
+    dc->writeSections(sc, this, buf);
+    buf->writestring(ddoc_decl_dd_e);
+}
+
+void AggregateDeclaration::emitComment(Scope *sc)
+{
+    //printf("AggregateDeclaration::emitComment() '%s'\n", toChars());
+    if (prot() == PROTprivate)
+	return;
+    if (!comment)
+	return;
+
+    OutBuffer *buf = sc->docbuf;
+    DocComment *dc = DocComment::parse(sc, this, comment);
+
+    if (!dc)
+    {
+	emitDitto(sc);
+	return;
+    }
+    dc->pmacrotable = &sc->module->macrotable;
+
+    buf->writestring(ddoc_decl_s);
+    toDocBuffer(buf);
+    sc->lastoffset = buf->offset;
+    buf->writestring(ddoc_decl_e);
+
+    buf->writestring(ddoc_decl_dd_s);
+    dc->writeSections(sc, this, buf);
+    emitMemberComments(sc);
+    buf->writestring(ddoc_decl_dd_e);
+}
+
+void TemplateDeclaration::emitComment(Scope *sc)
+{
+    //printf("TemplateDeclaration::emitComment() '%s', kind = %s\n", toChars(), kind());
+    if (prot() == PROTprivate)
+	return;
+    if (!comment)
+	return;
+
+    OutBuffer *buf = sc->docbuf;
+    DocComment *dc = DocComment::parse(sc, this, comment);
+    unsigned o;
+    int hasmembers = 1;
+
+    Dsymbol *ss = this;
+
+    if (onemember)
+    {
+	ss = onemember->isAggregateDeclaration();
+	if (!ss)
+	{
+	    ss = onemember->isFuncDeclaration();
+	    if (ss)
+		hasmembers = 0;
+	    else
+		ss = this;
+	}
+    }
+
+    if (!dc)
+    {
+	ss->emitDitto(sc);
+	return;
+    }
+    dc->pmacrotable = &sc->module->macrotable;
+
+    buf->writestring(ddoc_decl_s);
+	o = buf->offset;
+	ss->toDocBuffer(buf);
+	if (ss == this)
+	    highlightCode(sc, this, buf, o);
+	sc->lastoffset = buf->offset;
+    buf->writestring(ddoc_decl_e);
+
+    buf->writestring(ddoc_decl_dd_s);
+    dc->writeSections(sc, this, buf);
+    if (hasmembers)
+	((ScopeDsymbol *)ss)->emitMemberComments(sc);
+    buf->writestring(ddoc_decl_dd_e);
+}
+
+void EnumDeclaration::emitComment(Scope *sc)
+{
+    if (prot() == PROTprivate)
+	return;
+//    if (!comment)
+    {	if (isAnonymous() && members)
+	{
+	    for (int i = 0; i < members->dim; i++)
+	    {
+		Dsymbol *s = (Dsymbol *)members->data[i];
+		s->emitComment(sc);
+	    }
+	    return;
+	}
+    }
+    if (!comment)
+	return;
+    if (isAnonymous())
+	return;
+
+    OutBuffer *buf = sc->docbuf;
+    DocComment *dc = DocComment::parse(sc, this, comment);
+
+    if (!dc)
+    {
+	emitDitto(sc);
+	return;
+    }
+    dc->pmacrotable = &sc->module->macrotable;
+
+    buf->writestring(ddoc_decl_s);
+	toDocBuffer(buf);
+	sc->lastoffset = buf->offset;
+    buf->writestring(ddoc_decl_e);
+
+    buf->writestring(ddoc_decl_dd_s);
+    dc->writeSections(sc, this, buf);
+    emitMemberComments(sc);
+    buf->writestring(ddoc_decl_dd_e);
+}
+
+void EnumMember::emitComment(Scope *sc)
+{
+    //printf("EnumMember::emitComment(%p '%s'), comment = '%s'\n", this, toChars(), comment);
+    if (prot() == PROTprivate)
+	return;
+    if (!comment)
+	return;
+
+    OutBuffer *buf = sc->docbuf;
+    DocComment *dc = DocComment::parse(sc, this, comment);
+    unsigned o;
+
+    if (!dc)
+    {
+	emitDitto(sc);
+	return;
+    }
+    dc->pmacrotable = &sc->module->macrotable;
+
+    buf->writestring(ddoc_decl_s);
+	o = buf->offset;
+	toDocBuffer(buf);
+	highlightCode(sc, this, buf, o);
+	sc->lastoffset = buf->offset;
+    buf->writestring(ddoc_decl_e);
+
+    buf->writestring(ddoc_decl_dd_s);
+    dc->writeSections(sc, this, buf);
+    buf->writestring(ddoc_decl_dd_e);
+}
+
+/******************************* toDocBuffer **********************************/
+
+void Dsymbol::toDocBuffer(OutBuffer *buf)
+{
+    //printf("Dsymbol::toDocbuffer() %s\n", toChars());
+    HdrGenState hgs;
+
+    toCBuffer(buf, &hgs);
+}
+
+void prefix(OutBuffer *buf, Dsymbol *s)
+{
+    if (s->isDeprecated())
+	buf->writestring("deprecated ");
+    Declaration *d = s->isDeclaration();
+    if (d)
+    {
+	emitProtection(buf, d->protection);
+	if (d->isAbstract())
+	    buf->writestring("abstract ");
+	if (d->isStatic())
+	    buf->writestring("static ");
+	if (d->isConst())
+	    buf->writestring("const ");
+	if (d->isFinal())
+	    buf->writestring("final ");
+	if (d->isSynchronized())
+	    buf->writestring("synchronized ");
+    }
+}
+
+void Declaration::toDocBuffer(OutBuffer *buf)
+{
+    //printf("Declaration::toDocbuffer() %s\n", toChars());
+    if (ident)
+    {
+	prefix(buf, this);
+
+	if (type)
+	{   HdrGenState hgs;
+	    hgs.ddoc = 1;
+	    type->toCBuffer(buf, ident, &hgs);
+	}
+	else
+	    buf->writestring(ident->toChars());
+	buf->writestring(";\n");
+    }
+}
+
+
+void AliasDeclaration::toDocBuffer(OutBuffer *buf)
+{
+    //printf("AliasDeclaration::toDocbuffer() %s\n", toChars());
+    if (ident)
+    {
+	if (isDeprecated())
+	    buf->writestring("deprecated ");
+
+	emitProtection(buf, protection);
+	buf->writestring("alias ");
+	buf->writestring(toChars());
+	buf->writestring(";\n");
+    }
+}
+
+
+void TypedefDeclaration::toDocBuffer(OutBuffer *buf)
+{
+    if (ident)
+    {
+	if (isDeprecated())
+	    buf->writestring("deprecated ");
+
+	emitProtection(buf, protection);
+	buf->writestring("typedef ");
+	buf->writestring(toChars());
+	buf->writestring(";\n");
+    }
+}
+
+
+void FuncDeclaration::toDocBuffer(OutBuffer *buf)
+{
+    //printf("FuncDeclaration::toDocbuffer() %s\n", toChars());
+    if (ident)
+    {
+	TemplateDeclaration *td;
+
+	if (parent &&
+	    (td = parent->isTemplateDeclaration()) != NULL &&
+	    td->onemember == this)
+	{   HdrGenState hgs;
+	    unsigned o = buf->offset;
+
+	    hgs.ddoc = 1;
+	    prefix(buf, td);
+	    type->next->toCBuffer(buf, NULL, &hgs);
+	    buf->writeByte(' ');
+	    buf->writestring(ident->toChars());
+	    buf->writeByte('(');
+	    for (int i = 0; i < td->parameters->dim; i++)
+	    {
+		TemplateParameter *tp = (TemplateParameter *)td->parameters->data[i];
+		if (i)
+		    buf->writeByte(',');
+		tp->toCBuffer(buf, &hgs);
+	    }
+	    buf->writeByte(')');
+	    TypeFunction *tf = (TypeFunction *)type;
+	    Argument::argsToCBuffer(buf, &hgs, tf->parameters, tf->varargs);
+	    buf->writestring(";\n");
+
+	    highlightCode(NULL, this, buf, o);
+	}
+	else
+	{
+	    Declaration::toDocBuffer(buf);
+	}
+    }
+}
+
+void CtorDeclaration::toDocBuffer(OutBuffer *buf)
+{
+    HdrGenState hgs;
+
+    buf->writestring("this");
+    Argument::argsToCBuffer(buf, &hgs, arguments, varargs);
+    buf->writestring(";\n");
+}
+
+
+void AggregateDeclaration::toDocBuffer(OutBuffer *buf)
+{
+    if (ident)
+    {
+#if 0
+	emitProtection(buf, protection);
+#endif
+	buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars());
+	buf->writestring(";\n");
+    }
+}
+
+void StructDeclaration::toDocBuffer(OutBuffer *buf)
+{
+    //printf("StructDeclaration::toDocbuffer() %s\n", toChars());
+    if (ident)
+    {
+#if 0
+	emitProtection(buf, protection);
+#endif
+	TemplateDeclaration *td;
+
+	if (parent &&
+	    (td = parent->isTemplateDeclaration()) != NULL &&
+	    td->onemember == this)
+	{   unsigned o = buf->offset;
+	    td->toDocBuffer(buf);
+	    highlightCode(NULL, this, buf, o);
+	}
+	else
+	{
+	    buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars());
+	}
+	buf->writestring(";\n");
+    }
+}
+
+void ClassDeclaration::toDocBuffer(OutBuffer *buf)
+{
+    //printf("ClassDeclaration::toDocbuffer() %s\n", toChars());
+    if (ident)
+    {
+#if 0
+	emitProtection(buf, protection);
+#endif
+	TemplateDeclaration *td;
+
+	if (parent &&
+	    (td = parent->isTemplateDeclaration()) != NULL &&
+	    td->onemember == this)
+	{   unsigned o = buf->offset;
+	    td->toDocBuffer(buf);
+	    highlightCode(NULL, this, buf, o);
+	}
+	else
+	{
+	    buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars());
+	}
+	int any = 0;
+	for (int i = 0; i < baseclasses.dim; i++)
+	{   BaseClass *bc = (BaseClass *)baseclasses.data[i];
+
+	    if (bc->protection == PROTprivate)
+		continue;
+	    if (bc->base && bc->base->ident == Id::Object)
+		continue;
+
+	    if (any)
+		buf->writestring(", ");
+	    else
+	    {	buf->writestring(": ");
+		any = 1;
+	    }
+	    emitProtection(buf, bc->protection);
+	    if (bc->base)
+	    {
+		buf->writestring(bc->base->toPrettyChars());
+	    }
+	    else
+	    {
+		HdrGenState hgs;
+		bc->type->toCBuffer(buf, NULL, &hgs);
+	    }
+	}
+	buf->writestring(";\n");
+    }
+}
+
+
+void EnumDeclaration::toDocBuffer(OutBuffer *buf)
+{
+    if (ident)
+    {
+	buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars());
+	buf->writestring(";\n");
+    }
+}
+
+void EnumMember::toDocBuffer(OutBuffer *buf)
+{
+    if (ident)
+    {
+	buf->writestring(toChars());
+    }
+}
+
+
+/********************************* DocComment *********************************/
+
+DocComment::DocComment()
+{
+    memset(this, 0, sizeof(DocComment));
+}
+
+DocComment *DocComment::parse(Scope *sc, Dsymbol *s, unsigned char *comment)
+{   unsigned idlen;
+
+    if (sc->lastdc && isDitto(comment))
+	return NULL;
+
+    DocComment *dc = new DocComment();
+    if (!comment)
+	return dc;
+
+    dc->parseSections(comment);
+
+    for (int i = 0; i < dc->sections.dim; i++)
+    {	Section *s = (Section *)dc->sections.data[i];
+
+	if (icmp("copyright", s->name, s->namelen) == 0)
+	{
+	    dc->copyright = s;
+	}
+	if (icmp("macros", s->name, s->namelen) == 0)
+	{
+	    dc->macros = s;
+	}
+    }
+
+    sc->lastdc = dc;
+    return dc;
+}
+
+/*****************************************
+ * Parse next paragraph out of *pcomment.
+ * Update *pcomment to point past paragraph.
+ * Returns NULL if no more paragraphs.
+ * If paragraph ends in 'identifier:',
+ * then (*pcomment)[0 .. idlen] is the identifier.
+ */
+
+void DocComment::parseSections(unsigned char *comment)
+{   unsigned char *p;
+    unsigned char *pstart;
+    unsigned char *pend;
+    unsigned char *q;
+    unsigned char *idstart;
+    unsigned idlen;
+
+    unsigned char *name = NULL;
+    unsigned namelen = 0;
+
+    p = comment;
+    while (*p)
+    {
+	p = skipwhitespace(p);
+	pstart = p;
+
+	/* Find end of section, which is ended by one of:
+	 *	'identifier:'
+	 *	'\0'
+	 */
+	idlen = 0;
+	while (1)
+	{
+	    if (isalpha(*p) || *p == '_')
+	    {
+		q = p + 1;
+		while (isalnum(*q) || *q == '_')
+		    q++;
+		if (*q == ':')	// identifier: ends it
+		{   idlen = q - p;
+		    idstart = p;
+		    for (pend = p; pend > pstart; pend--)
+		    {	if (pend[-1] == '\n')
+			    break;
+		    }
+		    p = q + 1;
+		    break;
+		}
+	    }
+	    while (1)
+	    {
+		if (!*p)
+		{   pend = p;
+		    goto L1;
+		}
+		if (*p == '\n')
+		{   p++;
+		    if (*p == '\n' && !summary && !namelen)
+		    {
+			pend = p;
+			p++;
+			goto L1;
+		    }
+		    break;
+		}
+		p++;
+	    }
+	    p = skipwhitespace(p);
+	}
+      L1:
+
+	if (namelen || pstart < pend)
+	{
+	    Section *s;
+	    if (icmp("Params", name, namelen) == 0)
+		s = new ParamSection();
+	    else if (icmp("Macros", name, namelen) == 0)
+		s = new MacroSection();
+	    else
+		s = new Section();
+	    s->name = name;
+	    s->namelen = namelen;
+	    s->body = pstart;
+	    s->bodylen = pend - pstart;
+	    s->nooutput = 0;
+
+	    //printf("Section: '%.*s' = '%.*s'\n", s->namelen, s->name, s->bodylen, s->body);
+
+	    sections.push(s);
+
+	    if (!summary && !namelen)
+		summary = s;
+	}
+
+	if (idlen)
+	{   name = idstart;
+	    namelen = idlen;
+	}
+	else
+	{   name = NULL;
+	    namelen = 0;
+	    if (!*p)
+		break;
+	}
+    }
+}
+
+void DocComment::writeSections(Scope *sc, Dsymbol *s, OutBuffer *buf)
+{
+    //printf("DocComment::writeSections()\n");
+    if (sections.dim)
+    {
+	buf->writestring("$(DDOC_SECTIONS \n");
+	for (int i = 0; i < sections.dim; i++)
+	{   Section *sec = (Section *)sections.data[i];
+
+	    if (sec->nooutput)
+		continue;
+	    //printf("Section: '%.*s' = '%.*s'\n", sec->namelen, sec->name, sec->bodylen, sec->body);
+	    if (sec->namelen || i)
+		sec->write(this, sc, s, buf);
+	    else
+	    {
+		buf->writestring("$(DDOC_SUMMARY ");
+		    unsigned o = buf->offset;
+		    buf->write(sec->body, sec->bodylen);
+		    highlightText(sc, s, buf, o);
+		buf->writestring(")\n");
+	    }
+	}
+	buf->writestring(")\n");
+    }
+    else
+    {
+	buf->writestring("$(DDOC_BLANKLINE)\n");
+    }
+}
+
+/***************************************************
+ */
+
+void Section::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf)
+{
+    if (namelen)
+    {
+	static char *table[] =
+	{	"AUTHORS", "BUGS", "COPYRIGHT", "DATE",
+		"DEPRECATED", "EXAMPLES", "HISTORY", "LICENSE",
+		"RETURNS", "SEE_ALSO", "STANDARDS", "THROWS",
+		"VERSION" };
+
+	for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++)
+	{
+	    if (icmp(table[i], name, namelen) == 0)
+	    {
+		buf->printf("$(DDOC_%s ", table[i]);
+		goto L1;
+	    }
+	}
+
+	buf->writestring("$(DDOC_SECTION ");
+	    // Replace _ characters with spaces
+	    buf->writestring("$(DDOC_SECTION_H ");
+	    for (unsigned u = 0; u < namelen; u++)
+	    {   unsigned char c = name[u];
+		buf->writeByte((c == '_') ? ' ' : c);
+	    }
+	    buf->writestring(":)\n");
+    }
+    else
+    {
+	buf->writestring("$(DDOC_DESCRIPTION ");
+    }
+  L1:
+    unsigned o = buf->offset;
+    buf->write(body, bodylen);
+    highlightText(sc, s, buf, o);
+    buf->writestring(")\n");
+}
+
+/***************************************************
+ */
+
+void ParamSection::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf)
+{
+    unsigned char *p = body;
+    unsigned len = bodylen;
+    unsigned char *pend = p + len;
+
+    unsigned char *tempstart;
+    unsigned templen;
+
+    unsigned char *namestart;
+    unsigned namelen = 0;	// !=0 if line continuation
+
+    unsigned char *textstart;
+    unsigned textlen;
+
+    unsigned o;
+    Argument *arg;
+
+    buf->writestring("$(DDOC_PARAMS \n");
+    while (p < pend)
+    {
+	// Skip to start of macro
+	for (; 1; p++)
+	{
+	    switch (*p)
+	    {
+		case ' ':
+		case '\t':
+		    continue;
+
+		case '\n':
+		    p++;
+		    goto Lcont;
+
+		default:
+		    if (!(isalpha(*p) || *p == '_'))
+		    {
+			if (namelen)
+			    goto Ltext;		// continuation of prev macro
+			goto Lskipline;
+		    }
+		    break;
+	    }
+	    break;
+	}
+	tempstart = p;
+
+	while (isalnum(*p) || *p == '_')
+	    p++;
+	templen = p - tempstart;
+
+	while (*p == ' ' || *p == '\t')
+	    p++;
+
+	if (*p != '=')
+	{   if (namelen)
+		goto Ltext;		// continuation of prev macro
+	    goto Lskipline;
+	}
+	p++;
+
+	if (namelen)
+	{   // Output existing param
+
+	L1:
+	    //printf("param '%.*s' = '%.*s'\n", namelen, namestart, textlen, textstart);
+	    HdrGenState hgs;
+	    buf->writestring("$(DDOC_PARAM_ROW ");
+		buf->writestring("$(DDOC_PARAM_ID ");
+		    o = buf->offset;
+		    arg = isFunctionParameter(s, namestart, namelen);
+		    if (arg && arg->type && arg->ident)
+			arg->type->toCBuffer(buf, arg->ident, &hgs);
+		    else
+			buf->write(namestart, namelen);
+		    highlightCode(sc, s, buf, o);
+		buf->writestring(")\n");
+
+		buf->writestring("$(DDOC_PARAM_DESC ");
+		    o = buf->offset;
+		    buf->write(textstart, textlen);
+		    highlightText(sc, s, buf, o);
+		buf->writestring(")");
+	    buf->writestring(")\n");
+	    namelen = 0;
+	    if (p >= pend)
+		break;
+	}
+
+	namestart = tempstart;
+	namelen = templen;
+
+	while (*p == ' ' || *p == '\t')
+	    p++;
+	textstart = p;
+
+      Ltext:
+	while (*p != '\n')
+	    p++;
+	textlen = p - textstart;
+	p++;
+
+     Lcont:
+	continue;
+
+     Lskipline:
+	// Ignore this line
+	while (*p++ != '\n')
+	    ;
+    }
+    if (namelen)
+	goto L1;		// write out last one
+    buf->writestring(")\n");
+}
+
+/***************************************************
+ */
+
+void MacroSection::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf)
+{
+    //printf("MacroSection::write()\n");
+    DocComment::parseMacros(dc->pescapetable, dc->pmacrotable, body, bodylen);
+}
+
+/************************************************
+ * Parse macros out of Macros: section.
+ * Macros are of the form:
+ *	name1 = value1
+ *
+ *	name2 = value2
+ */
+
+void DocComment::parseMacros(Escape **pescapetable, Macro **pmacrotable, unsigned char *m, unsigned mlen)
+{
+    unsigned char *p = m;
+    unsigned len = mlen;
+    unsigned char *pend = p + len;
+
+    unsigned char *tempstart;
+    unsigned templen;
+
+    unsigned char *namestart;
+    unsigned namelen = 0;	// !=0 if line continuation
+
+    unsigned char *textstart;
+    unsigned textlen;
+
+    while (p < pend)
+    {
+	// Skip to start of macro
+	for (; 1; p++)
+	{
+	    if (p >= pend)
+		goto Ldone;
+	    switch (*p)
+	    {
+		case ' ':
+		case '\t':
+		    continue;
+
+		case '\n':
+		    p++;
+		    goto Lcont;
+
+		default:
+		    if (!(isalpha(*p) || *p == '_'))
+		    {
+			if (namelen)
+			    goto Ltext;		// continuation of prev macro
+			goto Lskipline;
+		    }
+		    break;
+	    }
+	    break;
+	}
+	tempstart = p;
+
+	while (1)
+	{
+	    if (p >= pend)
+		goto Ldone;
+	    if (!(isalnum(*p) || *p == '_'))
+		break;
+	    p++;
+	}
+	templen = p - tempstart;
+
+	while (1)
+	{
+	    if (p >= pend)
+		goto Ldone;
+	    if (!(*p == ' ' || *p == '\t'))
+		break;
+	    p++;
+	}
+
+	if (*p != '=')
+	{   if (namelen)
+		goto Ltext;		// continuation of prev macro
+	    goto Lskipline;
+	}
+	p++;
+	if (p >= pend)
+	    goto Ldone;
+
+	if (namelen)
+	{   // Output existing macro
+	L1:
+	    //printf("macro '%.*s' = '%.*s'\n", namelen, namestart, textlen, textstart);
+	    if (icmp("ESCAPES", namestart, namelen) == 0)
+		parseEscapes(pescapetable, textstart, textlen);
+	    else
+		Macro::define(pmacrotable, namestart, namelen, textstart, textlen);
+	    namelen = 0;
+	    if (p >= pend)
+		break;
+	}
+
+	namestart = tempstart;
+	namelen = templen;
+
+	while (p < pend && (*p == ' ' || *p == '\t'))
+	    p++;
+	textstart = p;
+
+      Ltext:
+	while (p < pend && *p != '\n')
+	    p++;
+	textlen = p - textstart;
+
+	// Remove trailing \r if there is one
+	if (p > m && p[-1] == '\r')
+	    textlen--;
+
+	p++;
+	//printf("p = %p, pend = %p\n", p, pend);
+
+     Lcont:
+	continue;
+
+     Lskipline:
+	// Ignore this line
+	while (p < pend && *p++ != '\n')
+	    ;
+    }
+Ldone:
+    if (namelen)
+	goto L1;		// write out last one
+}
+
+/**************************************
+ * Parse escapes of the form:
+ *	/c/string/
+ * where c is a single character.
+ * Multiple escapes can be separated
+ * by whitespace and/or commas.
+ */
+
+void DocComment::parseEscapes(Escape **pescapetable, unsigned char *textstart, unsigned textlen)
+{   Escape *escapetable = *pescapetable;
+
+    if (!escapetable)
+    {	escapetable = new Escape;
+	*pescapetable = escapetable;
+    }
+    unsigned char *p = textstart;
+    unsigned char *pend = p + textlen;
+
+    while (1)
+    {
+	while (1)
+	{
+	    if (p + 4 >= pend)
+		return;
+	    if (!(*p == ' ' || *p == '\t' || *p == '\n' || *p == ','))
+		break;
+	    p++;
+	}
+	if (p[0] != '/' || p[2] != '/')
+	    return;
+	unsigned char c = p[1];
+	p += 3;
+	unsigned char *start = p;
+	while (1)
+	{
+	    if (p >= pend)
+		return;
+	    if (*p == '/')
+		break;
+	    p++;
+	}
+	size_t len = p - start;
+	char *s = (char *)memcpy(mem.malloc(len + 1), start, len);
+	s[len] = 0;
+	escapetable->strings[c] = s;
+	//printf("%c = '%s'\n", c, s);
+	p++;
+    }
+}
+
+
+/******************************************
+ * Compare 0-terminated string with length terminated string.
+ * Return < 0, ==0, > 0
+ */
+
+int cmp(char *stringz, void *s, size_t slen)
+{
+    size_t len1 = strlen(stringz);
+
+    if (len1 != slen)
+	return len1 - slen;
+    return memcmp(stringz, s, slen);
+}
+
+int icmp(char *stringz, void *s, size_t slen)
+{
+    size_t len1 = strlen(stringz);
+
+    if (len1 != slen)
+	return len1 - slen;
+    return memicmp(stringz, (char *)s, slen);
+}
+
+/*****************************************
+ * Return !=0 if comment consists entirely of "ditto".
+ */
+
+int isDitto(unsigned char *comment)
+{
+    if (comment)
+    {
+	unsigned char *p = skipwhitespace(comment);
+
+	if (memicmp((char *)p, "ditto", 5) == 0 && *skipwhitespace(p + 5) == 0)
+	    return 1;
+    }
+    return 0;
+}
+
+/**********************************************
+ * Skip white space.
+ */
+
+unsigned char *skipwhitespace(unsigned char *p)
+{
+    for (; 1; p++)
+    {	switch (*p)
+	{
+	    case ' ':
+	    case '\t':
+	    case '\n':
+		continue;
+	}
+	break;
+    }
+    return p;
+}
+
+
+/************************************************
+ * Scan forward to one of:
+ *	start of identifier
+ *	beginning of next line
+ *	end of buf
+ */
+
+unsigned skiptoident(OutBuffer *buf, unsigned i)
+{
+    for (; i < buf->offset; i++)
+    {
+	// BUG: handle unicode alpha's
+	unsigned char c = buf->data[i];
+	if (isalpha(c) || c == '_')
+	    break;
+	if (c == '\n')
+	    break;
+    }
+    return i;
+}
+
+/************************************************
+ * Scan forward past end of identifier.
+ */
+
+unsigned skippastident(OutBuffer *buf, unsigned i)
+{
+    for (; i < buf->offset; i++)
+    {
+	// BUG: handle unicode alpha's
+	unsigned char c = buf->data[i];
+	if (!(isalnum(c) || c == '_'))
+	    break;
+    }
+    return i;
+}
+
+
+/****************************************************
+ */
+
+int isKeyword(unsigned char *p, unsigned len)
+{
+    static char *table[] = { "true", "false", "null" };
+
+    for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++)
+    {
+	if (cmp(table[i], p, len) == 0)
+	    return 1;
+    }
+    return 0;
+}
+
+/****************************************************
+ */
+
+Argument *isFunctionParameter(Dsymbol *s, unsigned char *p, unsigned len)
+{
+    FuncDeclaration *f = s->isFuncDeclaration();
+
+    /* f->type may be NULL for template members.
+     */
+    if (f && f->type)
+    {
+	TypeFunction *tf = (TypeFunction *)f->type;
+
+	if (tf->parameters)
+	{
+	    for (size_t k = 0; k < tf->parameters->dim; k++)
+	    {   Argument *arg = (Argument *)tf->parameters->data[k];
+
+		if (arg->ident && cmp(arg->ident->toChars(), p, len) == 0)
+		{
+		    return arg;
+		}
+	    }
+	}
+    }
+    return NULL;
+}
+
+/**************************************************
+ * Highlight text section.
+ */
+
+void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset)
+{
+    //printf("highlightText()\n");
+    char *sid = s->ident->toChars();
+    FuncDeclaration *f = s->isFuncDeclaration();
+    unsigned char *p;
+    char *se;
+
+    int leadingBlank = 1;
+    int inCode = 0;
+    int inComment = 0;			// in <!-- ... --> comment
+    unsigned iCodeStart;		// start of code section
+
+    unsigned iLineStart = offset;
+
+    for (unsigned i = offset; i < buf->offset; i++)
+    {	unsigned char c = buf->data[i];
+
+     Lcont:
+	switch (c)
+	{
+	    case ' ':
+	    case '\t':
+		break;
+
+	    case '\n':
+		if (sc && !inCode && i == iLineStart && i + 1 < buf->offset)	// if "\n\n"
+		{
+		    static char blankline[] = "$(DDOC_BLANKLINE)\n";
+
+		    i = buf->insert(i, blankline, sizeof(blankline) - 1);
+		}
+		leadingBlank = 1;
+		iLineStart = i + 1;
+		break;
+
+	    case '<':
+		leadingBlank = 0;
+		if (inCode)
+		    break;
+		p = &buf->data[i];
+
+		// Skip over comments
+		if (p[1] == '!' && p[2] == '-' && p[3] == '-')
+		{   unsigned j = i + 4;
+		    p += 4;
+		    while (1)
+		    {
+			if (j == buf->offset)
+			    goto L1;
+			if (p[0] == '-' && p[1] == '-' && p[2] == '>')
+			{
+			    i = j + 2;	// place on closing '>'
+			    break;
+			}
+			j++;
+			p++;
+		    }
+		    break;
+		}
+
+		// Skip over HTML tag
+		if (isalpha(p[1]) || (p[1] == '/' && isalpha(p[2])))
+		{   unsigned j = i + 2;
+		    p += 2;
+		    while (1)
+		    {
+			if (j == buf->offset)
+			    goto L1;
+			if (p[0] == '>')
+			{
+			    i = j;	// place on closing '>'
+			    break;
+			}
+			j++;
+			p++;
+		    }
+		    break;
+		}
+
+	    L1:
+		// Replace '<' with '&lt;' character entity
+		se = Escape::escapeChar('<');
+		if (se)
+		{   size_t len = strlen(se);
+		    buf->remove(i, 1);
+		    i = buf->insert(i, se, len);
+		    i--;	// point to ';'
+		}
+		break;
+
+	    case '>':
+		leadingBlank = 0;
+		if (inCode)
+		    break;
+		// Replace '>' with '&gt;' character entity
+		se = Escape::escapeChar('>');
+		if (se)
+		{   size_t len = strlen(se);
+		    buf->remove(i, 1);
+		    i = buf->insert(i, se, len);
+		    i--;	// point to ';'
+		}
+		break;
+
+	    case '&':
+		leadingBlank = 0;
+		if (inCode)
+		    break;
+		p = &buf->data[i];
+		if (p[1] == '#' || isalpha(p[1]))
+		    break;			// already a character entity
+		// Replace '&' with '&amp;' character entity
+		se = Escape::escapeChar('&');
+		if (se)
+		{   size_t len = strlen(se);
+		    buf->remove(i, 1);
+		    i = buf->insert(i, se, len);
+		    i--;	// point to ';'
+		}
+		break;
+
+	    case '-':
+		/* A line beginning with --- delimits a code section.
+		 * inCode tells us if it is start or end of a code section.
+		 */
+		if (leadingBlank)
+		{   int istart = i;
+		    int eollen = 0;
+
+		    leadingBlank = 0;
+		    while (1)
+		    {
+			++i;
+			if (i >= buf->offset)
+			    break;
+			c = buf->data[i];
+			if (c == '\n')
+			{   eollen = 1;
+			    break;
+			}
+			if (c == '\r')
+			{
+			    eollen = 1;
+			    if (i + 1 >= buf->offset)
+				break;
+			    if (buf->data[i + 1] == '\n')
+			    {	eollen = 2;
+				break;
+			    }
+			}
+			// BUG: handle UTF PS and LS too
+			if (c != '-')
+			    goto Lcont;
+		    }
+		    if (i - istart < 3)
+			goto Lcont;
+
+		    // We have the start/end of a code section
+
+		    // Remove the entire --- line, including blanks and \n
+		    buf->remove(iLineStart, i - iLineStart + eollen);
+		    i = iLineStart;
+
+		    if (inCode)
+		    {
+			inCode = 0;
+			// The code section is from iCodeStart to i
+			OutBuffer codebuf;
+
+			codebuf.write(buf->data + iCodeStart, i - iCodeStart);
+			codebuf.writeByte(0);
+			highlightCode2(sc, s, &codebuf, 0);
+			buf->remove(iCodeStart, i - iCodeStart);
+			i = buf->insert(iCodeStart, codebuf.data, codebuf.offset);
+			i = buf->insert(i, ")\n", 2);
+			i--;
+		    }
+		    else
+		    {	static char pre[] = "$(D_CODE \n";
+
+			inCode = 1;
+			i = buf->insert(i, pre, sizeof(pre) - 1);
+			iCodeStart = i;
+			i--;		// place i on >
+		    }
+		}
+		break;
+
+	    default:
+		leadingBlank = 0;
+		if (sc && !inCode && (isalpha(c) || c == '_'))
+		{   unsigned j;
+
+		    j = skippastident(buf, i);
+		    if (j > i)
+		    {
+			if (buf->data[i] == '_')	// leading '_' means no highlight
+			{
+			    buf->remove(i, 1);
+			    i = j - 1;
+			}
+			else
+			{
+			    if (cmp(sid, buf->data + i, j - i) == 0)
+			    {
+				i = buf->bracket(i, "$(DDOC_PSYMBOL ", j, ")") - 1;
+				break;
+			    }
+			    else if (isKeyword(buf->data + i, j - i))
+			    {
+				i = buf->bracket(i, "$(DDOC_KEYWORD ", j, ")") - 1;
+				break;
+			    }
+			    else
+			    {
+				if (f && isFunctionParameter(f, buf->data + i, j - i))
+				{
+				    //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j);
+				    i = buf->bracket(i, "$(DDOC_PARAM ", j, ")") - 1;
+				    break;
+				}
+			    }
+			    i = j - 1;
+			}
+		    }
+		}
+		break;
+	}
+    }
+  Ldone:
+    ;
+}
+
+/**************************************************
+ * Highlight code for DDOC section.
+ */
+
+void highlightCode(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset)
+{
+    char *sid = s->ident->toChars();
+    FuncDeclaration *f = s->isFuncDeclaration();
+
+    //printf("highlightCode(s = '%s', kind = %s)\n", sid, s->kind());
+    for (unsigned i = offset; i < buf->offset; i++)
+    {	unsigned char c = buf->data[i];
+	char *se;
+
+	se = Escape::escapeChar(c);
+	if (se)
+	{
+	    size_t len = strlen(se);
+	    buf->remove(i, 1);
+	    i = buf->insert(i, se, len);
+	    i--;		// point to ';'
+	}
+	else if (isalpha(c) || c == '_')
+	{   unsigned j;
+
+	    j = skippastident(buf, i);
+	    if (j > i)
+	    {
+		if (cmp(sid, buf->data + i, j - i) == 0)
+		{
+		    i = buf->bracket(i, "$(DDOC_PSYMBOL ", j, ")") - 1;
+		    continue;
+		}
+		else if (f)
+		{
+		    if (isFunctionParameter(f, buf->data + i, j - i))
+		    {
+			//printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j);
+			i = buf->bracket(i, "$(DDOC_PARAM ", j, ")") - 1;
+			continue;
+		    }
+		}
+		i = j - 1;
+	    }
+	}
+    }
+}
+
+/****************************************
+ */
+
+void highlightCode3(OutBuffer *buf, unsigned char *p, unsigned char *pend)
+{
+    for (; p < pend; p++)
+    {	char *s = Escape::escapeChar(*p);
+	if (s)
+	    buf->writestring(s);
+	else
+	    buf->writeByte(*p);
+    }
+}
+
+/**************************************************
+ * Highlight code for CODE section.
+ */
+
+
+void highlightCode2(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset)
+{
+    char *sid = s->ident->toChars();
+    FuncDeclaration *f = s->isFuncDeclaration();
+    unsigned errorsave = global.errors;
+    Lexer lex(NULL, buf->data, 0, buf->offset - 1, 0, 1);
+    Token tok;
+    OutBuffer res;
+    unsigned char *lastp = buf->data;
+    char *highlight;
+
+    //printf("highlightCode2('%.*s')\n", buf->offset - 1, buf->data);
+    res.reserve(buf->offset);
+    while (1)
+    {
+	lex.scan(&tok);
+	highlightCode3(&res, lastp, tok.ptr);
+	highlight = NULL;
+	switch (tok.value)
+	{
+	    case TOKidentifier:
+		if (!sc)
+		    break;
+		if (cmp(sid, tok.ptr, lex.p - tok.ptr) == 0)
+		{
+		    highlight = "$(D_PSYMBOL ";
+		    break;
+		}
+		else if (f)
+		{
+		    if (isFunctionParameter(f, tok.ptr, lex.p - tok.ptr))
+		    {
+			//printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j);
+			highlight = "$(D_PARAM ";
+			break;
+		    }
+		}
+		break;
+
+	    case TOKcomment:
+		highlight = "$(D_COMMENT ";
+		break;
+
+	    case TOKstring:
+		highlight = "$(D_STRING ";
+		break;
+
+	    default:
+		if (tok.isKeyword())
+		    highlight = "$(D_KEYWORD ";
+		break;
+	}
+	if (highlight)
+	    res.writestring(highlight);
+	highlightCode3(&res, tok.ptr, lex.p);
+	if (highlight)
+	    res.writeByte(')');
+	if (tok.value == TOKeof)
+	    break;
+	lastp = lex.p;
+    }
+    buf->setsize(offset);
+    buf->write(&res);
+    global.errors = errorsave;
+}
+
+/***************************************
+ * Find character string to replace c with.
+ */
+
+char *Escape::escapeChar(unsigned c)
+{   char *s;
+
+    switch (c)
+    {
+	case '<':
+	    s = "&lt;";
+	    break;
+	case '>':
+	    s = "&gt;";
+	    break;
+	case '&':
+	    s = "&amp;";
+	    break;
+	default:
+	    s = NULL;
+	    break;
+    }
+    return s;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/doc.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,19 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#ifndef DMD_DOC_H
+#define DMD_DOC_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/dsymbol.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,971 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "mem.h"
+
+#include "mars.h"
+#include "dsymbol.h"
+#include "aggregate.h"
+#include "identifier.h"
+#include "module.h"
+#include "mtype.h"
+#include "expression.h"
+#include "statement.h"
+#include "declaration.h"
+#include "id.h"
+#include "scope.h"
+#include "init.h"
+#include "import.h"
+#include "template.h"
+
+#include "../gen/enums.h"
+
+/****************************** Dsymbol ******************************/
+
+Dsymbol::Dsymbol()
+{
+    //printf("Dsymbol::Dsymbol(%p)\n", this);
+    this->ident = NULL;
+    this->c_ident = NULL;
+    this->parent = NULL;
+    this->csym = NULL;
+    this->isym = NULL;
+    this->loc = 0;
+    this->comment = NULL;
+    this->llvmInternal = LLVMnone;
+    this->llvmInternal1 = NULL;
+    this->llvmInternal2 = NULL;
+    this->llvmValue = NULL;
+}
+
+Dsymbol::Dsymbol(Identifier *ident)
+{
+    //printf("Dsymbol::Dsymbol(%p, ident)\n", this);
+    this->ident = ident;
+    this->c_ident = NULL;
+    this->parent = NULL;
+    this->csym = NULL;
+    this->isym = NULL;
+    this->loc = 0;
+    this->comment = NULL;
+    this->llvmInternal = LLVMnone;
+    this->llvmInternal1 = NULL;
+    this->llvmInternal2 = NULL;
+    this->llvmValue = NULL;
+    this->llvmDModule = NULL;
+}
+
+int Dsymbol::equals(Object *o)
+{   Dsymbol *s;
+
+    if (this == o)
+	return TRUE;
+    s = (Dsymbol *)(o);
+    if (s && ident->equals(s->ident))
+	return TRUE;
+    return FALSE;
+}
+
+/**************************************
+ * Copy the syntax.
+ * Used for template instantiations.
+ * If s is NULL, allocate the new object, otherwise fill it in.
+ */
+
+Dsymbol *Dsymbol::syntaxCopy(Dsymbol *s)
+{
+    print();
+    printf("%s %s\n", kind(), toChars());
+    assert(0);
+    return NULL;
+}
+
+/**************************************
+ * Determine if this symbol is only one.
+ * Returns:
+ *	FALSE, *ps = NULL: There are 2 or more symbols
+ *	TRUE,  *ps = NULL: There are zero symbols
+ *	TRUE,  *ps = symbol: The one and only one symbol
+ */
+
+int Dsymbol::oneMember(Dsymbol **ps)
+{
+    //printf("Dsymbol::oneMember()\n");
+    *ps = this;
+    return TRUE;
+}
+
+/*****************************************
+ * Same as Dsymbol::oneMember(), but look at an array of Dsymbols.
+ */
+
+int Dsymbol::oneMembers(Array *members, Dsymbol **ps)
+{
+    //printf("Dsymbol::oneMembers() %d\n", members ? members->dim : 0);
+    Dsymbol *s = NULL;
+
+    if (members)
+    {
+	for (int i = 0; i < members->dim; i++)
+	{   Dsymbol *sx = (Dsymbol *)members->data[i];
+
+	    int x = sx->oneMember(ps);
+	    //printf("\t[%d] kind %s = %d, s = %p\n", i, sx->kind(), x, *ps);
+	    if (!x)
+	    {
+		//printf("\tfalse 1\n");
+		assert(*ps == NULL);
+		return FALSE;
+	    }
+	    if (*ps)
+	    {
+		if (s)			// more than one symbol
+		{   *ps = NULL;
+		    //printf("\tfalse 2\n");
+		    return FALSE;
+		}
+		s = *ps;
+	    }
+	}
+    }
+    *ps = s;		// s is the one symbol, NULL if none
+    //printf("\ttrue\n");
+    return TRUE;
+}
+
+/*****************************************
+ * Is Dsymbol a variable that contains pointers?
+ */
+
+int Dsymbol::hasPointers()
+{
+    //printf("Dsymbol::hasPointers() %s\n", toChars());
+    return 0;
+}
+
+char *Dsymbol::toChars()
+{
+    return ident ? ident->toChars() : (char *)"__anonymous";
+}
+
+char *Dsymbol::toPrettyChars()
+{   Dsymbol *p;
+    char *s;
+    char *q;
+    size_t len;
+
+    //printf("Dsymbol::toPrettyChars() '%s'\n", toChars());
+    if (!parent)
+	return toChars();
+
+    len = 0;
+    for (p = this; p; p = p->parent)
+	len += strlen(p->toChars()) + 1;
+
+    s = (char *)mem.malloc(len);
+    q = s + len - 1;
+    *q = 0;
+    for (p = this; p; p = p->parent)
+    {
+	char *t = p->toChars();
+	len = strlen(t);
+	q -= len;
+	memcpy(q, t, len);
+	if (q == s)
+	    break;
+	q--;
+	*q = '.';
+    }
+    return s;
+}
+
+char *Dsymbol::locToChars()
+{
+    OutBuffer buf;
+    char *p;
+
+    Module *m = getModule();
+
+    if (m && m->srcfile)
+	loc.filename = m->srcfile->toChars();
+    return loc.toChars();
+}
+
+char *Dsymbol::kind()
+{
+    return "symbol";
+}
+
+/*********************************
+ * If this symbol is really an alias for another,
+ * return that other.
+ */
+
+Dsymbol *Dsymbol::toAlias()
+{
+    return this;
+}
+
+Dsymbol *Dsymbol::toParent()
+{
+    return parent ? parent->pastMixin() : NULL;
+}
+
+Dsymbol *Dsymbol::pastMixin()
+{
+    Dsymbol *s = this;
+
+    //printf("Dsymbol::pastMixin() %s\n", toChars());
+    while (s && s->isTemplateMixin())
+	s = s->parent;
+    return s;
+}
+
+/**********************************
+ * Use this instead of toParent() when looking for the
+ * 'this' pointer of the enclosing function/class.
+ */
+
+Dsymbol *Dsymbol::toParent2()
+{
+    Dsymbol *s = parent;
+    while (s && s->isTemplateInstance())
+	s = s->parent;
+    return s;
+}
+
+
+int Dsymbol::isAnonymous()
+{
+    return ident ? 0 : 1;
+}
+
+void Dsymbol::semantic(Scope *sc)
+{
+    error("%p has no semantic routine", this);
+}
+
+void Dsymbol::semantic2(Scope *sc)
+{
+    // Most Dsymbols have no further semantic analysis needed
+}
+
+void Dsymbol::semantic3(Scope *sc)
+{
+    // Most Dsymbols have no further semantic analysis needed
+}
+
+void Dsymbol::inlineScan()
+{
+    // Most Dsymbols have no further semantic analysis needed
+}
+
+Dsymbol *Dsymbol::search(Loc loc, Identifier *ident, int flags)
+{
+    //printf("Dsymbol::search(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars());
+    return NULL;
+}
+
+/***************************************
+ * Search for identifier id as a member of 'this'.
+ * id may be a template instance.
+ * Returns:
+ *	symbol found, NULL if not
+ */
+
+Dsymbol *Dsymbol::searchX(Loc loc, Scope *sc, Identifier *id)
+{
+    //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars());
+    Dsymbol *s = toAlias();
+    Dsymbol *sm;
+
+    switch (id->dyncast())
+    {
+	case DYNCAST_IDENTIFIER:
+	    sm = s->search(loc, id, 0);
+	    break;
+
+	case DYNCAST_DSYMBOL:
+	{   // It's a template instance
+	    //printf("\ttemplate instance id\n");
+	    Dsymbol *st = (Dsymbol *)id;
+	    TemplateInstance *ti = st->isTemplateInstance();
+	    id = ti->name;
+	    sm = s->search(loc, id, 0);
+	    if (!sm)
+	    {   error("template identifier %s is not a member of %s %s",
+		    id->toChars(), s->kind(), s->toChars());
+		return NULL;
+	    }
+	    sm = sm->toAlias();
+	    TemplateDeclaration *td = sm->isTemplateDeclaration();
+	    if (!td)
+	    {
+		error("%s is not a template, it is a %s", id->toChars(), sm->kind());
+		return NULL;
+	    }
+	    ti->tempdecl = td;
+	    if (!ti->semanticdone)
+		ti->semantic(sc);
+	    sm = ti->toAlias();
+	    break;
+	}
+
+	default:
+	    assert(0);
+    }
+    return sm;
+}
+
+int Dsymbol::overloadInsert(Dsymbol *s)
+{
+    //printf("Dsymbol::overloadInsert('%s')\n", s->toChars());
+    return FALSE;
+}
+
+void Dsymbol::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring(toChars());
+}
+
+unsigned Dsymbol::size(Loc loc)
+{
+    error("Dsymbol '%s' has no size\n", toChars());
+    return 0;
+}
+
+int Dsymbol::isforwardRef()
+{
+    return FALSE;
+}
+
+AggregateDeclaration *Dsymbol::isThis()
+{
+    return NULL;
+}
+
+ClassDeclaration *Dsymbol::isClassMember()	// are we a member of a class?
+{
+    Dsymbol *parent = toParent();
+    if (parent && parent->isClassDeclaration())
+	return (ClassDeclaration *)parent;
+    return NULL;
+}
+
+void Dsymbol::defineRef(Dsymbol *s)
+{
+    assert(0);
+}
+
+int Dsymbol::isExport()
+{
+    return FALSE;
+}
+
+int Dsymbol::isImportedSymbol()
+{
+    return FALSE;
+}
+
+int Dsymbol::isDeprecated()
+{
+    return FALSE;
+}
+
+LabelDsymbol *Dsymbol::isLabel()		// is this a LabelDsymbol()?
+{
+    return NULL;
+}
+
+AggregateDeclaration *Dsymbol::isMember()	// is this a member of an AggregateDeclaration?
+{
+    Dsymbol *parent = toParent();
+    return parent ? parent->isAggregateDeclaration() : NULL;
+}
+
+Type *Dsymbol::getType()
+{
+    return NULL;
+}
+
+int Dsymbol::needThis()
+{
+    return FALSE;
+}
+
+int Dsymbol::addMember(Scope *sc, ScopeDsymbol *sd, int memnum)
+{
+    //printf("Dsymbol::addMember('%s')\n", toChars());
+    //printf("Dsymbol::addMember(this = %p, '%s' scopesym = '%s')\n", this, toChars(), sd->toChars());
+    //printf("Dsymbol::addMember(this = %p, '%s' sd = %p, sd->symtab = %p)\n", this, toChars(), sd, sd->symtab);
+    parent = sd;
+    if (!isAnonymous())		// no name, so can't add it to symbol table
+    {
+	if (!sd->symtab->insert(this))	// if name is already defined
+	{
+	    Dsymbol *s2;
+
+	    s2 = sd->symtab->lookup(ident);
+	    if (!s2->overloadInsert(this))
+	    {
+		sd->multiplyDefined(0, this, s2);
+	    }
+	}
+	if (sd->isAggregateDeclaration() || sd->isEnumDeclaration())
+	{
+	    if (ident == Id::__sizeof || ident == Id::alignof || ident == Id::mangleof)
+		error(".%s property cannot be redefined", ident->toChars());
+	}
+	return 1;
+    }
+    return 0;
+}
+
+void Dsymbol::error(const char *format, ...)
+{
+    //printf("Dsymbol::error()\n");
+    if (!global.gag)
+    {
+	char *p = locToChars();
+
+	if (*p)
+	    fprintf(stdmsg, "%s: ", p);
+	mem.free(p);
+
+	if (isAnonymous())
+	    fprintf(stdmsg, "%s ", kind());
+	else
+	    fprintf(stdmsg, "%s %s ", kind(), toPrettyChars());
+
+	va_list ap;
+	va_start(ap, format);
+	vfprintf(stdmsg, format, ap);
+	va_end(ap);
+
+	fprintf(stdmsg, "\n");
+	fflush(stdmsg);
+    }
+    global.errors++;
+
+    //fatal();
+}
+
+void Dsymbol::error(Loc loc, const char *format, ...)
+{
+    if (!global.gag)
+    {
+	char *p = loc.toChars();
+	if (!*p)
+	    p = locToChars();
+
+	if (*p)
+	    fprintf(stdmsg, "%s: ", p);
+	mem.free(p);
+
+	fprintf(stdmsg, "%s %s ", kind(), toPrettyChars());
+
+	va_list ap;
+	va_start(ap, format);
+	vfprintf(stdmsg, format, ap);
+	va_end(ap);
+
+	fprintf(stdmsg, "\n");
+	fflush(stdmsg);
+    }
+
+    global.errors++;
+
+    //fatal();
+}
+
+void Dsymbol::checkDeprecated(Loc loc, Scope *sc)
+{
+    if (!global.params.useDeprecated && isDeprecated())
+    {
+	// Don't complain if we're inside a deprecated symbol's scope
+	for (Dsymbol *sp = sc->parent; sp; sp = sp->parent)
+	{   if (sp->isDeprecated())
+		return;
+	}
+
+	for (; sc; sc = sc->enclosing)
+	{
+	    if (sc->scopesym && sc->scopesym->isDeprecated())
+		return;
+	}
+
+	error(loc, "is deprecated");
+    }
+}
+
+/**********************************
+ * Determine which Module a Dsymbol is in.
+ */
+
+Module *Dsymbol::getModule()
+{
+    Module *m;
+    Dsymbol *s;
+
+    //printf("Dsymbol::getModule()\n");
+    s = this;
+    while (s)
+    {
+	//printf("\ts = '%s'\n", s->toChars());
+	m = s->isModule();
+	if (m)
+	    return m;
+	s = s->parent;
+    }
+    return NULL;
+}
+
+/*************************************
+ */
+
+enum PROT Dsymbol::prot()
+{
+    return PROTpublic;
+}
+
+/*************************************
+ * Do syntax copy of an array of Dsymbol's.
+ */
+
+
+Array *Dsymbol::arraySyntaxCopy(Array *a)
+{
+
+    Array *b = NULL;
+    if (a)
+    {
+	b = a->copy();
+	for (int i = 0; i < b->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)b->data[i];
+
+	    s = s->syntaxCopy(NULL);
+	    b->data[i] = (void *)s;
+	}
+    }
+    return b;
+}
+
+
+/****************************************
+ * Add documentation comment to Dsymbol.
+ * Ignore NULL comments.
+ */
+
+void Dsymbol::addComment(unsigned char *comment)
+{
+//    if (comment)
+//	printf("adding comment '%s' to symbol %p '%s'\n", comment, this, toChars());
+
+    if (!this->comment)
+	this->comment = comment;
+#if 1
+    else if (comment && strcmp((char *)comment, (char *)this->comment))
+    {	// Concatenate the two
+	this->comment = Lexer::combineComments(this->comment, comment);
+    }
+#endif
+}
+
+
+/********************************* ScopeDsymbol ****************************/
+
+ScopeDsymbol::ScopeDsymbol()
+    : Dsymbol()
+{
+    members = NULL;
+    symtab = NULL;
+    imports = NULL;
+    prots = NULL;
+}
+
+ScopeDsymbol::ScopeDsymbol(Identifier *id)
+    : Dsymbol(id)
+{
+    members = NULL;
+    symtab = NULL;
+    imports = NULL;
+    prots = NULL;
+}
+
+Dsymbol *ScopeDsymbol::syntaxCopy(Dsymbol *s)
+{
+    //printf("ScopeDsymbol::syntaxCopy('%s')\n", toChars());
+
+    ScopeDsymbol *sd;
+    if (s)
+	sd = (ScopeDsymbol *)s;
+    else
+	sd = new ScopeDsymbol(ident);
+    sd->members = arraySyntaxCopy(members);
+    return sd;
+}
+
+Dsymbol *ScopeDsymbol::search(Loc loc, Identifier *ident, int flags)
+{   Dsymbol *s;
+    int i;
+
+    //printf("%s->ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident->toChars(), flags);
+    // Look in symbols declared in this module
+    s = symtab ? symtab->lookup(ident) : NULL;
+    if (s)
+    {
+	//printf("\ts = '%s.%s'\n",toChars(),s->toChars());
+    }
+    else if (imports)
+    {
+	// Look in imported modules
+	for (i = 0; i < imports->dim; i++)
+	{   ScopeDsymbol *ss = (ScopeDsymbol *)imports->data[i];
+	    Dsymbol *s2;
+
+	    // If private import, don't search it
+	    if (flags & 1 && prots[i] == PROTprivate)
+		continue;
+
+	    //printf("\tscanning import '%s', prots = %d, isModule = %p, isImport = %p\n", ss->toChars(), prots[i], ss->isModule(), ss->isImport());
+	    s2 = ss->search(loc, ident, ss->isModule() ? 1 : 0);
+	    if (!s)
+		s = s2;
+	    else if (s2 && s != s2)
+	    {
+		if (s->toAlias() == s2->toAlias())
+		{
+		    if (s->isDeprecated())
+			s = s2;
+		}
+		else
+		{
+		    /* Two imports of the same module should be regarded as
+		     * the same.
+		     */
+		    Import *i1 = s->isImport();
+		    Import *i2 = s2->isImport();
+		    if (!(i1 && i2 &&
+			  (i1->mod == i2->mod ||
+			   (!i1->parent->isImport() && !i2->parent->isImport() &&
+			    i1->ident->equals(i2->ident))
+			  )
+			 )
+		       )
+		    {
+			ss->multiplyDefined(loc, s, s2);
+			break;
+		    }
+		}
+	    }
+	}
+	if (s)
+	{
+	    Declaration *d = s->isDeclaration();
+	    if (d && d->protection == PROTprivate && !d->parent->isTemplateMixin())
+		error("%s is private", d->toPrettyChars());
+	}
+    }
+    return s;
+}
+
+void ScopeDsymbol::importScope(ScopeDsymbol *s, enum PROT protection)
+{
+    //printf("%s->ScopeDsymbol::importScope(%s, %d)\n", toChars(), s->toChars(), protection);
+
+    // No circular or redundant import's
+    if (s != this)
+    {
+	if (!imports)
+	    imports = new Array();
+	else
+	{
+	    for (int i = 0; i < imports->dim; i++)
+	    {   ScopeDsymbol *ss;
+
+		ss = (ScopeDsymbol *) imports->data[i];
+		if (ss == s)
+		{
+		    if (protection > prots[i])
+			prots[i] = protection;	// upgrade access
+		    return;
+		}
+	    }
+	}
+	imports->push(s);
+	prots = (unsigned char *)mem.realloc(prots, imports->dim * sizeof(prots[0]));
+	prots[imports->dim - 1] = protection;
+    }
+}
+
+int ScopeDsymbol::isforwardRef()
+{
+    return (members == NULL);
+}
+
+void ScopeDsymbol::defineRef(Dsymbol *s)
+{
+    ScopeDsymbol *ss;
+
+    ss = s->isScopeDsymbol();
+    members = ss->members;
+    ss->members = NULL;
+}
+
+void ScopeDsymbol::multiplyDefined(Loc loc, Dsymbol *s1, Dsymbol *s2)
+{
+#if 0
+    printf("ScopeDsymbol::multiplyDefined()\n");
+    printf("s1 = %p, '%s' kind = '%s', parent = %s\n", s1, s1->toChars(), s1->kind(), s1->parent ? s1->parent->toChars() : "");
+    printf("s2 = %p, '%s' kind = '%s', parent = %s\n", s2, s2->toChars(), s2->kind(), s2->parent ? s2->parent->toChars() : "");
+#endif
+    if (loc.filename)
+    {	::error(loc, "%s at %s conflicts with %s at %s",
+	    s1->toPrettyChars(),
+	    s1->locToChars(),
+	    s2->toPrettyChars(),
+	    s2->locToChars());
+    }
+    else
+    {
+	s1->error(loc, "conflicts with %s %s at %s",
+	    s2->kind(),
+	    s2->toPrettyChars(),
+	    s2->locToChars());
+    }
+}
+
+Dsymbol *ScopeDsymbol::nameCollision(Dsymbol *s)
+{
+    Dsymbol *sprev;
+
+    // Look to see if we are defining a forward referenced symbol
+
+    sprev = symtab->lookup(s->ident);
+    assert(sprev);
+    if (s->equals(sprev))		// if the same symbol
+    {
+	if (s->isforwardRef())		// if second declaration is a forward reference
+	    return sprev;
+	if (sprev->isforwardRef())
+	{
+	    sprev->defineRef(s);	// copy data from s into sprev
+	    return sprev;
+	}
+    }
+    multiplyDefined(0, s, sprev);
+    return sprev;
+}
+
+char *ScopeDsymbol::kind()
+{
+    return "ScopeDsymbol";
+}
+
+
+/****************************** WithScopeSymbol ******************************/
+
+WithScopeSymbol::WithScopeSymbol(WithStatement *withstate)
+    : ScopeDsymbol()
+{
+    this->withstate = withstate;
+}
+
+Dsymbol *WithScopeSymbol::search(Loc loc, Identifier *ident, int flags)
+{
+    // Acts as proxy to the with class declaration
+    return withstate->exp->type->toDsymbol(NULL)->search(loc, ident, 0);
+}
+
+/****************************** ArrayScopeSymbol ******************************/
+
+ArrayScopeSymbol::ArrayScopeSymbol(Expression *e)
+    : ScopeDsymbol()
+{
+    assert(e->op == TOKindex || e->op == TOKslice);
+    exp = e;
+    type = NULL;
+    td = NULL;
+}
+
+ArrayScopeSymbol::ArrayScopeSymbol(TypeTuple *t)
+    : ScopeDsymbol()
+{
+    exp = NULL;
+    type = t;
+    td = NULL;
+}
+
+ArrayScopeSymbol::ArrayScopeSymbol(TupleDeclaration *s)
+    : ScopeDsymbol()
+{
+    exp = NULL;
+    type = NULL;
+    td = s;
+}
+
+Dsymbol *ArrayScopeSymbol::search(Loc loc, Identifier *ident, int flags)
+{
+    //printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident->toChars(), flags);
+    if (ident == Id::length || ident == Id::dollar)
+    {	VarDeclaration **pvar;
+	Expression *ce;
+
+    L1:
+
+	if (td)
+ 	{
+	    VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL);
+	    Expression *e = new IntegerExp(0, td->objects->dim, Type::tsize_t);
+	    v->init = new ExpInitializer(0, e);
+	    v->storage_class |= STCconst;
+	    return v;
+	}
+
+	if (type)
+ 	{
+	    VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL);
+	    Expression *e = new IntegerExp(0, type->arguments->dim, Type::tsize_t);
+	    v->init = new ExpInitializer(0, e);
+	    v->storage_class |= STCconst;
+	    return v;
+	}
+
+	if (exp->op == TOKindex)
+	{
+	    IndexExp *ie = (IndexExp *)exp;
+
+	    pvar = &ie->lengthVar;
+	    ce = ie->e1;
+	}
+	else if (exp->op == TOKslice)
+	{
+	    SliceExp *se = (SliceExp *)exp;
+
+	    pvar = &se->lengthVar;
+	    ce = se->e1;
+	}
+	else
+	    return NULL;
+
+	if (ce->op == TOKtype)
+	{
+	    Type *t = ((TypeExp *)ce)->type;
+	    if (t->ty == Ttuple)
+	    {	type = (TypeTuple *)t;
+		goto L1;
+	    }
+	}
+
+	if (!*pvar)
+	{
+	    VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL);
+
+	    if (ce->op == TOKstring)
+	    {	/* It is for a string literal, so the
+		 * length will be a const.
+		 */
+		Expression *e = new IntegerExp(0, ((StringExp *)ce)->len, Type::tsize_t);
+		v->init = new ExpInitializer(0, e);
+		v->storage_class |= STCconst;
+	    }
+	    else if (ce->op == TOKarrayliteral)
+	    {	/* It is for an array literal, so the
+		 * length will be a const.
+		 */
+		Expression *e = new IntegerExp(0, ((ArrayLiteralExp *)ce)->elements->dim, Type::tsize_t);
+		v->init = new ExpInitializer(0, e);
+		v->storage_class |= STCconst;
+	    }
+	    else if (ce->op == TOKtuple)
+	    {	/* It is for an expression tuple, so the
+		 * length will be a const.
+		 */
+		Expression *e = new IntegerExp(0, ((TupleExp *)ce)->exps->dim, Type::tsize_t);
+		v->init = new ExpInitializer(0, e);
+		v->storage_class |= STCconst;
+	    }
+	    *pvar = v;
+	}
+	return (*pvar);
+    }
+    return NULL;
+}
+
+
+/****************************** DsymbolTable ******************************/
+
+DsymbolTable::DsymbolTable()
+{
+    tab = new StringTable;
+}
+
+DsymbolTable::~DsymbolTable()
+{
+    delete tab;
+}
+
+Dsymbol *DsymbolTable::lookup(Identifier *ident)
+{   StringValue *sv;
+
+#ifdef DEBUG
+    assert(ident);
+    assert(tab);
+#endif
+    sv = tab->lookup((char*)ident->string, ident->len);
+    return (Dsymbol *)(sv ? sv->ptrvalue : NULL);
+}
+
+Dsymbol *DsymbolTable::insert(Dsymbol *s)
+{   StringValue *sv;
+    Identifier *ident;
+
+    //printf("DsymbolTable::insert(this = %p, '%s')\n", this, s->ident->toChars());
+    ident = s->ident;
+#ifdef DEBUG
+    assert(ident);
+    assert(tab);
+#endif
+    sv = tab->insert(ident->toChars(), ident->len);
+    if (!sv)
+	return NULL;		// already in table
+    sv->ptrvalue = s;
+    return s;
+}
+
+Dsymbol *DsymbolTable::insert(Identifier *ident, Dsymbol *s)
+{   StringValue *sv;
+
+    //printf("DsymbolTable::insert()\n");
+    sv = tab->insert(ident->toChars(), ident->len);
+    if (!sv)
+	return NULL;		// already in table
+    sv->ptrvalue = s;
+    return s;
+}
+
+Dsymbol *DsymbolTable::update(Dsymbol *s)
+{   StringValue *sv;
+    Identifier *ident;
+
+    ident = s->ident;
+    sv = tab->update(ident->toChars(), ident->len);
+    sv->ptrvalue = s;
+    return s;
+}
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/dsymbol.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,299 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#ifndef DMD_DSYMBOL_H
+#define DMD_DSYMBOL_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include "root.h"
+#include "stringtable.h"
+
+#include "mars.h"
+#include "arraytypes.h"
+
+struct Identifier;
+struct Scope;
+struct DsymbolTable;
+struct Declaration;
+struct TupleDeclaration;
+struct TypedefDeclaration;
+struct AliasDeclaration;
+struct AggregateDeclaration;
+struct EnumDeclaration;
+struct ClassDeclaration;
+struct InterfaceDeclaration;
+struct StructDeclaration;
+struct UnionDeclaration;
+struct FuncDeclaration;
+struct FuncAliasDeclaration;
+struct FuncLiteralDeclaration;
+struct CtorDeclaration;
+struct DtorDeclaration;
+struct StaticCtorDeclaration;
+struct StaticDtorDeclaration;
+struct InvariantDeclaration;
+struct UnitTestDeclaration;
+struct NewDeclaration;
+struct VarDeclaration;
+struct AttribDeclaration;
+struct Symbol;
+struct Package;
+struct Module;
+struct Import;
+struct Type;
+struct TypeTuple;
+struct WithStatement;
+struct LabelDsymbol;
+struct ScopeDsymbol;
+struct TemplateDeclaration;
+struct TemplateInstance;
+struct TemplateMixin;
+struct EnumMember;
+struct ScopeDsymbol;
+struct WithScopeSymbol;
+struct ArrayScopeSymbol;
+struct SymbolDeclaration;
+struct Expression;
+struct DeleteDeclaration;
+struct HdrGenState;
+struct TypeInfoDeclaration;
+
+#if IN_GCC
+union tree_node;
+typedef union tree_node TYPE;
+#else
+struct TYPE;
+#endif
+
+#if IN_LLVM
+namespace llvm
+{
+    class Value;
+}
+#endif
+
+enum PROT
+{
+    PROTundefined,
+    PROTnone,		// no access
+    PROTprivate,
+    PROTpackage,
+    PROTprotected,
+    PROTpublic,
+    PROTexport,
+};
+
+struct Dsymbol : Object
+{
+    Identifier *ident;
+    Identifier *c_ident;
+    Dsymbol *parent;
+    Symbol *csym;		// symbol for code generator
+    Symbol *isym;		// import version of csym
+    unsigned char *comment;	// documentation comment for this Dsymbol
+    Loc loc;			// where defined
+
+    Dsymbol();
+    Dsymbol(Identifier *);
+    char *toChars();
+    char *toPrettyChars();
+    char *locToChars();
+    int equals(Object *o);
+    int isAnonymous();
+    void error(Loc loc, const char *format, ...);
+    void error(const char *format, ...);
+    void checkDeprecated(Loc loc, Scope *sc);
+    Module *getModule();
+    Dsymbol *pastMixin();
+    Dsymbol *toParent();
+    Dsymbol *toParent2();
+
+    int dyncast() { return DYNCAST_DSYMBOL; }	// kludge for template.isSymbol()
+
+    static Array *arraySyntaxCopy(Array *a);
+
+    virtual char *kind();
+    virtual Dsymbol *toAlias();			// resolve real symbol
+    virtual int addMember(Scope *sc, ScopeDsymbol *s, int memnum);
+    virtual void semantic(Scope *sc);
+    virtual void semantic2(Scope *sc);
+    virtual void semantic3(Scope *sc);
+    virtual void inlineScan();
+    virtual Dsymbol *search(Loc loc, Identifier *ident, int flags);
+    Dsymbol *searchX(Loc loc, Scope *sc, Identifier *id);
+    virtual int overloadInsert(Dsymbol *s);
+#ifdef _DH
+    char *toHChars();
+    virtual void toHBuffer(OutBuffer *buf, HdrGenState *hgs);
+#endif
+    virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    virtual void toDocBuffer(OutBuffer *buf);
+    virtual unsigned size(Loc loc);
+    virtual int isforwardRef();
+    virtual void defineRef(Dsymbol *s);
+    virtual AggregateDeclaration *isThis();	// is a 'this' required to access the member
+    virtual ClassDeclaration *isClassMember();	// are we a member of a class?
+    virtual int isExport();			// is Dsymbol exported?
+    virtual int isImportedSymbol();			// is Dsymbol imported?
+    virtual int isDeprecated();			// is Dsymbol deprecated?
+    virtual LabelDsymbol *isLabel();		// is this a LabelDsymbol?
+    virtual AggregateDeclaration *isMember();	// is this symbol a member of an AggregateDeclaration?
+    virtual Type *getType();			// is this a type?
+    virtual char *mangle();
+    virtual int needThis();			// need a 'this' pointer?
+    virtual enum PROT prot();
+    virtual Dsymbol *syntaxCopy(Dsymbol *s);	// copy only syntax trees
+    virtual int oneMember(Dsymbol **ps);
+    static int oneMembers(Array *members, Dsymbol **ps);
+    virtual int hasPointers();
+    virtual void addLocalClass(ClassDeclarations *) { }
+    virtual void checkCtorConstInit() { }
+
+    virtual void addComment(unsigned char *comment);
+    virtual void emitComment(Scope *sc);
+    void emitDitto(Scope *sc);
+
+    // Backend
+
+    virtual Symbol *toSymbol();			// to backend symbol
+    virtual void toObjFile();			// compile to .obj file
+    virtual int cvMember(unsigned char *p);	// emit cv debug info for member
+
+    Symbol *toImport();				// to backend import symbol
+    static Symbol *toImport(Symbol *s);		// to backend import symbol
+
+    Symbol *toSymbolX(const char *prefix, int sclass, TYPE *t, const char *suffix);	// helper
+
+    // Eliminate need for dynamic_cast
+    virtual Package *isPackage() { return NULL; }
+    virtual Module *isModule() { return NULL; }
+    virtual EnumMember *isEnumMember() { return NULL; }
+    virtual TemplateDeclaration *isTemplateDeclaration() { return NULL; }
+    virtual TemplateInstance *isTemplateInstance() { return NULL; }
+    virtual TemplateMixin *isTemplateMixin() { return NULL; }
+    virtual Declaration *isDeclaration() { return NULL; }
+    virtual TupleDeclaration *isTupleDeclaration() { return NULL; }
+    virtual TypedefDeclaration *isTypedefDeclaration() { return NULL; }
+    virtual AliasDeclaration *isAliasDeclaration() { return NULL; }
+    virtual AggregateDeclaration *isAggregateDeclaration() { return NULL; }
+    virtual FuncDeclaration *isFuncDeclaration() { return NULL; }
+    virtual FuncAliasDeclaration *isFuncAliasDeclaration() { return NULL; }
+    virtual FuncLiteralDeclaration *isFuncLiteralDeclaration() { return NULL; }
+    virtual CtorDeclaration *isCtorDeclaration() { return NULL; }
+    virtual DtorDeclaration *isDtorDeclaration() { return NULL; }
+    virtual StaticCtorDeclaration *isStaticCtorDeclaration() { return NULL; }
+    virtual StaticDtorDeclaration *isStaticDtorDeclaration() { return NULL; }
+    virtual InvariantDeclaration *isInvariantDeclaration() { return NULL; }
+    virtual UnitTestDeclaration *isUnitTestDeclaration() { return NULL; }
+    virtual NewDeclaration *isNewDeclaration() { return NULL; }
+    virtual VarDeclaration *isVarDeclaration() { return NULL; }
+    virtual ClassDeclaration *isClassDeclaration() { return NULL; }
+    virtual StructDeclaration *isStructDeclaration() { return NULL; }
+    virtual UnionDeclaration *isUnionDeclaration() { return NULL; }
+    virtual InterfaceDeclaration *isInterfaceDeclaration() { return NULL; }
+    virtual ScopeDsymbol *isScopeDsymbol() { return NULL; }
+    virtual WithScopeSymbol *isWithScopeSymbol() { return NULL; }
+    virtual ArrayScopeSymbol *isArrayScopeSymbol() { return NULL; }
+    virtual Import *isImport() { return NULL; }
+    virtual EnumDeclaration *isEnumDeclaration() { return NULL; }
+#ifdef _DH
+    virtual DeleteDeclaration *isDeleteDeclaration() { return NULL; }
+#endif
+    virtual SymbolDeclaration *isSymbolDeclaration() { return NULL; }
+    virtual AttribDeclaration *isAttribDeclaration() { return NULL; }
+    virtual TypeInfoDeclaration* isTypeInfoDeclaration() { return NULL; }
+    
+    // llvm stuff
+    int llvmInternal;
+    char* llvmInternal1;
+    char* llvmInternal2;
+
+    llvm::Value* llvmValue;
+    Module* llvmDModule;
+};
+
+// Dsymbol that generates a scope
+
+struct ScopeDsymbol : Dsymbol
+{
+    Array *members;		// all Dsymbol's in this scope
+    DsymbolTable *symtab;	// members[] sorted into table
+
+    Array *imports;		// imported ScopeDsymbol's
+    unsigned char *prots;	// PROT for each import
+
+    ScopeDsymbol();
+    ScopeDsymbol(Identifier *id);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    Dsymbol *search(Loc loc, Identifier *ident, int flags);
+    void importScope(ScopeDsymbol *s, enum PROT protection);
+    int isforwardRef();
+    void defineRef(Dsymbol *s);
+    static void multiplyDefined(Loc loc, Dsymbol *s1, Dsymbol *s2);
+    Dsymbol *nameCollision(Dsymbol *s);
+    char *kind();
+
+    void emitMemberComments(Scope *sc);
+
+    ScopeDsymbol *isScopeDsymbol() { return this; }
+};
+
+// With statement scope
+
+struct WithScopeSymbol : ScopeDsymbol
+{
+    WithStatement *withstate;
+
+    WithScopeSymbol(WithStatement *withstate);
+    Dsymbol *search(Loc loc, Identifier *ident, int flags);
+
+    WithScopeSymbol *isWithScopeSymbol() { return this; }
+};
+
+// Array Index/Slice scope
+
+struct ArrayScopeSymbol : ScopeDsymbol
+{
+    Expression *exp;	// IndexExp or SliceExp
+    TypeTuple *type;	// for tuple[length]
+    TupleDeclaration *td;	// for tuples of objects
+
+    ArrayScopeSymbol(Expression *e);
+    ArrayScopeSymbol(TypeTuple *t);
+    ArrayScopeSymbol(TupleDeclaration *td);
+    Dsymbol *search(Loc loc, Identifier *ident, int flags);
+
+    ArrayScopeSymbol *isArrayScopeSymbol() { return this; }
+};
+
+// Table of Dsymbol's
+
+struct DsymbolTable : Object
+{
+    StringTable *tab;
+
+    DsymbolTable();
+    ~DsymbolTable();
+
+    // Look up Identifier. Return Dsymbol if found, NULL if not.
+    Dsymbol *lookup(Identifier *ident);
+
+    // Insert Dsymbol in table. Return NULL if already there.
+    Dsymbol *insert(Dsymbol *s);
+
+    // Look for Dsymbol in table. If there, return it. If not, insert s and return that.
+    Dsymbol *update(Dsymbol *s);
+    Dsymbol *insert(Identifier *ident, Dsymbol *s);	// when ident and s are not the same
+};
+
+#endif /* DMD_DSYMBOL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/dump.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,144 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "mars.h"
+#include "mtype.h"
+#include "declaration.h"
+#include "expression.h"
+#include "template.h"
+
+static void indent(int indent)
+{
+    int i;
+
+    for (i = 0; i < indent; i++)
+	printf(" ");
+}
+
+static char *type_print(Type *type)
+{
+    return type ? type->toChars() : (char *) "null";
+}
+
+void dumpExpressions(int i, Expressions *exps)
+{
+    for (size_t j = 0; j < exps->dim; j++)
+    {	Expression *e = (Expression *)exps->data[j];
+	indent(i);
+	printf("(\n");
+	e->dump(i + 2);
+	indent(i);
+	printf(")\n");
+    }
+}
+
+void Expression::dump(int i)
+{
+    indent(i);
+    printf("%p %s type=%s\n", this, Token::toChars(op), type_print(type));
+}
+
+void IntegerExp::dump(int i)
+{
+    indent(i);
+    printf("%p %jd type=%s\n", this, (intmax_t)value, type_print(type));
+}
+
+void IdentifierExp::dump(int i)
+{
+    indent(i);
+    printf("%p ident '%s' type=%s\n", this, ident->toChars(), type_print(type));
+}
+
+void DsymbolExp::dump(int i)
+{
+    indent(i);
+    printf("%p %s type=%s\n", this, s->toChars(), type_print(type));
+}
+
+void VarExp::dump(int i)
+{
+    indent(i);
+    printf("%p %s var=%s type=%s\n", this, Token::toChars(op), var->toChars(), type_print(type));
+}
+
+void UnaExp::dump(int i)
+{
+    indent(i);
+    printf("%p %s type=%s e1=%p\n", this, Token::toChars(op), type_print(type), e1);
+    if (e1)
+	e1->dump(i + 2);
+}
+
+void CallExp::dump(int i)
+{
+    UnaExp::dump(i);
+    dumpExpressions(i, arguments);
+}
+
+void SliceExp::dump(int i)
+{
+    indent(i);
+    printf("%p %s type=%s e1=%p\n", this, Token::toChars(op), type_print(type), e1);
+    if (e1)
+	e1->dump(i + 2);
+    if (lwr)
+	lwr->dump(i + 2);
+    if (upr)
+	upr->dump(i + 2);
+}
+
+void DotIdExp::dump(int i)
+{
+    indent(i);
+    printf("%p %s type=%s ident=%s e1=%p\n", this, Token::toChars(op), type_print(type), ident->toChars(), e1);
+    if (e1)
+	e1->dump(i + 2);
+}
+
+void DotVarExp::dump(int i)
+{
+    indent(i);
+    printf("%p %s type=%s var='%s' e1=%p\n", this, Token::toChars(op), type_print(type), var->toChars(), e1);
+    if (e1)
+	e1->dump(i + 2);
+}
+
+void DotTemplateInstanceExp::dump(int i)
+{
+    indent(i);
+    printf("%p %s type=%s ti='%s' e1=%p\n", this, Token::toChars(op), type_print(type), ti->toChars(), e1);
+    if (e1)
+	e1->dump(i + 2);
+}
+
+void DelegateExp::dump(int i)
+{
+    indent(i);
+    printf("%p %s func=%s type=%s e1=%p\n", this, Token::toChars(op), func->toChars(), type_print(type), e1);
+    if (e1)
+	e1->dump(i + 2);
+}
+
+void BinExp::dump(int i)
+{
+    indent(i);
+    printf("%p %s type=%s e1=%p e2=%p\n", this, Token::toChars(op), type_print(type), e1, e2);
+    if (e1)
+	e1->dump(i + 2);
+    if (e2)
+	e2->dump(i + 2);
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/entity.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,1366 @@
+
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+
+#include <string.h>
+
+/*********************************************
+ * Convert from named entity to its encoding.
+ * For reference:
+ *	http://www.htmlhelp.com/reference/html40/entities/
+ *	http://www.w3.org/TR/1999/REC-html401-19991224/sgml/entities.html
+ */
+
+struct NameId
+{
+    char *name;
+    unsigned short value;
+};
+
+#if IN_GCC
+static NameId namesA[]={
+	"Aacgr", 	0x0386,
+	"aacgr", 	0x03AC,
+	"Aacute",	0x00C1,
+	"aacute",	0x00E1,
+	"Abreve",	0x0102,
+	"abreve",	0x0103,
+	"Acirc", 	0x00C2,
+	"acirc", 	0x00E2,
+	"acute", 	0x00B4,
+	"Acy",   	0x0410,
+	"acy",   	0x0430,
+	"AElig", 	0x00C6,
+	"aelig", 	0x00E6,
+	"Agr",   	0x0391,
+	"agr",   	0x03B1,
+	"Agrave",	0x00C0,
+	"agrave",	0x00E0,
+	"aleph", 	0x2135,
+	"alpha", 	0x03B1,
+	"Amacr", 	0x0100,
+	"amacr", 	0x0101,
+	"amalg", 	0x2210,
+	"amp",   	0x0026,
+	"and",   	0x2227,
+	"ang",   	0x2220,
+	"ang90", 	0x221F,
+	"angmsd",	0x2221,
+	"angsph",	0x2222,
+	"angst", 	0x212B,
+	"Aogon", 	0x0104,
+	"aogon", 	0x0105,
+	"ap",    	0x2248,
+	"ape",   	0x224A,
+	"apos",  	0x0027,
+	"Aring", 	0x00C5,
+	"aring", 	0x00E5,
+	"ast",   	0x002A,
+	"asymp", 	0x224D,
+	"Atilde",	0x00C3,
+	"atilde",	0x00E3,
+	"Auml",  	0x00C4,
+	"auml",  	0x00E4,
+	NULL,		0
+};
+
+static NameId namesB[]={
+	"barwed",	0x22BC,
+	"Barwed",	0x2306,
+	"bcong", 	0x224C,
+	"Bcy",   	0x0411,
+	"bcy",   	0x0431,
+	"becaus",	0x2235,
+	"bepsi", 	0x220D,
+	"bernou",	0x212C,
+	"beta",  	0x03B2,
+	"beth",  	0x2136,
+	"Bgr",   	0x0392,
+	"bgr",   	0x03B2,
+	"blank", 	0x2423,
+	"blk12", 	0x2592,
+	"blk14", 	0x2591,
+	"blk34", 	0x2593,
+	"block", 	0x2588,
+	"bottom",	0x22A5,
+	"bowtie",	0x22C8,
+	"boxdl", 	0x2510,
+	"boxDL", 	0x2555,
+	"boxdL", 	0x2556,
+	"boxDl", 	0x2557,
+	"boxdr", 	0x250C,
+	"boxDR", 	0x2552,
+	"boxDr", 	0x2553,
+	"boxdR", 	0x2554,
+	"boxh",  	0x2500,
+	"boxH",  	0x2550,
+	"boxhd", 	0x252C,
+	"boxhD", 	0x2564,
+	"boxHD", 	0x2565,
+	"boxHd", 	0x2566,
+	"boxhu", 	0x2534,
+	"boxhU", 	0x2567,
+	"boxHU", 	0x2568,
+	"boxHu", 	0x2569,
+	"boxul", 	0x2518,
+	"boxUL", 	0x255B,
+	"boxUl", 	0x255C,
+	"boxuL", 	0x255D,
+	"boxur", 	0x2514,
+	"boxUR", 	0x2558,
+	"boxuR", 	0x2559,
+	"boxUr", 	0x255A,
+	"boxv",  	0x2502,
+	"boxV",  	0x2551,
+	"boxvh", 	0x253C,
+	"boxvH", 	0x256A,
+	"boxVH", 	0x256B,
+	"boxVh", 	0x256C,
+	"boxvl", 	0x2524,
+	"boxvL", 	0x2561,
+	"boxVL", 	0x2562,
+	"boxVl", 	0x2563,
+	"boxvr", 	0x251C,
+	"boxvR", 	0x255E,
+	"boxVR", 	0x255F,
+	"boxVr", 	0x2560,
+	"bprime",	0x2035,
+	"breve", 	0x02D8,
+	"brvbar",	0x00A6,
+	"bsim",  	0x223D,
+	"bsime", 	0x22CD,
+	"bsol",  	0x005C,
+	"bull",  	0x2022,
+	"bump",  	0x224E,
+	"bumpe", 	0x224F,
+	NULL,		0
+};
+
+static NameId namesC[]={
+	"Cacute",	0x0106,
+	"cacute",	0x0107,
+	"cap",   	0x2229,
+	"Cap",   	0x22D2,
+	"caret", 	0x2041,
+	"caron", 	0x02C7,
+	"Ccaron",	0x010C,
+	"ccaron",	0x010D,
+	"Ccedil",	0x00C7,
+	"ccedil",	0x00E7,
+	"Ccirc", 	0x0108,
+	"ccirc", 	0x0109,
+	"Cdot",  	0x010A,
+	"cdot",  	0x010B,
+	"cedil", 	0x00B8,
+	"cent",  	0x00A2,
+	"CHcy",  	0x0427,
+	"chcy",  	0x0447,
+	"check", 	0x2713,
+	"chi",   	0x03C7,
+	"cir",   	0x25CB,
+	"circ",  	0x005E,
+	"cire",  	0x2257,
+	"clubs", 	0x2663,
+	"colon", 	0x003A,
+	"colone",	0x2254,
+	"comma", 	0x002C,
+	"commat",	0x0040,
+	"comp",  	0x2201,
+	"compfn",	0x2218,
+	"cong",  	0x2245,
+	"conint",	0x222E,
+	"coprod",	0x2210,
+	"copy",  	0x00A9,
+	"copysr",	0x2117,
+	"cross", 	0x2717,
+	"cuepr", 	0x22DE,
+	"cuesc", 	0x22DF,
+	"cularr",	0x21B6,
+	"cup",   	0x222A,
+	"Cup",   	0x22D3,
+	"cupre", 	0x227C,
+	"curarr",	0x21B7,
+	"curren",	0x00A4,
+	"cuvee", 	0x22CE,
+	"cuwed", 	0x22CF,
+	NULL,		0
+};
+
+static NameId namesD[]={
+	"dagger",	0x2020,
+	"Dagger",	0x2021,
+	"daleth",	0x2138,
+	"darr",  	0x2193,
+	"dArr",  	0x21D3,
+	"darr2", 	0x21CA,
+	"dash",  	0x2010,
+	"dashv", 	0x22A3,
+	"dblac", 	0x02DD,
+	"Dcaron",	0x010E,
+	"dcaron",	0x010F,
+	"Dcy",   	0x0414,
+	"dcy",   	0x0434,
+	"deg",   	0x00B0,
+	"Delta", 	0x0394,
+	"delta", 	0x03B4,
+	"Dgr",   	0x0394,
+	"dgr",   	0x03B4,
+	"dharl", 	0x21C3,
+	"dharr", 	0x21C2,
+	"diam",  	0x22C4,
+	"diams", 	0x2666,
+	"die",   	0x00A8,
+	"divide",	0x00F7,
+	"divonx",	0x22C7,
+	"DJcy",  	0x0402,
+	"djcy",  	0x0452,
+	"dlarr", 	0x2199,
+	"dlcorn",	0x231E,
+	"dlcrop",	0x230D,
+	"dollar",	0x0024,
+	"Dot",   	0x00A8,
+	"dot",   	0x02D9,
+	"DotDot",	0x20DC,
+	"drarr", 	0x2198,
+	"drcorn",	0x231F,
+	"drcrop",	0x230C,
+	"DScy",  	0x0405,
+	"dscy",  	0x0455,
+	"Dstrok",	0x0110,
+	"dstrok",	0x0111,
+	"dtri",  	0x25BF,
+	"dtrif", 	0x25BE,
+	"DZcy",  	0x040F,
+	"dzcy",  	0x045F,
+	NULL,		0
+};
+
+static NameId namesE[]={
+	"Eacgr", 	0x0388,
+	"eacgr", 	0x03AD,
+	"Eacute",	0x00C9,
+	"eacute",	0x00E9,
+	"Ecaron",	0x011A,
+	"ecaron",	0x011B,
+	"ecir",  	0x2256,
+	"Ecirc", 	0x00CA,
+	"ecirc", 	0x00EA,
+	"ecolon",	0x2255,
+	"Ecy",   	0x042D,
+	"ecy",   	0x044D,
+	"Edot",  	0x0116,
+	"edot",  	0x0117,
+	"eDot",  	0x2251,
+	"EEacgr",	0x0389,
+	"eeacgr",	0x03AE,
+	"EEgr",  	0x0397,
+	"eegr",  	0x03B7,
+	"efDot", 	0x2252,
+	"Egr",   	0x0395,
+	"egr",   	0x03B5,
+	"Egrave",	0x00C8,
+	"egrave",	0x00E8,
+	"egs",   	0x22DD,
+	"ell",   	0x2113,
+	"els",   	0x22DC,
+	"Emacr", 	0x0112,
+	"emacr", 	0x0113,
+	"empty", 	0x2205,
+	"emsp",  	0x2003,
+	"emsp13",	0x2004,
+	"emsp14",	0x2005,
+	"ENG",   	0x014A,
+	"eng",   	0x014B,
+	"ensp",  	0x2002,
+	"Eogon", 	0x0118,
+	"eogon", 	0x0119,
+	"epsi",  	0x220A,
+	"epsis", 	0x220A,
+	"epsiv", 	0x03B5,
+	"equals",	0x003D,
+	"equiv", 	0x2261,
+	"erDot", 	0x2253,
+	"esdot", 	0x2250,
+	"eta",   	0x03B7,
+	"ETH",   	0x00D0,
+	"eth",   	0x00F0,
+	"Euml",  	0x00CB,
+	"euml",  	0x00EB,
+	"excl",  	0x0021,
+	"exist", 	0x2203,
+	NULL,		0
+};
+
+static NameId namesF[]={
+	"Fcy",   	0x0424,
+	"fcy",   	0x0444,
+	"female",	0x2640,
+	"ffilig",	0xFB03,
+	"fflig", 	0xFB00,
+	"ffllig",	0xFB04,
+	"filig", 	0xFB01,
+	"flat",  	0x266D,
+	"fllig", 	0xFB02,
+	"fnof",  	0x0192,
+	"forall",	0x2200,
+	"fork",  	0x22D4,
+	"frac12",	0x00BD,
+	"frac13",	0x2153,
+	"frac14",	0x00BC,
+	"frac15",	0x2155,
+	"frac16",	0x2159,
+	"frac18",	0x215B,
+	"frac23",	0x2154,
+	"frac25",	0x2156,
+	"frac34",	0x00BE,
+	"frac35",	0x2157,
+	"frac38",	0x215C,
+	"frac45",	0x2158,
+	"frac56",	0x215A,
+	"frac58",	0x215D,
+	"frac78",	0x215E,
+	"frown", 	0x2322,
+	NULL,		0
+};
+
+static NameId namesG[]={
+	"gacute",	0x01F5,
+	"Gamma", 	0x0393,
+	"gamma", 	0x03B3,
+	"gammad",	0x03DC,
+	"gap",   	0x2273,
+	"Gbreve",	0x011E,
+	"gbreve",	0x011F,
+	"Gcedil",	0x0122,
+	"Gcirc", 	0x011C,
+	"gcirc", 	0x011D,
+	"Gcy",   	0x0413,
+	"gcy",   	0x0433,
+	"Gdot",  	0x0120,
+	"gdot",  	0x0121,
+	"ge",    	0x2265,
+	"gE",    	0x2267,
+	"gel",   	0x22DB,
+	"gEl",   	0x22DB,
+	"ges",   	0x2265,
+	"Gg",    	0x22D9,
+	"Ggr",   	0x0393,
+	"ggr",   	0x03B3,
+	"gimel", 	0x2137,
+	"GJcy",  	0x0403,
+	"gjcy",  	0x0453,
+	"gl",    	0x2277,
+	"gnap",  	0xE411,
+	"gne",   	0x2269,
+	"gnE",   	0x2269,
+	"gnsim", 	0x22E7,
+	"grave", 	0x0060,
+	"gsdot", 	0x22D7,
+	"gsim",  	0x2273,
+	"gt",    	0x003E,
+	"Gt",    	0x226B,
+	"gvnE",  	0x2269,
+	NULL,		0
+};
+
+static NameId namesH[]={
+	"hairsp",	0x200A,
+	"half",  	0x00BD,
+	"hamilt",	0x210B,
+	"HARDcy",	0x042A,
+	"hardcy",	0x044A,
+	"harr",  	0x2194,
+	"hArr",  	0x21D4,
+	"harrw", 	0x21AD,
+	"Hcirc", 	0x0124,
+	"hcirc", 	0x0125,
+	"hearts",	0x2665,
+	"hellip",	0x2026,
+	"horbar",	0x2015,
+	"Hstrok",	0x0126,
+	"hstrok",	0x0127,
+	"hybull",	0x2043,
+	"hyphen",	0x002D,
+	NULL,		0
+};
+
+static NameId namesI[]={
+	"Iacgr", 	0x038A,
+	"iacgr", 	0x03AF,
+	"Iacute",	0x00CD,
+	"iacute",	0x00ED,
+	"Icirc", 	0x00CE,
+	"icirc", 	0x00EE,
+	"Icy",   	0x0418,
+	"icy",   	0x0438,
+	"idiagr",	0x0390,
+	"Idigr", 	0x03AA,
+	"idigr", 	0x03CA,
+	"Idot",  	0x0130,
+	"IEcy",  	0x0415,
+	"iecy",  	0x0435,
+	"iexcl", 	0x00A1,
+	"iff",   	0x21D4,
+	"Igr",   	0x0399,
+	"igr",   	0x03B9,
+	"Igrave",	0x00CC,
+	"igrave",	0x00EC,
+	"IJlig", 	0x0132,
+	"ijlig", 	0x0133,
+	"Imacr", 	0x012A,
+	"imacr", 	0x012B,
+	"image", 	0x2111,
+	"incare",	0x2105,
+	"infin", 	0x221E,
+	"inodot",	0x0131,
+	"int",   	0x222B,
+	"intcal",	0x22BA,
+	"IOcy",  	0x0401,
+	"iocy",  	0x0451,
+	"Iogon", 	0x012E,
+	"iogon", 	0x012F,
+	"iota",  	0x03B9,
+	"iquest",	0x00BF,
+	"isin",  	0x220A,
+	"Itilde",	0x0128,
+	"itilde",	0x0129,
+	"Iukcy", 	0x0406,
+	"iukcy", 	0x0456,
+	"Iuml",  	0x00CF,
+	"iuml",  	0x00EF,
+	NULL,		0
+};
+
+static NameId namesJ[]={
+	"Jcirc", 	0x0134,
+	"jcirc", 	0x0135,
+	"Jcy",   	0x0419,
+	"jcy",   	0x0439,
+	"Jsercy",	0x0408,
+	"jsercy",	0x0458,
+	"Jukcy", 	0x0404,
+	"jukcy", 	0x0454,
+	NULL,		0
+};
+
+static NameId namesK[]={
+	"kappa", 	0x03BA,
+	"kappav",	0x03F0,
+	"Kcedil",	0x0136,
+	"kcedil",	0x0137,
+	"Kcy",   	0x041A,
+	"kcy",   	0x043A,
+	"Kgr",   	0x039A,
+	"kgr",   	0x03BA,
+	"kgreen",	0x0138,
+	"KHcy",  	0x0425,
+	"khcy",  	0x0445,
+	"KHgr",  	0x03A7,
+	"khgr",  	0x03C7,
+	"KJcy",  	0x040C,
+	"kjcy",  	0x045C,
+	NULL,		0
+};
+
+static NameId namesL[]={
+	"lAarr", 	0x21DA,
+	"Lacute",	0x0139,
+	"lacute",	0x013A,
+	"lagran",	0x2112,
+	"Lambda",	0x039B,
+	"lambda",	0x03BB,
+	"lang",  	0x3008,
+	"lap",   	0x2272,
+	"laquo", 	0x00AB,
+	"larr",  	0x2190,
+	"Larr",  	0x219E,
+	"lArr",  	0x21D0,
+	"larr2", 	0x21C7,
+	"larrhk",	0x21A9,
+	"larrlp",	0x21AB,
+	"larrtl",	0x21A2,
+	"Lcaron",	0x013D,
+	"lcaron",	0x013E,
+	"Lcedil",	0x013B,
+	"lcedil",	0x013C,
+	"lceil", 	0x2308,
+	"lcub",  	0x007B,
+	"Lcy",   	0x041B,
+	"lcy",   	0x043B,
+	"ldot",  	0x22D6,
+	"ldquo", 	0x201C,
+	"ldquor",	0x201E,
+	"le",    	0x2264,
+	"lE",    	0x2266,
+	"leg",   	0x22DA,
+	"lEg",   	0x22DA,
+	"les",   	0x2264,
+	"lfloor",	0x230A,
+	"lg",    	0x2276,
+	"Lgr",   	0x039B,
+	"lgr",   	0x03BB,
+	"lhard", 	0x21BD,
+	"lharu", 	0x21BC,
+	"lhblk", 	0x2584,
+	"LJcy",  	0x0409,
+	"ljcy",  	0x0459,
+	"Ll",    	0x22D8,
+	"Lmidot",	0x013F,
+	"lmidot",	0x0140,
+	"lnap",  	0xE2A2,
+	"lne",   	0x2268,
+	"lnE",   	0x2268,
+	"lnsim", 	0x22E6,
+	"lowast",	0x2217,
+	"lowbar",	0x005F,
+	"loz",   	0x25CA,
+	"lozf",  	0x2726,
+	"lpar",  	0x0028,
+	"lrarr2",	0x21C6,
+	"lrhar2",	0x21CB,
+	"lsh",   	0x21B0,
+	"lsim",  	0x2272,
+	"lsqb",  	0x005B,
+	"lsquo", 	0x2018,
+	"lsquor",	0x201A,
+	"Lstrok",	0x0141,
+	"lstrok",	0x0142,
+	"lt",    	0x003C,
+	"Lt",    	0x226A,
+	"lthree",	0x22CB,
+	"ltimes",	0x22C9,
+	"ltri",  	0x25C3,
+	"ltrie", 	0x22B4,
+	"ltrif", 	0x25C2,
+	"lvnE",  	0x2268,
+	NULL,		0
+};
+
+static NameId namesM[]={
+	"macr",  	0x00AF,
+	"male",  	0x2642,
+	"malt",  	0x2720,
+	"map",   	0x21A6,
+	"marker",	0x25AE,
+	"Mcy",   	0x041C,
+	"mcy",   	0x043C,
+	"mdash", 	0x2014,
+	"Mgr",   	0x039C,
+	"mgr",   	0x03BC,
+	"micro", 	0x00B5,
+	"mid",   	0x2223,
+	"middot",	0x00B7,
+	"minus", 	0x2212,
+	"minusb",	0x229F,
+	"mldr",  	0x2026,
+	"mnplus",	0x2213,
+	"models",	0x22A7,
+	"mu",    	0x03BC,
+	"mumap", 	0x22B8,
+	NULL,		0
+};
+
+static NameId namesN[]={
+	"nabla", 	0x2207,
+	"Nacute",	0x0143,
+	"nacute",	0x0144,
+	"nap",   	0x2249,
+	"napos", 	0x0149,
+	"natur", 	0x266E,
+//	"nbsp",  	0x00A0,
+	"nbsp",  	32,    // make non-breaking space appear as space
+	"Ncaron",	0x0147,
+	"ncaron",	0x0148,
+	"Ncedil",	0x0145,
+	"ncedil",	0x0146,
+	"ncong", 	0x2247,
+	"Ncy",   	0x041D,
+	"ncy",   	0x043D,
+	"ndash", 	0x2013,
+	"ne",    	0x2260,
+	"nearr", 	0x2197,
+	"nequiv",	0x2262,
+	"nexist",	0x2204,
+	"nge",   	0x2271,
+	"ngE",   	0x2271,
+	"nges",  	0x2271,
+	"Ngr",   	0x039D,
+	"ngr",   	0x03BD,
+	"ngt",   	0x226F,
+	"nharr", 	0x21AE,
+	"nhArr", 	0x21CE,
+	"ni",    	0x220D,
+	"NJcy",  	0x040A,
+	"njcy",  	0x045A,
+	"nlarr", 	0x219A,
+	"nlArr", 	0x21CD,
+	"nldr",  	0x2025,
+	"nle",   	0x2270,
+	"nlE",   	0x2270,
+	"nles",  	0x2270,
+	"nlt",   	0x226E,
+	"nltri", 	0x22EA,
+	"nltrie",	0x22EC,
+	"nmid",  	0x2224,
+	"not",   	0x00AC,
+	"notin", 	0x2209,
+	"npar",  	0x2226,
+	"npr",   	0x2280,
+	"npre",  	0x22E0,
+	"nrarr", 	0x219B,
+	"nrArr", 	0x21CF,
+	"nrtri", 	0x22EB,
+	"nrtrie",	0x22ED,
+	"nsc",   	0x2281,
+	"nsce",  	0x22E1,
+	"nsim",  	0x2241,
+	"nsime", 	0x2244,
+	"nsmid", 	0xE2AA,
+	"nspar", 	0x2226,
+	"nsub",  	0x2284,
+	"nsube", 	0x2288,
+	"nsubE", 	0x2288,
+	"nsup",  	0x2285,
+	"nsupe", 	0x2289,
+	"nsupE", 	0x2289,
+	"Ntilde",	0x00D1,
+	"ntilde",	0x00F1,
+	"nu",    	0x03BD,
+	"num",   	0x0023,
+	"numero",	0x2116,
+	"numsp", 	0x2007,
+	"nvdash",	0x22AC,
+	"nvDash",	0x22AD,
+	"nVdash",	0x22AE,
+	"nVDash",	0x22AF,
+	"nwarr", 	0x2196,
+	NULL,		0
+};
+
+static NameId namesO[]={
+	"Oacgr", 	0x038C,
+	"oacgr", 	0x03CC,
+	"Oacute",	0x00D3,
+	"oacute",	0x00F3,
+	"oast",  	0x229B,
+	"ocir",  	0x229A,
+	"Ocirc", 	0x00D4,
+	"ocirc", 	0x00F4,
+	"Ocy",   	0x041E,
+	"ocy",   	0x043E,
+	"odash", 	0x229D,
+	"Odblac",	0x0150,
+	"odblac",	0x0151,
+	"odot",  	0x2299,
+	"OElig", 	0x0152,
+	"oelig", 	0x0153,
+	"ogon",  	0x02DB,
+	"Ogr",   	0x039F,
+	"ogr",   	0x03BF,
+	"Ograve",	0x00D2,
+	"ograve",	0x00F2,
+	"OHacgr",	0x038F,
+	"ohacgr",	0x03CE,
+	"OHgr",  	0x03A9,
+	"ohgr",  	0x03C9,
+	"ohm",   	0x2126,
+	"olarr", 	0x21BA,
+	"Omacr", 	0x014C,
+	"omacr", 	0x014D,
+	"Omega", 	0x03A9,
+	"omega", 	0x03C9,
+	"ominus",	0x2296,
+	"oplus", 	0x2295,
+	"or",    	0x2228,
+	"orarr", 	0x21BB,
+	"order", 	0x2134,
+	"ordf",  	0x00AA,
+	"ordm",  	0x00BA,
+	"oS",    	0x24C8,
+	"Oslash",	0x00D8,
+	"oslash",	0x00F8,
+	"osol",  	0x2298,
+	"Otilde",	0x00D5,
+	"otilde",	0x00F5,
+	"otimes",	0x2297,
+	"Ouml",  	0x00D6,
+	"ouml",  	0x00F6,
+	NULL,		0
+};
+
+static NameId namesP[]={
+	"par",   	0x2225,
+	"para",  	0x00B6,
+	"part",  	0x2202,
+	"Pcy",   	0x041F,
+	"pcy",   	0x043F,
+	"percnt",	0x0025,
+	"period",	0x002E,
+	"permil",	0x2030,
+	"perp",  	0x22A5,
+	"Pgr",   	0x03A0,
+	"pgr",   	0x03C0,
+	"PHgr",  	0x03A6,
+	"phgr",  	0x03C6,
+	"Phi",   	0x03A6,
+	"phis",  	0x03C6,
+	"phiv",  	0x03D5,
+	"phmmat",	0x2133,
+	"phone", 	0x260E,
+	"Pi",    	0x03A0,
+	"pi",    	0x03C0,
+	"piv",   	0x03D6,
+	"planck",	0x210F,
+	"plus",  	0x002B,
+	"plusb", 	0x229E,
+	"plusdo",	0x2214,
+	"plusmn",	0x00B1,
+	"pound", 	0x00A3,
+	"pr",    	0x227A,
+	"prap",  	0x227E,
+	"pre",   	0x227C,
+	"prime", 	0x2032,
+	"Prime", 	0x2033,
+	"prnap", 	0x22E8,
+	"prnE",  	0xE2B3,
+	"prnsim",	0x22E8,
+	"prod",  	0x220F,
+	"prop",  	0x221D,
+	"prsim", 	0x227E,
+	"PSgr",  	0x03A8,
+	"psgr",  	0x03C8,
+	"Psi",   	0x03A8,
+	"psi",   	0x03C8,
+	"puncsp",	0x2008,
+	NULL,		0
+};
+
+static NameId namesQ[]={
+	"quest", 	0x003F,
+	"quot",  	0x0022,
+	NULL,		0
+};
+
+static NameId namesR[]={
+	"rAarr", 	0x21DB,
+	"Racute",	0x0154,
+	"racute",	0x0155,
+	"radic", 	0x221A,
+	"rang",  	0x3009,
+	"raquo", 	0x00BB,
+	"rarr",  	0x2192,
+	"Rarr",  	0x21A0,
+	"rArr",  	0x21D2,
+	"rarr2", 	0x21C9,
+	"rarrhk",	0x21AA,
+	"rarrlp",	0x21AC,
+	"rarrtl",	0x21A3,
+	"rarrw", 	0x219D,
+	"Rcaron",	0x0158,
+	"rcaron",	0x0159,
+	"Rcedil",	0x0156,
+	"rcedil",	0x0157,
+	"rceil", 	0x2309,
+	"rcub",  	0x007D,
+	"Rcy",   	0x0420,
+	"rcy",   	0x0440,
+	"rdquo", 	0x201D,
+	"rdquor",	0x201C,
+	"real",  	0x211C,
+	"rect",  	0x25AD,
+	"reg",   	0x00AE,
+	"rfloor",	0x230B,
+	"Rgr",   	0x03A1,
+	"rgr",   	0x03C1,
+	"rhard", 	0x21C1,
+	"rharu", 	0x21C0,
+	"rho",   	0x03C1,
+	"rhov",  	0x03F1,
+	"ring",  	0x02DA,
+	"rlarr2",	0x21C4,
+	"rlhar2",	0x21CC,
+	"rpar",  	0x0029,
+	"rpargt",	0xE291,
+	"rsh",   	0x21B1,
+	"rsqb",  	0x005D,
+	"rsquo", 	0x2019,
+	"rsquor",	0x2018,
+	"rthree",	0x22CC,
+	"rtimes",	0x22CA,
+	"rtri",  	0x25B9,
+	"rtrie", 	0x22B5,
+	"rtrif", 	0x25B8,
+	"rx",    	0x211E,
+	NULL,		0
+};
+
+static NameId namesS[]={
+	"Sacute",	0x015A,
+	"sacute",	0x015B,
+	"samalg",	0x2210,
+	"sbsol", 	0xFE68,
+	"sc",    	0x227B,
+	"scap",  	0x227F,
+	"Scaron",	0x0160,
+	"scaron",	0x0161,
+	"sccue", 	0x227D,
+	"sce",   	0x227D,
+	"Scedil",	0x015E,
+	"scedil",	0x015F,
+	"Scirc", 	0x015C,
+	"scirc", 	0x015D,
+	"scnap", 	0x22E9,
+	"scnE",  	0xE2B5,
+	"scnsim",	0x22E9,
+	"scsim", 	0x227F,
+	"Scy",   	0x0421,
+	"scy",   	0x0441,
+	"sdot",  	0x22C5,
+	"sdotb", 	0x22A1,
+	"sect",  	0x00A7,
+	"semi",  	0x003B,
+	"setmn", 	0x2216,
+	"sext",  	0x2736,
+	"sfgr",  	0x03C2,
+	"sfrown",	0x2322,
+	"Sgr",   	0x03A3,
+	"sgr",   	0x03C3,
+	"sharp", 	0x266F,
+	"SHCHcy",	0x0429,
+	"shchcy",	0x0449,
+	"SHcy",  	0x0428,
+	"shcy",  	0x0448,
+	"shy",   	0x00AD,
+	"Sigma", 	0x03A3,
+	"sigma", 	0x03C3,
+	"sigmav",	0x03C2,
+	"sim",   	0x223C,
+	"sime",  	0x2243,
+	"smid",  	0xE301,
+	"smile", 	0x2323,
+	"SOFTcy",	0x042C,
+	"softcy",	0x044C,
+	"sol",   	0x002F,
+	"spades",	0x2660,
+	"spar",  	0x2225,
+	"sqcap", 	0x2293,
+	"sqcup", 	0x2294,
+	"sqsub", 	0x228F,
+	"sqsube",	0x2291,
+	"sqsup", 	0x2290,
+	"sqsupe",	0x2292,
+	"squ",   	0x25A1,
+	"square",	0x25A1,
+	"squf",  	0x25AA,
+	"ssetmn",	0x2216,
+	"ssmile",	0x2323,
+	"sstarf",	0x22C6,
+	"star",  	0x22C6,
+	"starf", 	0x2605,
+	"sub",   	0x2282,
+	"Sub",   	0x22D0,
+	"sube",  	0x2286,
+	"subE",  	0x2286,
+	"subne", 	0x228A,
+	"subnE", 	0x228A,
+	"sum",   	0x2211,
+	"sung",  	0x2669,
+	"sup",   	0x2283,
+	"Sup",   	0x22D1,
+	"sup1",  	0x00B9,
+	"sup2",  	0x00B2,
+	"sup3",  	0x00B3,
+	"supe",  	0x2287,
+	"supE",  	0x2287,
+	"supne", 	0x228B,
+	"supnE", 	0x228B,
+	"szlig", 	0x00DF,
+	NULL,		0
+};
+
+static NameId namesT[]={
+	"target",	0x2316,
+	"tau",   	0x03C4,
+	"Tcaron",	0x0164,
+	"tcaron",	0x0165,
+	"Tcedil",	0x0162,
+	"tcedil",	0x0163,
+	"Tcy",   	0x0422,
+	"tcy",   	0x0442,
+	"tdot",  	0x20DB,
+	"telrec",	0x2315,
+	"Tgr",   	0x03A4,
+	"tgr",   	0x03C4,
+	"there4",	0x2234,
+	"Theta", 	0x0398,
+	"thetas",	0x03B8,
+	"thetav",	0x03D1,
+	"THgr",  	0x0398,
+	"thgr",  	0x03B8,
+	"thinsp",	0x2009,
+	"thkap", 	0x2248,
+	"thksim",	0x223C,
+	"THORN", 	0x00DE,
+	"thorn", 	0x00FE,
+	"tilde", 	0x02DC,
+	"times", 	0x00D7,
+	"timesb",	0x22A0,
+	"top",   	0x22A4,
+	"tprime",	0x2034,
+	"trade", 	0x2122,
+	"trie",  	0x225C,
+	"TScy",  	0x0426,
+	"tscy",  	0x0446,
+	"TSHcy", 	0x040B,
+	"tshcy", 	0x045B,
+	"Tstrok",	0x0166,
+	"tstrok",	0x0167,
+	"twixt", 	0x226C,
+	NULL,		0
+};
+
+static NameId namesU[]={
+	"Uacgr", 	0x038E,
+	"uacgr", 	0x03CD,
+	"Uacute",	0x00DA,
+	"uacute",	0x00FA,
+	"uarr",  	0x2191,
+	"uArr",  	0x21D1,
+	"uarr2", 	0x21C8,
+	"Ubrcy", 	0x040E,
+	"ubrcy", 	0x045E,
+	"Ubreve",	0x016C,
+	"ubreve",	0x016D,
+	"Ucirc", 	0x00DB,
+	"ucirc", 	0x00FB,
+	"Ucy",   	0x0423,
+	"ucy",   	0x0443,
+	"Udblac",	0x0170,
+	"udblac",	0x0171,
+	"udiagr",	0x03B0,
+	"Udigr", 	0x03AB,
+	"udigr", 	0x03CB,
+	"Ugr",   	0x03A5,
+	"ugr",   	0x03C5,
+	"Ugrave",	0x00D9,
+	"ugrave",	0x00F9,
+	"uharl", 	0x21BF,
+	"uharr", 	0x21BE,
+	"uhblk", 	0x2580,
+	"ulcorn",	0x231C,
+	"ulcrop",	0x230F,
+	"Umacr", 	0x016A,
+	"umacr", 	0x016B,
+	"uml",   	0x00A8,
+	"Uogon", 	0x0172,
+	"uogon", 	0x0173,
+	"uplus", 	0x228E,
+	"upsi",  	0x03C5,
+	"Upsi",  	0x03D2,
+	"urcorn",	0x231D,
+	"urcrop",	0x230E,
+	"Uring", 	0x016E,
+	"uring", 	0x016F,
+	"Utilde",	0x0168,
+	"utilde",	0x0169,
+	"utri",  	0x25B5,
+	"utrif", 	0x25B4,
+	"Uuml",  	0x00DC,
+	"uuml",  	0x00FC,
+	NULL,		0
+};
+
+static NameId namesV[]={
+	"varr",  	0x2195,
+	"vArr",  	0x21D5,
+	"Vcy",   	0x0412,
+	"vcy",   	0x0432,
+	"vdash", 	0x22A2,
+	"vDash", 	0x22A8,
+	"Vdash", 	0x22A9,
+	"veebar",	0x22BB,
+	"vellip",	0x22EE,
+	"verbar",	0x007C,
+	"Verbar",	0x2016,
+	"vltri", 	0x22B2,
+	"vprime",	0x2032,
+	"vprop", 	0x221D,
+	"vrtri", 	0x22B3,
+	"vsubne",	0x228A,
+	"vsubnE",	0xE2B8,
+	"vsupne",	0x228B,
+	"vsupnE",	0x228B,
+	"Vvdash",	0x22AA,
+	NULL,		0
+};
+
+static NameId namesW[]={
+	"Wcirc", 	0x0174,
+	"wcirc", 	0x0175,
+	"wedgeq",	0x2259,
+	"weierp",	0x2118,
+	"wreath",	0x2240,
+	NULL,		0
+};
+
+static NameId namesX[]={
+	"xcirc", 	0x25CB,
+	"xdtri", 	0x25BD,
+	"Xgr",   	0x039E,
+	"xgr",   	0x03BE,
+	"xharr", 	0x2194,
+	"xhArr", 	0x2194,
+	"Xi",    	0x039E,
+	"xi",    	0x03BE,
+	"xlArr", 	0x21D0,
+	"xrArr", 	0x21D2,
+	"xutri", 	0x25B3,
+	NULL,		0
+};
+
+static NameId namesY[]={
+	"Yacute",	0x00DD,
+	"yacute",	0x00FD,
+	"YAcy",  	0x042F,
+	"yacy",  	0x044F,
+	"Ycirc", 	0x0176,
+	"ycirc", 	0x0177,
+	"Ycy",   	0x042B,
+	"ycy",   	0x044B,
+	"yen",   	0x00A5,
+	"YIcy",  	0x0407,
+	"yicy",  	0x0457,
+	"YUcy",  	0x042E,
+	"yucy",  	0x044E,
+	"yuml",  	0x00FF,
+	"Yuml",  	0x0178,
+	NULL,		0
+};
+
+static NameId namesZ[]={
+	"Zacute",	0x0179,
+	"zacute",	0x017A,
+	"Zcaron",	0x017D,
+	"zcaron",	0x017E,
+	"Zcy",   	0x0417,
+	"zcy",   	0x0437,
+	"Zdot",  	0x017B,
+	"zdot",  	0x017C,
+	"zeta",  	0x03B6,
+	"Zgr",   	0x0396,
+	"zgr",   	0x03B6,
+	"ZHcy",  	0x0416,
+	"zhcy",  	0x0436,
+	NULL, 0
+};
+
+// @todo@ order namesTable and names? by frequency
+static NameId* namesTable[] = { 
+	namesA, namesB, namesC, namesD, namesE, namesF, namesG, namesH, namesI,
+	namesJ, namesK, namesL, namesM, namesN, namesO, namesP, namesQ, namesR,
+	namesS, namesT, namesU, namesV, namesW, namesX, namesY, namesZ, NULL
+};
+
+int HtmlNamedEntity(unsigned char *p, int length)
+{
+    int tableIndex = tolower(*p) - 'a';
+    if (tableIndex >= 0 && tableIndex < 26) {
+	NameId* names = namesTable[tableIndex];
+	int i;
+
+	for (i = 0; names[i].name; i++){
+		if (strncmp(names[i].name, (char *)p, length) == 0){
+			return names[i].value;
+		}
+	}
+    }
+    error("unrecognized character entity \"%.*s\"", length, p);
+    return -1;
+}
+
+#else //TODO: Merge Walter's list with Thomas'
+
+static NameId names[] =
+{
+    // Entities
+    "quot",	34,
+    "amp",	38,
+    "lt",	60,
+    "gt",	62,
+
+    "OElig",	338,
+    "oelig",	339,
+    "Scaron",	352,
+    "scaron",	353,
+    "Yuml",	376,
+    "circ",	710,
+    "tilde",	732,
+    "ensp",	8194,
+    "emsp",	8195,
+    "thinsp",	8201,
+    "zwnj",	8204,
+    "zwj",	8205,
+    "lrm",	8206,
+    "rlm",	8207,
+    "ndash",	8211,
+    "mdash",	8212,
+    "lsquo",	8216,
+    "rsquo",	8217,
+    "sbquo",	8218,
+    "ldquo",	8220,
+    "rdquo",	8221,
+    "bdquo",	8222,
+    "dagger",	8224,
+    "Dagger",	8225,
+    "permil",	8240,
+    "lsaquo",	8249,
+    "rsaquo",	8250,
+    "euro",	8364,
+
+    // Latin-1 (ISO-8859-1) Entities
+    "nbsp",	160,
+    "iexcl",	161,
+    "cent",	162,
+    "pound",	163,
+    "curren",	164,
+    "yen",	165,
+    "brvbar",	166,
+    "sect",	167,
+    "uml",	168,
+    "copy",	169,
+    "ordf",	170,
+    "laquo",	171,
+    "not",	172,
+    "shy",	173,
+    "reg",	174,
+    "macr",	175,
+    "deg",	176,
+    "plusmn",	177,
+    "sup2",	178,
+    "sup3",	179,
+    "acute",	180,
+    "micro",	181,
+    "para",	182,
+    "middot",	183,
+    "cedil",	184,
+    "sup1",	185,
+    "ordm",	186,
+    "raquo",	187,
+    "frac14",	188,
+    "frac12",	189,
+    "frac34",	190,
+    "iquest",	191,
+    "Agrave",	192,
+    "Aacute",	193,
+    "Acirc",	194,
+    "Atilde",	195,
+    "Auml",	196,
+    "Aring",	197,
+    "AElig",	198,
+    "Ccedil",	199,
+    "Egrave",	200,
+    "Eacute",	201,
+    "Ecirc",	202,
+    "Euml",	203,
+    "Igrave",	204,
+    "Iacute",	205,
+    "Icirc",	206,
+    "Iuml",	207,
+    "ETH",	208,
+    "Ntilde",	209,
+    "Ograve",	210,
+    "Oacute",	211,
+    "Ocirc",	212,
+    "Otilde",	213,
+    "Ouml",	214,
+    "times",	215,
+    "Oslash",	216,
+    "Ugrave",	217,
+    "Uacute",	218,
+    "Ucirc",	219,
+    "Uuml",	220,
+    "Yacute",	221,
+    "THORN",	222,
+    "szlig",	223,
+    "agrave",	224,
+    "aacute",	225,
+    "acirc",	226,
+    "atilde",	227,
+    "auml",	228,
+    "aring",	229,
+    "aelig",	230,
+    "ccedil",	231,
+    "egrave",	232,
+    "eacute",	233,
+    "ecirc",	234,
+    "euml",	235,
+    "igrave",	236,
+    "iacute",	237,
+    "icirc",	238,
+    "iuml",	239,
+    "eth",	240,
+    "ntilde",	241,
+    "ograve",	242,
+    "oacute",	243,
+    "ocirc",	244,
+    "otilde",	245,
+    "ouml",	246,
+    "divide",	247,
+    "oslash",	248,
+    "ugrave",	249,
+    "uacute",	250,
+    "ucirc",	251,
+    "uuml",	252,
+    "yacute",	253,
+    "thorn",	254,
+    "yuml",	255,
+
+	// Symbols and Greek letter entities
+    "fnof",	402,
+    "Alpha",	913,
+    "Beta",	914,
+    "Gamma",	915,
+    "Delta",	916,
+    "Epsilon",	917,
+    "Zeta",	918,
+    "Eta",	919,
+    "Theta",	920,
+    "Iota",	921,
+    "Kappa",	922,
+    "Lambda",	923,
+    "Mu",	924,
+    "Nu",	925,
+    "Xi",	926,
+    "Omicron",	927,
+    "Pi",	928,
+    "Rho",	929,
+    "Sigma",	931,
+    "Tau",	932,
+    "Upsilon",	933,
+    "Phi",	934,
+    "Chi",	935,
+    "Psi",	936,
+    "Omega",	937,
+    "alpha",	945,
+    "beta",	946,
+    "gamma",	947,
+    "delta",	948,
+    "epsilon",	949,
+    "zeta",	950,
+    "eta",	951,
+    "theta",	952,
+    "iota",	953,
+    "kappa",	954,
+    "lambda",	955,
+    "mu",	956,
+    "nu",	957,
+    "xi",	958,
+    "omicron",	959,
+    "pi",	960,
+    "rho",	961,
+    "sigmaf",	962,
+    "sigma",	963,
+    "tau",	964,
+    "upsilon",	965,
+    "phi",	966,
+    "chi",	967,
+    "psi",	968,
+    "omega",	969,
+    "thetasym",	977,
+    "upsih",	978,
+    "piv",	982,
+    "bull",	8226,
+    "hellip",	8230,
+    "prime",	8242,
+    "Prime",	8243,
+    "oline",	8254,
+    "frasl",	8260,
+    "weierp",	8472,
+    "image",	8465,
+    "real",	8476,
+    "trade",	8482,
+    "alefsym",	8501,
+    "larr",	8592,
+    "uarr",	8593,
+    "rarr",	8594,
+    "darr",	8595,
+    "harr",	8596,
+    "crarr",	8629,
+    "lArr",	8656,
+    "uArr",	8657,
+    "rArr",	8658,
+    "dArr",	8659,
+    "hArr",	8660,
+    "forall",	8704,
+    "part",	8706,
+    "exist",	8707,
+    "empty",	8709,
+    "nabla",	8711,
+    "isin",	8712,
+    "notin",	8713,
+    "ni",	8715,
+    "prod",	8719,
+    "sum",	8721,
+    "minus",	8722,
+    "lowast",	8727,
+    "radic",	8730,
+    "prop",	8733,
+    "infin",	8734,
+    "ang",	8736,
+    "and",	8743,
+    "or",	8744,
+    "cap",	8745,
+    "cup",	8746,
+    "int",	8747,
+    "there4",	8756,
+    "sim",	8764,
+    "cong",	8773,
+    "asymp",	8776,
+    "ne",	8800,
+    "equiv",	8801,
+    "le",	8804,
+    "ge",	8805,
+    "sub",	8834,
+    "sup",	8835,
+    "nsub",	8836,
+    "sube",	8838,
+    "supe",	8839,
+    "oplus",	8853,
+    "otimes",	8855,
+    "perp",	8869,
+    "sdot",	8901,
+    "lceil",	8968,
+    "rceil",	8969,
+    "lfloor",	8970,
+    "rfloor",	8971,
+    "lang",	9001,
+    "rang",	9002,
+    "loz",	9674,
+    "spades",	9824,
+    "clubs",	9827,
+    "hearts",	9829,
+    "diams",	9830,
+};
+
+int HtmlNamedEntity(unsigned char *p, int length)
+{
+    int i;
+
+    // BUG: this is a dumb, slow linear search
+    for (i = 0; i < sizeof(names) / sizeof(names[0]); i++)
+    {
+	// Entries are case sensitive
+	if (memcmp(names[i].name, (char *)p, length) == 0 &&
+	    !names[i].name[length])
+	    return names[i].value;
+    }
+    return -1;
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/enum.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,314 @@
+
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "root.h"
+#include "enum.h"
+#include "mtype.h"
+#include "scope.h"
+
+/********************************* EnumDeclaration ****************************/
+
+EnumDeclaration::EnumDeclaration(Loc loc, Identifier *id, Type *memtype)
+    : ScopeDsymbol(id)
+{
+    this->loc = loc;
+    type = new TypeEnum(this);
+    this->memtype = memtype;
+    maxval = 0;
+    minval = 0;
+    defaultval = 0;
+    sinit = NULL;
+}
+
+Dsymbol *EnumDeclaration::syntaxCopy(Dsymbol *s)
+{
+    Type *t = NULL;
+    if (memtype)
+	t = memtype->syntaxCopy();
+
+    EnumDeclaration *ed;
+    if (s)
+    {	ed = (EnumDeclaration *)s;
+	ed->memtype = t;
+    }
+    else
+	ed = new EnumDeclaration(loc, ident, t);
+    ScopeDsymbol::syntaxCopy(ed);
+    return ed;
+}
+
+void EnumDeclaration::semantic(Scope *sc)
+{   int i;
+    uinteger_t number;
+    Type *t;
+    Scope *sce;
+
+    //printf("EnumDeclaration::semantic(sd = %p, '%s')\n", sc->scopesym, sc->scopesym->toChars());
+    if (symtab)			// if already done
+	return;
+    if (!memtype)
+	memtype = Type::tint32;
+    parent = sc->scopesym;
+    memtype = memtype->semantic(loc, sc);
+
+    /* Check to see if memtype is forward referenced
+     */
+    if (memtype->ty == Tenum)
+    {	EnumDeclaration *sym = (EnumDeclaration *)memtype->toDsymbol(sc);
+	if (!sym->memtype)
+	{
+	    error("base enum %s is forward referenced", sym->toChars());
+	    memtype = Type::tint32;
+	}
+    }
+
+    if (!memtype->isintegral())
+    {	error("base type must be of integral type, not %s", memtype->toChars());
+	memtype = Type::tint32;
+    }
+
+    t = isAnonymous() ? memtype : type;
+    symtab = new DsymbolTable();
+    sce = sc->push(this);
+    sce->parent = this;
+    number = 0;
+    if (!members)		// enum ident;
+	return;
+    if (members->dim == 0)
+	error("enum %s must have at least one member", toChars());
+    int first = 1;
+    for (i = 0; i < members->dim; i++)
+    {
+	EnumMember *em = ((Dsymbol *)members->data[i])->isEnumMember();
+	Expression *e;
+
+	if (!em)
+	    /* The e->semantic(sce) can insert other symbols, such as
+	     * template instances and function literals.
+	     */
+	    continue;
+
+	//printf("Enum member '%s'\n",em->toChars());
+	e = em->value;
+	if (e)
+	{
+	    assert(e->dyncast() == DYNCAST_EXPRESSION);
+	    e = e->semantic(sce);
+	    e = e->optimize(WANTvalue);
+	    // Need to copy it because we're going to change the type
+	    e = e->copy();
+	    e = e->implicitCastTo(sc, memtype);
+	    e = e->optimize(WANTvalue);
+	    number = e->toInteger();
+	    e->type = t;
+	}
+	else
+	{   // Default is the previous number plus 1
+
+	    // Check for overflow
+	    if (!first)
+	    {
+		switch (t->toBasetype()->ty)
+		{
+		    case Tbool:
+			if (number == 2)	goto Loverflow;
+			break;
+
+		    case Tint8:
+			if (number == 128) goto Loverflow;
+			break;
+
+		    case Tchar:
+		    case Tuns8:
+			if (number == 256) goto Loverflow;
+			break;
+
+		    case Tint16:
+			if (number == 0x8000) goto Loverflow;
+			break;
+
+		    case Twchar:
+		    case Tuns16:
+			if (number == 0x10000) goto Loverflow;
+			break;
+
+		    case Tint32:
+			if (number == 0x80000000) goto Loverflow;
+			break;
+
+		    case Tdchar:
+		    case Tuns32:
+			if (number == 0x100000000LL) goto Loverflow;
+			break;
+
+		    case Tint64:
+			if (number == 0x8000000000000000LL) goto Loverflow;
+			break;
+
+		    case Tuns64:
+			if (number == 0) goto Loverflow;
+			break;
+
+		    Loverflow:
+			error("overflow of enum value");
+			break;
+
+		    default:
+			assert(0);
+		}
+	    }
+	    e = new IntegerExp(em->loc, number, t);
+	}
+	em->value = e;
+
+	// Add to symbol table only after evaluating 'value'
+	if (isAnonymous())
+	{
+	    //sce->enclosing->insert(em);
+	    for (Scope *scx = sce->enclosing; scx; scx = scx->enclosing)
+	    {
+		if (scx->scopesym)
+		{
+		    if (!scx->scopesym->symtab)
+			scx->scopesym->symtab = new DsymbolTable();
+		    em->addMember(sce, scx->scopesym, 1);
+		    break;
+		}
+	    }
+	}
+	else
+	    em->addMember(sc, this, 1);
+
+	if (first)
+	{   first = 0;
+	    defaultval = number;
+	    minval = number;
+	    maxval = number;
+	}
+	else if (memtype->isunsigned())
+	{
+	    if (number < minval)
+		minval = number;
+	    if (number > maxval)
+		maxval = number;
+	}
+	else
+	{
+	    if ((sinteger_t)number < (sinteger_t)minval)
+		minval = number;
+	    if ((sinteger_t)number > (sinteger_t)maxval)
+		maxval = number;
+	}
+
+	number++;
+    }
+    //printf("defaultval = %lld\n", defaultval);
+
+    sce->pop();
+    //members->print();
+}
+
+int EnumDeclaration::oneMember(Dsymbol **ps)
+{
+    if (isAnonymous())
+	return Dsymbol::oneMembers(members, ps);
+    return Dsymbol::oneMember(ps);
+}
+
+void EnumDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{   int i;
+
+    buf->writestring("enum ");
+    if (ident)
+    {	buf->writestring(ident->toChars());
+	buf->writeByte(' ');
+    }
+    if (memtype)
+    {
+	buf->writestring(": ");
+	memtype->toCBuffer(buf, NULL, hgs);
+    }
+    if (!members)
+    {
+	buf->writeByte(';');
+	buf->writenl();
+	return;
+    }
+    buf->writenl();
+    buf->writeByte('{');
+    buf->writenl();
+    for (i = 0; i < members->dim; i++)
+    {
+	EnumMember *em = ((Dsymbol *)members->data[i])->isEnumMember();
+	if (!em)
+	    continue;
+	//buf->writestring("    ");
+	em->toCBuffer(buf, hgs);
+	buf->writeByte(',');
+	buf->writenl();
+    }
+    buf->writeByte('}');
+    buf->writenl();
+}
+
+Type *EnumDeclaration::getType()
+{
+    return type;
+}
+
+char *EnumDeclaration::kind()
+{
+    return "enum";
+}
+
+/********************************* EnumMember ****************************/
+
+EnumMember::EnumMember(Loc loc, Identifier *id, Expression *value)
+    : Dsymbol(id)
+{
+    this->value = value;
+    this->loc = loc;
+}
+
+Dsymbol *EnumMember::syntaxCopy(Dsymbol *s)
+{
+    Expression *e = NULL;
+    if (value)
+	e = value->syntaxCopy();
+
+    EnumMember *em;
+    if (s)
+    {	em = (EnumMember *)s;
+	em->loc = loc;
+	em->value = e;
+    }
+    else
+	em = new EnumMember(loc, ident, e);
+    return em;
+}
+
+void EnumMember::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring(ident->toChars());
+    if (value)
+    {
+	buf->writestring(" = ");
+	value->toCBuffer(buf, hgs);
+    }
+}
+
+char *EnumMember::kind()
+{
+    return "enum member";
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/enum.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,74 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#ifndef DMD_ENUM_H
+#define DMD_ENUM_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include "root.h"
+#include "dsymbol.h"
+
+struct Identifier;
+struct Type;
+struct Expression;
+#ifdef _DH
+struct HdrGenState;
+#endif
+
+
+struct EnumDeclaration : ScopeDsymbol
+{
+    Type *type;			// the TypeEnum
+    Type *memtype;		// type of the members
+    integer_t maxval;
+    integer_t minval;
+    integer_t defaultval;	// default initializer
+
+    EnumDeclaration(Loc loc, Identifier *id, Type *memtype);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    void semantic(Scope *sc);
+    int oneMember(Dsymbol **ps);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    Type *getType();
+    char *kind();
+
+    void emitComment(Scope *sc);
+    void toDocBuffer(OutBuffer *buf);
+
+    EnumDeclaration *isEnumDeclaration() { return this; }
+
+    void toObjFile();			// compile to .obj file
+    void toDebug();
+    int cvMember(unsigned char *p);
+
+    Symbol *sinit;
+    Symbol *toInitializer();
+};
+
+
+struct EnumMember : Dsymbol
+{
+    Expression *value;
+
+    EnumMember(Loc loc, Identifier *id, Expression *value);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    char *kind();
+
+    void emitComment(Scope *sc);
+    void toDocBuffer(OutBuffer *buf);
+
+    EnumMember *isEnumMember() { return this; }
+};
+
+#endif /* DMD_ENUM_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/expression.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,8584 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <assert.h>
+#include <complex>
+#include <math.h>
+
+#if _WIN32 && __DMC__
+extern "C" char * __cdecl __locale_decpoint;
+#endif
+
+#if IN_GCC
+// Issues with using -include total.h (defines integer_t) and then complex.h fails...
+#undef integer_t
+#endif
+
+#ifdef __APPLE__
+#define integer_t dmd_integer_t
+#endif
+
+#if IN_GCC || IN_LLVM
+#include "mem.h"
+#elif _WIN32
+#include "..\root\mem.h"
+#elif linux
+#include "../root/mem.h"
+#endif
+
+//#include "port.h"
+#include "mtype.h"
+#include "init.h"
+#include "expression.h"
+#include "template.h"
+#include "utf.h"
+#include "enum.h"
+#include "scope.h"
+#include "statement.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "import.h"
+#include "id.h"
+#include "dsymbol.h"
+#include "module.h"
+#include "attrib.h"
+#include "hdrgen.h"
+#include "parse.h"
+
+Expression *createTypeInfoArray(Scope *sc, Expression *args[], int dim);
+
+#define LOGSEMANTIC	0
+
+/**********************************
+ * Set operator precedence for each operator.
+ */
+
+// Operator precedence - greater values are higher precedence
+
+enum PREC
+{
+    PREC_zero,
+    PREC_expr,
+    PREC_assign,
+    PREC_cond,
+    PREC_oror,
+    PREC_andand,
+    PREC_or,
+    PREC_xor,
+    PREC_and,
+    PREC_equal,
+    PREC_rel,
+    PREC_shift,
+    PREC_add,
+    PREC_mul,
+    PREC_unary,
+    PREC_primary,
+};
+
+enum PREC precedence[TOKMAX];
+
+void initPrecedence()
+{
+    precedence[TOKimport] = PREC_primary;
+    precedence[TOKidentifier] = PREC_primary;
+    precedence[TOKthis] = PREC_primary;
+    precedence[TOKsuper] = PREC_primary;
+    precedence[TOKint64] = PREC_primary;
+    precedence[TOKfloat64] = PREC_primary;
+    precedence[TOKnull] = PREC_primary;
+    precedence[TOKstring] = PREC_primary;
+    precedence[TOKarrayliteral] = PREC_primary;
+    precedence[TOKtypedot] = PREC_primary;
+    precedence[TOKtypeid] = PREC_primary;
+    precedence[TOKis] = PREC_primary;
+    precedence[TOKassert] = PREC_primary;
+    precedence[TOKfunction] = PREC_primary;
+    precedence[TOKvar] = PREC_primary;
+
+    // post
+    precedence[TOKdotti] = PREC_primary;
+    precedence[TOKdot] = PREC_primary;
+//  precedence[TOKarrow] = PREC_primary;
+    precedence[TOKplusplus] = PREC_primary;
+    precedence[TOKminusminus] = PREC_primary;
+    precedence[TOKcall] = PREC_primary;
+    precedence[TOKslice] = PREC_primary;
+    precedence[TOKarray] = PREC_primary;
+
+    precedence[TOKaddress] = PREC_unary;
+    precedence[TOKstar] = PREC_unary;
+    precedence[TOKneg] = PREC_unary;
+    precedence[TOKuadd] = PREC_unary;
+    precedence[TOKnot] = PREC_unary;
+    precedence[TOKtobool] = PREC_add;
+    precedence[TOKtilde] = PREC_unary;
+    precedence[TOKdelete] = PREC_unary;
+    precedence[TOKnew] = PREC_unary;
+    precedence[TOKcast] = PREC_unary;
+
+    precedence[TOKmul] = PREC_mul;
+    precedence[TOKdiv] = PREC_mul;
+    precedence[TOKmod] = PREC_mul;
+
+    precedence[TOKadd] = PREC_add;
+    precedence[TOKmin] = PREC_add;
+    precedence[TOKcat] = PREC_add;
+
+    precedence[TOKshl] = PREC_shift;
+    precedence[TOKshr] = PREC_shift;
+    precedence[TOKushr] = PREC_shift;
+
+    precedence[TOKlt] = PREC_rel;
+    precedence[TOKle] = PREC_rel;
+    precedence[TOKgt] = PREC_rel;
+    precedence[TOKge] = PREC_rel;
+    precedence[TOKunord] = PREC_rel;
+    precedence[TOKlg] = PREC_rel;
+    precedence[TOKleg] = PREC_rel;
+    precedence[TOKule] = PREC_rel;
+    precedence[TOKul] = PREC_rel;
+    precedence[TOKuge] = PREC_rel;
+    precedence[TOKug] = PREC_rel;
+    precedence[TOKue] = PREC_rel;
+    precedence[TOKin] = PREC_rel;
+
+    precedence[TOKequal] = PREC_equal;
+    precedence[TOKnotequal] = PREC_equal;
+    precedence[TOKidentity] = PREC_equal;
+    precedence[TOKnotidentity] = PREC_equal;
+
+    precedence[TOKand] = PREC_and;
+
+    precedence[TOKxor] = PREC_xor;
+
+    precedence[TOKor] = PREC_or;
+
+    precedence[TOKandand] = PREC_andand;
+
+    precedence[TOKoror] = PREC_oror;
+
+    precedence[TOKquestion] = PREC_cond;
+
+    precedence[TOKassign] = PREC_assign;
+    precedence[TOKaddass] = PREC_assign;
+    precedence[TOKminass] = PREC_assign;
+    precedence[TOKcatass] = PREC_assign;
+    precedence[TOKmulass] = PREC_assign;
+    precedence[TOKdivass] = PREC_assign;
+    precedence[TOKmodass] = PREC_assign;
+    precedence[TOKshlass] = PREC_assign;
+    precedence[TOKshrass] = PREC_assign;
+    precedence[TOKushrass] = PREC_assign;
+    precedence[TOKandass] = PREC_assign;
+    precedence[TOKorass] = PREC_assign;
+    precedence[TOKxorass] = PREC_assign;
+
+    precedence[TOKcomma] = PREC_expr;
+}
+
+/*****************************************
+ * Determine if 'this' is available.
+ * If it is, return the FuncDeclaration that has it.
+ */
+
+FuncDeclaration *hasThis(Scope *sc)
+{   FuncDeclaration *fd;
+    FuncDeclaration *fdthis;
+
+    //printf("hasThis()\n");
+    fdthis = sc->parent->isFuncDeclaration();
+    //printf("fdthis = %p, '%s'\n", fdthis, fdthis ? fdthis->toChars() : "");
+
+    // Go upwards until we find the enclosing member function
+    fd = fdthis;
+    while (1)
+    {
+	if (!fd)
+	{
+	    goto Lno;
+	}
+	if (!fd->isNested())
+	    break;
+
+	Dsymbol *parent = fd->parent;
+	while (parent)
+	{
+	    TemplateInstance *ti = parent->isTemplateInstance();
+	    if (ti)
+		parent = ti->parent;
+	    else
+		break;
+	}
+
+	fd = fd->parent->isFuncDeclaration();
+    }
+
+    if (!fd->isThis())
+    {   //printf("test '%s'\n", fd->toChars());
+	goto Lno;
+    }
+
+    assert(fd->vthis);
+    return fd;
+
+Lno:
+    return NULL;		// don't have 'this' available
+}
+
+
+/***************************************
+ * Pull out any properties.
+ */
+
+Expression *resolveProperties(Scope *sc, Expression *e)
+{
+    //printf("resolveProperties(%s)\n", e->toChars());
+    if (e->type)
+    {
+	Type *t = e->type->toBasetype();
+
+	if (t->ty == Tfunction)
+	{
+	    e = new CallExp(e->loc, e);
+	    e = e->semantic(sc);
+	}
+
+	/* Look for e being a lazy parameter; rewrite as delegate call
+	 */
+	else if (e->op == TOKvar)
+	{   VarExp *ve = (VarExp *)e;
+
+	    if (ve->var->storage_class & STClazy)
+	    {
+		e = new CallExp(e->loc, e);
+		e = e->semantic(sc);
+	    }
+	}
+
+	else if (e->op == TOKdotexp)
+	{
+	    e->error("expression has no value");
+	}
+    }
+    return e;
+}
+
+/******************************
+ * Perform semantic() on an array of Expressions.
+ */
+
+void arrayExpressionSemantic(Expressions *exps, Scope *sc)
+{
+    if (exps)
+    {
+	for (size_t i = 0; i < exps->dim; i++)
+	{   Expression *e = (Expression *)exps->data[i];
+
+	    e = e->semantic(sc);
+	    exps->data[i] = (void *)e;
+	}
+    }
+}
+
+/****************************************
+ * Expand tuples.
+ */
+
+void expandTuples(Expressions *exps)
+{
+    //printf("expandTuples()\n");
+    if (exps)
+    {
+	for (size_t i = 0; i < exps->dim; i++)
+	{   Expression *arg = (Expression *)exps->data[i];
+	    if (!arg)
+		continue;
+
+	    // Look for tuple with 0 members
+	    if (arg->op == TOKtype)
+	    {	TypeExp *e = (TypeExp *)arg;
+		if (e->type->toBasetype()->ty == Ttuple)
+		{   TypeTuple *tt = (TypeTuple *)e->type->toBasetype();
+
+		    if (!tt->arguments || tt->arguments->dim == 0)
+		    {
+			exps->remove(i);
+			if (i == exps->dim)
+			    return;
+			i--;
+			continue;
+		    }
+		}
+	    }
+
+	    // Inline expand all the tuples
+	    while (arg->op == TOKtuple)
+	    {	TupleExp *te = (TupleExp *)arg;
+
+		exps->remove(i);		// remove arg
+		exps->insert(i, te->exps);	// replace with tuple contents
+		if (i == exps->dim)
+		    return;		// empty tuple, no more arguments
+		arg = (Expression *)exps->data[i];
+	    }
+	}
+    }
+}
+
+/****************************************
+ * Preprocess arguments to function.
+ */
+
+void preFunctionArguments(Loc loc, Scope *sc, Expressions *exps)
+{
+    if (exps)
+    {
+	expandTuples(exps);
+
+	for (size_t i = 0; i < exps->dim; i++)
+	{   Expression *arg = (Expression *)exps->data[i];
+
+	    if (!arg->type)
+	    {
+#ifdef DEBUG
+		if (!global.gag)
+		    printf("1: \n");
+#endif
+		arg->error("%s is not an expression", arg->toChars());
+		arg = new IntegerExp(arg->loc, 0, Type::tint32);
+	    }
+
+	    arg = resolveProperties(sc, arg);
+	    exps->data[i] = (void *) arg;
+
+	    //arg->rvalue();
+#if 0
+	    if (arg->type->ty == Tfunction)
+	    {
+		arg = new AddrExp(arg->loc, arg);
+		arg = arg->semantic(sc);
+		exps->data[i] = (void *) arg;
+	    }
+#endif
+	}
+    }
+}
+
+
+/****************************************
+ * Now that we know the exact type of the function we're calling,
+ * the arguments[] need to be adjusted:
+ *	1) implicitly convert argument to the corresponding parameter type
+ *	2) add default arguments for any missing arguments
+ *	3) do default promotions on arguments corresponding to ...
+ *	4) add hidden _arguments[] argument
+ */
+
+void functionArguments(Loc loc, Scope *sc, TypeFunction *tf, Expressions *arguments)
+{
+    unsigned n;
+    int done;
+    Type *tb;
+
+    //printf("functionArguments()\n");
+    assert(arguments);
+    size_t nargs = arguments ? arguments->dim : 0;
+    size_t nparams = Argument::dim(tf->parameters);
+
+    if (nargs > nparams && tf->varargs == 0)
+	error(loc, "expected %zu arguments, not %zu", nparams, nargs);
+
+    n = (nargs > nparams) ? nargs : nparams;	// n = max(nargs, nparams)
+
+    done = 0;
+    for (size_t i = 0; i < n; i++)
+    {
+	Expression *arg;
+
+	if (i < nargs)
+	    arg = (Expression *)arguments->data[i];
+	else
+	    arg = NULL;
+
+	if (i < nparams)
+	{
+	    Argument *p = Argument::getNth(tf->parameters, i);
+
+	    if (!arg)
+	    {
+		if (!p->defaultArg)
+		{
+		    if (tf->varargs == 2 && i + 1 == nparams)
+			goto L2;
+		    error(loc, "expected %zu arguments, not %zu", nparams, nargs);
+		    break;
+		}
+		arg = p->defaultArg->copy();
+		arguments->push(arg);
+		nargs++;
+	    }
+
+	    if (tf->varargs == 2 && i + 1 == nparams)
+	    {
+		//printf("\t\tvarargs == 2, p->type = '%s'\n", p->type->toChars());
+		if (arg->implicitConvTo(p->type))
+		{
+		    if (nargs != nparams)
+		        error(loc, "expected %zu arguments, not %zu", nparams, nargs);
+		    goto L1;
+		}
+	     L2:
+		Type *tb = p->type->toBasetype();
+		Type *tret = p->isLazyArray();
+		switch (tb->ty)
+		{
+		    case Tsarray:
+		    case Tarray:
+		    {	// Create a static array variable v of type arg->type
+#ifdef IN_GCC
+			/* GCC 4.0 does not like zero length arrays used like
+			   this; pass a null array value instead. Could also
+			   just make a one-element array. */
+			if (nargs - i == 0)
+			{
+			    arg = new NullExp(loc);
+			    break;
+			}
+#endif
+			static int idn;
+			char name[10 + sizeof(idn)*3 + 1];
+			sprintf(name, "__arrayArg%d", ++idn);
+			Identifier *id = Lexer::idPool(name);
+			Type *t = new TypeSArray(tb->next, new IntegerExp(nargs - i));
+			t = t->semantic(loc, sc);
+			VarDeclaration *v = new VarDeclaration(loc, t, id, new VoidInitializer(loc));
+			v->semantic(sc);
+			v->parent = sc->parent;
+			//sc->insert(v);
+
+			Expression *c = new DeclarationExp(0, v);
+			c->type = v->type;
+
+			for (size_t u = i; u < nargs; u++)
+			{   Expression *a = (Expression *)arguments->data[u];
+			    if (tret && !tb->next->equals(a->type))
+				a = a->toDelegate(sc, tret);
+
+			    Expression *e = new VarExp(loc, v);
+			    e = new IndexExp(loc, e, new IntegerExp(u + 1 - nparams));
+			    e = new AssignExp(loc, e, a);
+			    if (c)
+				c = new CommaExp(loc, c, e);
+			    else
+				c = e;
+			}
+			arg = new VarExp(loc, v);
+			if (c)
+			    arg = new CommaExp(loc, c, arg);
+			break;
+		    }
+		    case Tclass:
+		    {	/* Set arg to be:
+			 *	new Tclass(arg0, arg1, ..., argn)
+			 */
+			Expressions *args = new Expressions();
+			args->setDim(nargs - i);
+			for (size_t u = i; u < nargs; u++)
+			    args->data[u - i] = arguments->data[u];
+			arg = new NewExp(loc, NULL, NULL, p->type, args);
+			break;
+		    }
+		    default:
+			if (!arg)
+			{   error(loc, "not enough arguments");
+			    return;
+		        }
+			break;
+		}
+		arg = arg->semantic(sc);
+		//printf("\targ = '%s'\n", arg->toChars());
+		arguments->setDim(i + 1);
+		done = 1;
+	    }
+
+	L1:
+	    if (!(p->storageClass & STClazy && p->type->ty == Tvoid))
+		arg = arg->implicitCastTo(sc, p->type);
+	    if (p->storageClass & (STCout | STCref))
+	    {
+		// BUG: should check that argument to ref is type 'invariant'
+		// BUG: assignments to ref should also be type 'invariant'
+		arg = arg->modifiableLvalue(sc, NULL);
+
+		//if (arg->op == TOKslice)
+		    //arg->error("cannot modify slice %s", arg->toChars());
+	    }
+
+	    // Convert static arrays to pointers
+	    tb = arg->type->toBasetype();
+	    if (tb->ty == Tsarray)
+	    {
+		arg = arg->checkToPointer();
+	    }
+
+	    // Convert lazy argument to a delegate
+	    if (p->storageClass & STClazy)
+	    {
+		arg = arg->toDelegate(sc, p->type);
+	    }
+	}
+	else
+	{
+
+	    // If not D linkage, do promotions
+	    if (tf->linkage != LINKd)
+	    {
+		// Promote bytes, words, etc., to ints
+		arg = arg->integralPromotions(sc);
+
+		// Promote floats to doubles
+		switch (arg->type->ty)
+		{
+		    case Tfloat32:
+			arg = arg->castTo(sc, Type::tfloat64);
+			break;
+
+		    case Timaginary32:
+			arg = arg->castTo(sc, Type::timaginary64);
+			break;
+		}
+	    }
+
+	    // Convert static arrays to dynamic arrays
+	    tb = arg->type->toBasetype();
+	    if (tb->ty == Tsarray)
+	    {	TypeSArray *ts = (TypeSArray *)tb;
+		Type *ta = tb->next->arrayOf();
+		if (ts->size(arg->loc) == 0)
+		{   arg = new NullExp(arg->loc);
+		    arg->type = ta;
+		}
+		else
+		    arg = arg->castTo(sc, ta);
+	    }
+
+	    arg->rvalue();
+	}
+	arg = arg->optimize(WANTvalue);
+	arguments->data[i] = (void *) arg;
+	if (done)
+	    break;
+    }
+
+    // If D linkage and variadic, add _arguments[] as first argument
+    if (tf->linkage == LINKd && tf->varargs == 1)
+    {
+	Expression *e;
+
+	e = createTypeInfoArray(sc, (Expression **)&arguments->data[nparams],
+		arguments->dim - nparams);
+	arguments->insert(0, e);
+    }
+}
+
+/**************************************************
+ * Write expression out to buf, but wrap it
+ * in ( ) if its precedence is less than pr.
+ */
+
+void expToCBuffer(OutBuffer *buf, HdrGenState *hgs, Expression *e, enum PREC pr)
+{
+    if (precedence[e->op] < pr)
+    {
+	buf->writeByte('(');
+	e->toCBuffer(buf, hgs);
+	buf->writeByte(')');
+    }
+    else
+	e->toCBuffer(buf, hgs);
+}
+
+/**************************************************
+ * Write out argument list to buf.
+ */
+
+void argsToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs)
+{
+    if (arguments)
+    {
+	for (size_t i = 0; i < arguments->dim; i++)
+	{   Expression *arg = (Expression *)arguments->data[i];
+
+	    if (i)
+		buf->writeByte(',');
+	    expToCBuffer(buf, hgs, arg, PREC_assign);
+	}
+    }
+}
+
+/**************************************************
+ * Write out argument types to buf.
+ */
+
+void argExpTypesToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs)
+{
+    if (arguments)
+    {	OutBuffer argbuf;
+
+	for (size_t i = 0; i < arguments->dim; i++)
+	{   Expression *arg = (Expression *)arguments->data[i];
+
+	    if (i)
+		buf->writeByte(',');
+	    argbuf.reset();
+	    arg->type->toCBuffer2(&argbuf, NULL, hgs);
+	    buf->write(&argbuf);
+	}
+    }
+}
+
+/******************************** Expression **************************/
+
+Expression::Expression(Loc loc, enum TOK op, int size)
+    : loc(loc)
+{
+    this->loc = loc;
+    this->op = op;
+    this->size = size;
+    type = NULL;
+}
+
+Expression *Expression::syntaxCopy()
+{
+    //printf("Expression::syntaxCopy()\n");
+    //dump(0);
+    return copy();
+}
+
+/*********************************
+ * Does *not* do a deep copy.
+ */
+
+Expression *Expression::copy()
+{
+    Expression *e;
+    if (!size)
+    {
+#ifdef DEBUG
+	fprintf(stdmsg, "No expression copy for: %s\n", toChars());
+	printf("op = %d\n", op);
+	dump(0);
+#endif
+	assert(0);
+    }
+    e = (Expression *)mem.malloc(size);
+    return (Expression *)memcpy(e, this, size);
+}
+
+/**************************
+ * Semantically analyze Expression.
+ * Determine types, fold constants, etc.
+ */
+
+Expression *Expression::semantic(Scope *sc)
+{
+#if LOGSEMANTIC
+    printf("Expression::semantic()\n");
+#endif
+    if (type)
+	type = type->semantic(loc, sc);
+    else
+	type = Type::tvoid;
+    return this;
+}
+
+void Expression::print()
+{
+    fprintf(stdmsg, "%s\n", toChars());
+    fflush(stdmsg);
+}
+
+char *Expression::toChars()
+{   OutBuffer *buf;
+    HdrGenState hgs;
+
+    memset(&hgs, 0, sizeof(hgs));
+    buf = new OutBuffer();
+    toCBuffer(buf, &hgs);
+    return buf->toChars();
+}
+
+void Expression::error(const char *format, ...)
+{
+    va_list ap;
+    va_start(ap, format);
+    ::verror(loc, format, ap);
+    va_end( ap );
+}
+
+void Expression::rvalue()
+{
+    if (type && type->toBasetype()->ty == Tvoid)
+    {	error("expression %s is void and has no value", toChars());
+#if 0
+	dump(0);
+	halt();
+#endif
+    }
+}
+
+Expression *Expression::combine(Expression *e1, Expression *e2)
+{
+    if (e1)
+    {
+	if (e2)
+	{
+	    e1 = new CommaExp(e1->loc, e1, e2);
+	    e1->type = e2->type;
+	}
+    }
+    else
+	e1 = e2;
+    return e1;
+}
+
+integer_t Expression::toInteger()
+{
+    //printf("Expression %s\n", Token::toChars(op));
+    error("Integer constant expression expected instead of %s", toChars());
+    return 0;
+}
+
+uinteger_t Expression::toUInteger()
+{
+    //printf("Expression %s\n", Token::toChars(op));
+    return (uinteger_t)toInteger();
+}
+
+real_t Expression::toReal()
+{
+    error("Floating point constant expression expected instead of %s", toChars());
+    return 0;
+}
+
+real_t Expression::toImaginary()
+{
+    error("Floating point constant expression expected instead of %s", toChars());
+    return 0;
+}
+
+complex_t Expression::toComplex()
+{
+    error("Floating point constant expression expected instead of %s", toChars());
+#ifdef IN_GCC
+    return complex_t(real_t(0)); // %% nicer
+#else
+    return 0;
+#endif
+}
+
+void Expression::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring(Token::toChars(op));
+}
+
+void Expression::toMangleBuffer(OutBuffer *buf)
+{
+    error("expression %s is not a valid template value argument", toChars());
+}
+
+/*******************************
+ * Give error if we're not an lvalue.
+ * If we can, convert expression to be an lvalue.
+ */
+
+Expression *Expression::toLvalue(Scope *sc, Expression *e)
+{
+    if (!e)
+	e = this;
+    else if (!loc.filename)
+	loc = e->loc;
+    error("%s is not an lvalue", e->toChars());
+    return this;
+}
+
+Expression *Expression::modifiableLvalue(Scope *sc, Expression *e)
+{
+    // See if this expression is a modifiable lvalue (i.e. not const)
+    return toLvalue(sc, e);
+}
+
+/************************************
+ * Detect cases where pointers to the stack can 'escape' the
+ * lifetime of the stack frame.
+ */
+
+void Expression::checkEscape()
+{
+}
+
+void Expression::checkScalar()
+{
+    if (!type->isscalar())
+	error("'%s' is not a scalar, it is a %s", toChars(), type->toChars());
+}
+
+void Expression::checkNoBool()
+{
+    if (type->toBasetype()->ty == Tbool)
+	error("operation not allowed on bool '%s'", toChars());
+}
+
+Expression *Expression::checkIntegral()
+{
+    if (!type->isintegral())
+    {	error("'%s' is not of integral type, it is a %s", toChars(), type->toChars());
+	return new IntegerExp(0);
+    }
+    return this;
+}
+
+void Expression::checkArithmetic()
+{
+    if (!type->isintegral() && !type->isfloating())
+	error("'%s' is not an arithmetic type", toChars());
+}
+
+void Expression::checkDeprecated(Scope *sc, Dsymbol *s)
+{
+    s->checkDeprecated(loc, sc);
+}
+
+/********************************
+ * Check for expressions that have no use.
+ * Input:
+ *	flag	0 not going to use the result, so issue error message if no
+ *		  side effects
+ *		1 the result of the expression is used, but still check
+ *		  for useless subexpressions
+ *		2 do not issue error messages, just return !=0 if expression
+ *		  has side effects
+ */
+
+int Expression::checkSideEffect(int flag)
+{
+    if (flag == 0)
+    {	if (op == TOKimport)
+	{
+	    error("%s has no effect", toChars());
+	}
+	else
+	    error("%s has no effect in expression (%s)",
+		Token::toChars(op), toChars());
+    }
+    return 0;
+}
+
+/*****************************
+ * Check that expression can be tested for true or false.
+ */
+
+Expression *Expression::checkToBoolean()
+{
+    // Default is 'yes' - do nothing
+
+#ifdef DEBUG
+    if (!type)
+	dump(0);
+#endif
+
+    if (!type->checkBoolean())
+    {
+	error("expression %s of type %s does not have a boolean value", toChars(), type->toChars());
+    }
+    return this;
+}
+
+/****************************
+ */
+
+Expression *Expression::checkToPointer()
+{
+    Expression *e;
+    Type *tb;
+
+    //printf("Expression::checkToPointer()\n");
+    e = this;
+
+    // If C static array, convert to pointer
+    tb = type->toBasetype();
+    if (tb->ty == Tsarray)
+    {	TypeSArray *ts = (TypeSArray *)tb;
+	if (ts->size(loc) == 0)
+	    e = new NullExp(loc);
+	else
+	    e = new AddrExp(loc, this);
+	e->type = tb->next->pointerTo();
+    }
+    return e;
+}
+
+/******************************
+ * Take address of expression.
+ */
+
+Expression *Expression::addressOf(Scope *sc)
+{
+    Expression *e;
+
+    //printf("Expression::addressOf()\n");
+    e = toLvalue(sc, NULL);
+    e = new AddrExp(loc, e);
+    e->type = type->pointerTo();
+    return e;
+}
+
+/******************************
+ * If this is a reference, dereference it.
+ */
+
+Expression *Expression::deref()
+{
+    //printf("Expression::deref()\n");
+    if (type->ty == Treference)
+    {	Expression *e;
+
+	e = new PtrExp(loc, this);
+	e->type = type->next;
+	return e;
+    }
+    return this;
+}
+
+/********************************
+ * Does this expression statically evaluate to a boolean TRUE or FALSE?
+ */
+
+int Expression::isBool(int result)
+{
+    return FALSE;
+}
+
+/********************************
+ * Does this expression result in either a 1 or a 0?
+ */
+
+int Expression::isBit()
+{
+    return FALSE;
+}
+
+Expressions *Expression::arraySyntaxCopy(Expressions *exps)
+{   Expressions *a = NULL;
+
+    if (exps)
+    {
+	a = new Expressions();
+	a->setDim(exps->dim);
+	for (int i = 0; i < a->dim; i++)
+	{   Expression *e = (Expression *)exps->data[i];
+
+	    e = e->syntaxCopy();
+	    a->data[i] = e;
+	}
+    }
+    return a;
+}
+
+/******************************** IntegerExp **************************/
+
+IntegerExp::IntegerExp(Loc loc, integer_t value, Type *type)
+	: Expression(loc, TOKint64, sizeof(IntegerExp))
+{
+    //printf("IntegerExp(value = %lld, type = '%s')\n", value, type ? type->toChars() : "");
+    if (type && !type->isscalar())
+    {
+	error("integral constant must be scalar type, not %s", type->toChars());
+	type = Type::terror;
+    }
+    this->type = type;
+    this->value = value;
+}
+
+IntegerExp::IntegerExp(integer_t value)
+	: Expression(0, TOKint64, sizeof(IntegerExp))
+{
+    this->type = Type::tint32;
+    this->value = value;
+}
+
+int IntegerExp::equals(Object *o)
+{   IntegerExp *ne;
+
+    if (this == o ||
+	(((Expression *)o)->op == TOKint64 &&
+	 ((ne = (IntegerExp *)o), type->equals(ne->type)) &&
+	 value == ne->value))
+	return 1;
+    return 0;
+}
+
+char *IntegerExp::toChars()
+{
+#if 1
+    return Expression::toChars();
+#else
+    static char buffer[sizeof(value) * 3 + 1];
+
+    sprintf(buffer, "%jd", value);
+    return buffer;
+#endif
+}
+
+integer_t IntegerExp::toInteger()
+{   Type *t;
+
+    t = type;
+    while (t)
+    {
+	switch (t->ty)
+	{
+	    case Tbit:
+	    case Tbool:		value = (value != 0);		break;
+	    case Tint8:		value = (d_int8)  value;	break;
+	    case Tchar:
+	    case Tuns8:		value = (d_uns8)  value;	break;
+	    case Tint16:	value = (d_int16) value;	break;
+	    case Twchar:
+	    case Tuns16:	value = (d_uns16) value;	break;
+	    case Tint32:	value = (d_int32) value;	break;
+	    case Tpointer:
+	    case Tdchar:
+	    case Tuns32:	value = (d_uns32) value;	break;
+	    case Tint64:	value = (d_int64) value;	break;
+	    case Tuns64:	value = (d_uns64) value;	break;
+
+	    case Tenum:
+	    {
+		TypeEnum *te = (TypeEnum *)t;
+		t = te->sym->memtype;
+		continue;
+	    }
+
+	    case Ttypedef:
+	    {
+		TypeTypedef *tt = (TypeTypedef *)t;
+		t = tt->sym->basetype;
+		continue;
+	    }
+
+	    default:
+		print();
+		type->print();
+		assert(0);
+		break;
+	}
+	break;
+    }
+    return value;
+}
+
+real_t IntegerExp::toReal()
+{
+    Type *t;
+
+    toInteger();
+    t = type->toBasetype();
+    if (t->ty == Tuns64)
+	return (real_t)(d_uns64)value;
+    else
+	return (real_t)(d_int64)value;
+}
+
+real_t IntegerExp::toImaginary()
+{
+    return (real_t) 0;
+}
+
+complex_t IntegerExp::toComplex()
+{
+    return toReal();
+}
+
+int IntegerExp::isBool(int result)
+{
+    return result ? value != 0 : value == 0;
+}
+
+Expression *IntegerExp::semantic(Scope *sc)
+{
+    if (!type)
+    {
+	// Determine what the type of this number is
+	integer_t number = value;
+
+	if (number & 0x8000000000000000LL)
+	    type = Type::tuns64;
+	else if (number & 0xFFFFFFFF80000000LL)
+	    type = Type::tint64;
+	else
+	    type = Type::tint32;
+    }
+    else
+    {	type = type->semantic(loc, sc);
+    }
+    return this;
+}
+
+Expression *IntegerExp::toLvalue(Scope *sc, Expression *e)
+{
+    if (!e)
+	e = this;
+    else if (!loc.filename)
+	loc = e->loc;
+    e->error("constant %s is not an lvalue", e->toChars());
+    return this;
+}
+
+void IntegerExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    integer_t v = toInteger();
+
+    if (type)
+    {	Type *t = type;
+
+      L1:
+	switch (t->ty)
+	{
+	    case Tenum:
+	    {   TypeEnum *te = (TypeEnum *)t;
+		buf->printf("cast(%s)", te->sym->toChars());
+		t = te->sym->memtype;
+		goto L1;
+	    }
+
+	    case Ttypedef:
+	    {	TypeTypedef *tt = (TypeTypedef *)t;
+		buf->printf("cast(%s)", tt->sym->toChars());
+		t = tt->sym->basetype;
+		goto L1;
+	    }
+
+	    case Twchar:	// BUG: need to cast(wchar)
+	    case Tdchar:	// BUG: need to cast(dchar)
+		if ((uinteger_t)v > 0xFF)
+		{
+		     buf->printf("'\\U%08x'", v);
+		     break;
+		}
+	    case Tchar:
+		if (v == '\'')
+		    buf->writestring("'\\''");
+		else if (isprint(v) && v != '\\')
+		    buf->printf("'%c'", (int)v);
+		else
+		    buf->printf("'\\x%02x'", (int)v);
+		break;
+
+	    case Tint8:
+		buf->writestring("cast(byte)");
+		goto L2;
+
+	    case Tint16:
+		buf->writestring("cast(short)");
+		goto L2;
+
+	    case Tint32:
+	    L2:
+		buf->printf("%d", (int)v);
+		break;
+
+	    case Tuns8:
+		buf->writestring("cast(ubyte)");
+		goto L3;
+
+	    case Tuns16:
+		buf->writestring("cast(ushort)");
+		goto L3;
+
+	    case Tuns32:
+	    L3:
+		buf->printf("%du", (unsigned)v);
+		break;
+
+	    case Tint64:
+		buf->printf("%jdL", v);
+		break;
+
+	    case Tuns64:
+		buf->printf("%juLU", v);
+		break;
+
+	    case Tbit:
+	    case Tbool:
+		buf->writestring((char *)(v ? "true" : "false"));
+		break;
+
+	    case Tpointer:
+		buf->writestring("cast(");
+		buf->writestring(t->toChars());
+		buf->writeByte(')');
+		goto L3;
+
+	    default:
+#ifdef DEBUG
+		t->print();
+#endif
+		assert(0);
+	}
+    }
+    else if (v & 0x8000000000000000LL)
+	buf->printf("0x%jx", v);
+    else
+	buf->printf("%jd", v);
+}
+
+void IntegerExp::toMangleBuffer(OutBuffer *buf)
+{
+    if ((sinteger_t)value < 0)
+	buf->printf("N%jd", -value);
+    else
+	buf->printf("%jd", value);
+}
+
+/******************************** RealExp **************************/
+
+RealExp::RealExp(Loc loc, real_t value, Type *type)
+	: Expression(loc, TOKfloat64, sizeof(RealExp))
+{
+    //printf("RealExp::RealExp(%Lg)\n", value);
+    this->value = value;
+    this->type = type;
+}
+
+char *RealExp::toChars()
+{
+    static char buffer[sizeof(value) * 3 + 8 + 1 + 1];
+
+#ifdef IN_GCC
+    value.format(buffer, sizeof(buffer));
+    if (type->isimaginary())
+	strcat(buffer, "i");
+#else
+    sprintf(buffer, type->isimaginary() ? "%Lgi" : "%Lg", value);
+#endif
+    assert(strlen(buffer) < sizeof(buffer));
+    return buffer;
+}
+
+integer_t RealExp::toInteger()
+{
+#ifdef IN_GCC
+    return toReal().toInt();
+#else
+    return (sinteger_t) toReal();
+#endif
+}
+
+uinteger_t RealExp::toUInteger()
+{
+#ifdef IN_GCC
+    return (uinteger_t) toReal().toInt();
+#else
+    return (uinteger_t) toReal();
+#endif
+}
+
+real_t RealExp::toReal()
+{
+    return type->isreal() ? value : 0;
+}
+
+real_t RealExp::toImaginary()
+{
+    return type->isreal() ? 0 : value;
+}
+
+complex_t RealExp::toComplex()
+{
+#ifdef __DMC__
+    return toReal() + toImaginary() * I;
+#else
+    return complex_t(toReal(), toImaginary());
+#endif
+}
+
+/********************************
+ * Test to see if two reals are the same.
+ * Regard NaN's as equivalent.
+ * Regard +0 and -0 as different.
+ */
+
+int RealEquals(real_t x1, real_t x2)
+{
+    return (isnan(x1) && isnan(x2)) ||
+	/* In some cases, the REALPAD bytes get garbage in them,
+	 * so be sure and ignore them.
+	 */
+	memcmp(&x1, &x2, REALSIZE - REALPAD) == 0;
+}
+
+int RealExp::equals(Object *o)
+{   RealExp *ne;
+
+    if (this == o ||
+	(((Expression *)o)->op == TOKfloat64 &&
+	 ((ne = (RealExp *)o), type->equals(ne->type)) &&
+	 RealEquals(value, ne->value)
+        )
+       )
+	return 1;
+    return 0;
+}
+
+Expression *RealExp::semantic(Scope *sc)
+{
+    if (!type)
+	type = Type::tfloat64;
+    else
+	type = type->semantic(loc, sc);
+    return this;
+}
+
+int RealExp::isBool(int result)
+{
+#ifdef IN_GCC
+    return result ? (! value.isZero()) : (value.isZero());
+#else
+    return result ? (value != 0)
+		  : (value == 0);
+#endif
+}
+
+void floatToBuffer(OutBuffer *buf, Type *type, real_t value)
+{
+    /* In order to get an exact representation, try converting it
+     * to decimal then back again. If it matches, use it.
+     * If it doesn't, fall back to hex, which is
+     * always exact.
+     */
+    char buffer[25];
+    sprintf(buffer, "%Lg", value);
+    assert(strlen(buffer) < sizeof(buffer));
+#if _WIN32 && __DMC__
+    char *save = __locale_decpoint;
+    __locale_decpoint = ".";
+    real_t r = strtold(buffer, NULL);
+    __locale_decpoint = save;
+#else
+    real_t r = strtold(buffer, NULL);
+#endif
+    if (r == value)			// if exact duplication
+	buf->writestring(buffer);
+    else
+	buf->printf("%La", value);	// ensure exact duplication
+
+    if (type)
+    {
+	Type *t = type->toBasetype();
+	switch (t->ty)
+	{
+	    case Tfloat32:
+	    case Timaginary32:
+	    case Tcomplex32:
+		buf->writeByte('F');
+		break;
+
+	    case Tfloat80:
+	    case Timaginary80:
+	    case Tcomplex80:
+		buf->writeByte('L');
+		break;
+
+	    default:
+		break;
+	}
+	if (t->isimaginary())
+	    buf->writeByte('i');
+    }
+}
+
+void RealExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    floatToBuffer(buf, type, value);
+}
+
+void realToMangleBuffer(OutBuffer *buf, real_t value)
+{
+    /* Rely on %A to get portable mangling.
+     * Must munge result to get only identifier characters.
+     *
+     * Possible values from %A	=> mangled result
+     * NAN			=> NAN
+     * -INF			=> NINF
+     * INF			=> INF
+     * -0X1.1BC18BA997B95P+79	=> N11BC18BA997B95P79
+     * 0X1.9P+2			=> 19P2
+     */
+
+    if (isnan(value))
+	buf->writestring("NAN");	// no -NAN bugs
+    else
+    {
+	char buffer[32];
+	int n = sprintf(buffer, "%LA", value);
+	assert(n > 0 && n < sizeof(buffer));
+	for (int i = 0; i < n; i++)
+	{   char c = buffer[i];
+
+	    switch (c)
+	    {
+		case '-':
+		    buf->writeByte('N');
+		    break;
+
+		case '+':
+		case 'X':
+		case '.':
+		    break;
+
+		case '0':
+		    if (i < 2)
+			break;		// skip leading 0X
+		default:
+		    buf->writeByte(c);
+		    break;
+	    }
+	}
+    }
+}
+
+void RealExp::toMangleBuffer(OutBuffer *buf)
+{
+    buf->writeByte('e');
+    realToMangleBuffer(buf, value);
+}
+
+
+/******************************** ComplexExp **************************/
+
+ComplexExp::ComplexExp(Loc loc, complex_t value, Type *type)
+	: Expression(loc, TOKcomplex80, sizeof(ComplexExp))
+{
+    this->value = value;
+    this->type = type;
+    //printf("ComplexExp::ComplexExp(%s)\n", toChars());
+}
+
+char *ComplexExp::toChars()
+{
+    static char buffer[sizeof(value) * 3 + 8 + 1];
+
+#ifdef IN_GCC
+    char buf1[sizeof(value) * 3 + 8 + 1];
+    char buf2[sizeof(value) * 3 + 8 + 1];
+    creall(value).format(buf1, sizeof(buf1));
+    cimagl(value).format(buf2, sizeof(buf2));
+    sprintf(buffer, "(%s+%si)", buf1, buf2);
+#else
+    sprintf(buffer, "(%Lg+%Lgi)", creall(value), cimagl(value));
+    assert(strlen(buffer) < sizeof(buffer));
+#endif
+    return buffer;
+}
+
+integer_t ComplexExp::toInteger()
+{
+#ifdef IN_GCC
+    return (sinteger_t) toReal().toInt();
+#else
+    return (sinteger_t) toReal();
+#endif
+}
+
+uinteger_t ComplexExp::toUInteger()
+{
+#ifdef IN_GCC
+    return (uinteger_t) toReal().toInt();
+#else
+    return (uinteger_t) toReal();
+#endif
+}
+
+real_t ComplexExp::toReal()
+{
+    return creall(value);
+}
+
+real_t ComplexExp::toImaginary()
+{
+    return cimagl(value);
+}
+
+complex_t ComplexExp::toComplex()
+{
+    return value;
+}
+
+int ComplexExp::equals(Object *o)
+{   ComplexExp *ne;
+
+    if (this == o ||
+	(((Expression *)o)->op == TOKcomplex80 &&
+	 ((ne = (ComplexExp *)o), type->equals(ne->type)) &&
+	 RealEquals(creall(value), creall(ne->value)) &&
+	 RealEquals(cimagl(value), cimagl(ne->value))
+	)
+       )
+	return 1;
+    return 0;
+}
+
+Expression *ComplexExp::semantic(Scope *sc)
+{
+    if (!type)
+	type = Type::tcomplex80;
+    else
+	type = type->semantic(loc, sc);
+    return this;
+}
+
+int ComplexExp::isBool(int result)
+{
+    if (result)
+	return (bool)(value);
+    else
+	return !value;
+}
+
+void ComplexExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    /* Print as:
+     *  (re+imi)
+     */
+#ifdef IN_GCC
+    char buf1[sizeof(value) * 3 + 8 + 1];
+    char buf2[sizeof(value) * 3 + 8 + 1];
+    creall(value).format(buf1, sizeof(buf1));
+    cimagl(value).format(buf2, sizeof(buf2));
+    buf->printf("(%s+%si)", buf1, buf2);
+#else
+    buf->writeByte('(');
+    floatToBuffer(buf, type, creall(value));
+    buf->writeByte('+');
+    floatToBuffer(buf, type, cimagl(value));
+    buf->writestring("i)");
+#endif
+}
+
+void ComplexExp::toMangleBuffer(OutBuffer *buf)
+{
+    buf->writeByte('c');
+    real_t r = toReal();
+    realToMangleBuffer(buf, r);
+    buf->writeByte('c');	// separate the two
+    r = toImaginary();
+    realToMangleBuffer(buf, r);
+}
+
+/******************************** IdentifierExp **************************/
+
+IdentifierExp::IdentifierExp(Loc loc, Identifier *ident)
+	: Expression(loc, TOKidentifier, sizeof(IdentifierExp))
+{
+    this->ident = ident;
+}
+
+Expression *IdentifierExp::semantic(Scope *sc)
+{
+    Dsymbol *s;
+    Dsymbol *scopesym;
+
+#if LOGSEMANTIC
+    printf("IdentifierExp::semantic('%s')\n", ident->toChars());
+#endif
+    s = sc->search(loc, ident, &scopesym);
+    if (s)
+    {	Expression *e;
+	WithScopeSymbol *withsym;
+
+	// See if it was a with class
+	withsym = scopesym->isWithScopeSymbol();
+	if (withsym)
+	{
+	    s = s->toAlias();
+
+	    // Same as wthis.ident
+	    if (s->needThis() || s->isTemplateDeclaration())
+	    {
+		e = new VarExp(loc, withsym->withstate->wthis);
+		e = new DotIdExp(loc, e, ident);
+	    }
+	    else
+	    {	Type *t = withsym->withstate->wthis->type;
+		if (t->ty == Tpointer)
+		    t = t->next;
+		e = new TypeDotIdExp(loc, t, ident);
+	    }
+	}
+	else
+	{
+	    if (!s->parent && scopesym->isArrayScopeSymbol())
+	    {	// Kludge to run semantic() here because
+		// ArrayScopeSymbol::search() doesn't have access to sc.
+		s->semantic(sc);
+	    }
+	    // Look to see if f is really a function template
+	    FuncDeclaration *f = s->isFuncDeclaration();
+	    if (f && f->parent)
+	    {   TemplateInstance *ti = f->parent->isTemplateInstance();
+
+		if (ti &&
+		    !ti->isTemplateMixin() &&
+		    (ti->name == f->ident ||
+		     ti->toAlias()->ident == f->ident)
+		    &&
+		    ti->tempdecl && ti->tempdecl->onemember)
+		{
+		    TemplateDeclaration *tempdecl = ti->tempdecl;
+		    if (tempdecl->overroot)         // if not start of overloaded list of TemplateDeclaration's
+			tempdecl = tempdecl->overroot; // then get the start
+		    e = new TemplateExp(loc, tempdecl);
+		    e = e->semantic(sc);
+		    return e;
+		}
+	    }
+	    e = new DsymbolExp(loc, s);
+	}
+	return e->semantic(sc);
+    }
+    error("undefined identifier %s", ident->toChars());
+    type = Type::terror;
+    return this;
+}
+
+char *IdentifierExp::toChars()
+{
+    return ident->toChars();
+}
+
+void IdentifierExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    if (hgs->hdrgen)
+	buf->writestring(ident->toHChars2());
+    else
+	buf->writestring(ident->toChars());
+}
+
+Expression *IdentifierExp::toLvalue(Scope *sc, Expression *e)
+{
+#if 0
+    tym = tybasic(e1->ET->Tty);
+    if (!(tyscalar(tym) ||
+	  tym == TYstruct ||
+	  tym == TYarray && e->Eoper == TOKaddr))
+	    synerr(EM_lvalue);	// lvalue expected
+#endif
+    return this;
+}
+
+/******************************** DollarExp **************************/
+
+DollarExp::DollarExp(Loc loc)
+	: IdentifierExp(loc, Id::dollar)
+{
+}
+
+/******************************** DsymbolExp **************************/
+
+DsymbolExp::DsymbolExp(Loc loc, Dsymbol *s)
+	: Expression(loc, TOKdsymbol, sizeof(DsymbolExp))
+{
+    this->s = s;
+}
+
+Expression *DsymbolExp::semantic(Scope *sc)
+{
+#if LOGSEMANTIC
+    printf("DsymbolExp::semantic('%s')\n", s->toChars());
+#endif
+
+Lagain:
+    EnumMember *em;
+    Expression *e;
+    VarDeclaration *v;
+    FuncDeclaration *f;
+    FuncLiteralDeclaration *fld;
+    Declaration *d;
+    ClassDeclaration *cd;
+    ClassDeclaration *thiscd = NULL;
+    Import *imp;
+    Package *pkg;
+    Type *t;
+
+    //printf("DsymbolExp:: %p '%s' is a symbol\n", this, toChars());
+    //printf("s = '%s', s->kind = '%s'\n", s->toChars(), s->kind());
+    if (type)
+	return this;
+    if (!s->isFuncDeclaration())	// functions are checked after overloading
+	checkDeprecated(sc, s);
+    s = s->toAlias();
+    //printf("s = '%s', s->kind = '%s', s->needThis() = %p\n", s->toChars(), s->kind(), s->needThis());
+    if (!s->isFuncDeclaration())
+	checkDeprecated(sc, s);
+
+    if (sc->func)
+	thiscd = sc->func->parent->isClassDeclaration();
+
+    // BUG: This should happen after overload resolution for functions, not before
+    if (s->needThis())
+    {
+	if (hasThis(sc) /*&& !s->isFuncDeclaration()*/)
+	{
+	    // Supply an implicit 'this', as in
+	    //	  this.ident
+
+	    DotVarExp *de;
+
+	    de = new DotVarExp(loc, new ThisExp(loc), s->isDeclaration());
+	    return de->semantic(sc);
+	}
+    }
+
+    em = s->isEnumMember();
+    if (em)
+    {
+	e = em->value;
+	e = e->semantic(sc);
+	return e;
+    }
+    v = s->isVarDeclaration();
+    if (v)
+    {
+	//printf("Identifier '%s' is a variable, type '%s'\n", toChars(), v->type->toChars());
+	if (!type)
+	{   type = v->type;
+	    if (!v->type)
+	    {	error("forward reference of %s", v->toChars());
+		type = Type::terror;
+	    }
+	}
+	if (v->isConst() && type->toBasetype()->ty != Tsarray)
+	{
+	    if (v->init)
+	    {
+		if (v->inuse)
+		{
+		    error("circular reference to '%s'", v->toChars());
+		    type = Type::tint32;
+		    return this;
+		}
+		ExpInitializer *ei = v->init->isExpInitializer();
+		if (ei)
+		{
+		    e = ei->exp->copy();	// make copy so we can change loc
+		    if (e->op == TOKstring || !e->type)
+			e = e->semantic(sc);
+		    e = e->implicitCastTo(sc, type);
+		    e->loc = loc;
+		    return e;
+		}
+	    }
+	    else
+	    {
+		e = type->defaultInit();
+		e->loc = loc;
+		return e;
+	    }
+	}
+	e = new VarExp(loc, v);
+	e->type = type;
+	e = e->semantic(sc);
+	return e->deref();
+    }
+    fld = s->isFuncLiteralDeclaration();
+    if (fld)
+    {	//printf("'%s' is a function literal\n", fld->toChars());
+	e = new FuncExp(loc, fld);
+	return e->semantic(sc);
+    }
+    f = s->isFuncDeclaration();
+    if (f)
+    {	//printf("'%s' is a function\n", f->toChars());
+	return new VarExp(loc, f);
+    }
+    cd = s->isClassDeclaration();
+    if (cd && thiscd && cd->isBaseOf(thiscd, NULL) && sc->func->needThis())
+    {
+	// We need to add an implicit 'this' if cd is this class or a base class.
+	DotTypeExp *dte;
+
+	dte = new DotTypeExp(loc, new ThisExp(loc), s);
+	return dte->semantic(sc);
+    }
+    imp = s->isImport();
+    if (imp)
+    {
+	ScopeExp *ie;
+
+	ie = new ScopeExp(loc, imp->pkg);
+	return ie->semantic(sc);
+    }
+    pkg = s->isPackage();
+    if (pkg)
+    {
+	ScopeExp *ie;
+
+	ie = new ScopeExp(loc, pkg);
+	return ie->semantic(sc);
+    }
+    Module *mod = s->isModule();
+    if (mod)
+    {
+	ScopeExp *ie;
+
+	ie = new ScopeExp(loc, mod);
+	return ie->semantic(sc);
+    }
+
+    t = s->getType();
+    if (t)
+    {
+	return new TypeExp(loc, t);
+    }
+
+    TupleDeclaration *tup = s->isTupleDeclaration();
+    if (tup)
+    {
+	e = new TupleExp(loc, tup);
+	e = e->semantic(sc);
+	return e;
+    }
+
+    TemplateInstance *ti = s->isTemplateInstance();
+    if (ti && !global.errors)
+    {   if (!ti->semanticdone)
+	    ti->semantic(sc);
+	s = ti->inst->toAlias();
+	if (!s->isTemplateInstance())
+	    goto Lagain;
+	e = new ScopeExp(loc, ti);
+	e = e->semantic(sc);
+	return e;
+    }
+
+    TemplateDeclaration *td = s->isTemplateDeclaration();
+    if (td)
+    {
+	e = new TemplateExp(loc, td);
+	e = e->semantic(sc);
+	return e;
+    }
+
+Lerr:
+    error("%s '%s' is not a variable", s->kind(), s->toChars());
+    type = Type::terror;
+    return this;
+}
+
+char *DsymbolExp::toChars()
+{
+    return s->toChars();
+}
+
+void DsymbolExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring(s->toChars());
+}
+
+Expression *DsymbolExp::toLvalue(Scope *sc, Expression *e)
+{
+#if 0
+    tym = tybasic(e1->ET->Tty);
+    if (!(tyscalar(tym) ||
+	  tym == TYstruct ||
+	  tym == TYarray && e->Eoper == TOKaddr))
+	    synerr(EM_lvalue);	// lvalue expected
+#endif
+    return this;
+}
+
+/******************************** ThisExp **************************/
+
+ThisExp::ThisExp(Loc loc)
+	: Expression(loc, TOKthis, sizeof(ThisExp))
+{
+    var = NULL;
+}
+
+Expression *ThisExp::semantic(Scope *sc)
+{   FuncDeclaration *fd;
+    FuncDeclaration *fdthis;
+    int nested = 0;
+
+#if LOGSEMANTIC
+    printf("ThisExp::semantic()\n");
+#endif
+    if (type)
+    {	//assert(global.errors || var);
+	return this;
+    }
+
+    /* Special case for typeof(this) and typeof(super) since both
+     * should work even if they are not inside a non-static member function
+     */
+    if (sc->intypeof)
+    {
+	// Find enclosing struct or class
+	for (Dsymbol *s = sc->parent; 1; s = s->parent)
+	{
+	    ClassDeclaration *cd;
+	    StructDeclaration *sd;
+
+	    if (!s)
+	    {
+		error("%s is not in a struct or class scope", toChars());
+		goto Lerr;
+	    }
+	    cd = s->isClassDeclaration();
+	    if (cd)
+	    {
+		type = cd->type;
+		return this;
+	    }
+	    sd = s->isStructDeclaration();
+	    if (sd)
+	    {
+		type = sd->type->pointerTo();
+		return this;
+	    }
+	}
+    }
+
+    fdthis = sc->parent->isFuncDeclaration();
+    fd = hasThis(sc);	// fd is the uplevel function with the 'this' variable
+    if (!fd)
+	goto Lerr;
+
+    assert(fd->vthis);
+    var = fd->vthis;
+    assert(var->parent);
+    type = var->type;
+    var->isVarDeclaration()->checkNestedReference(sc, loc);
+#if 0
+    if (fd != fdthis)		// if nested
+    {
+	fdthis->getLevel(loc, fd);
+	fd->vthis->nestedref = 1;
+	fd->nestedFrameRef = 1;
+    }
+#endif
+    sc->callSuper |= CSXthis;
+    return this;
+
+Lerr:
+    error("'this' is only allowed in non-static member functions, not %s", sc->parent->toChars());
+    type = Type::tint32;
+    return this;
+}
+
+int ThisExp::isBool(int result)
+{
+    return result ? TRUE : FALSE;
+}
+
+void ThisExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("this");
+}
+
+Expression *ThisExp::toLvalue(Scope *sc, Expression *e)
+{
+    return this;
+}
+
+/******************************** SuperExp **************************/
+
+SuperExp::SuperExp(Loc loc)
+	: ThisExp(loc)
+{
+    op = TOKsuper;
+}
+
+Expression *SuperExp::semantic(Scope *sc)
+{   FuncDeclaration *fd;
+    FuncDeclaration *fdthis;
+    ClassDeclaration *cd;
+    Dsymbol *s;
+
+#if LOGSEMANTIC
+    printf("SuperExp::semantic('%s')\n", toChars());
+#endif
+    if (type)
+	return this;
+
+    /* Special case for typeof(this) and typeof(super) since both
+     * should work even if they are not inside a non-static member function
+     */
+    if (sc->intypeof)
+    {
+	// Find enclosing class
+	for (Dsymbol *s = sc->parent; 1; s = s->parent)
+	{
+	    ClassDeclaration *cd;
+
+	    if (!s)
+	    {
+		error("%s is not in a class scope", toChars());
+		goto Lerr;
+	    }
+	    cd = s->isClassDeclaration();
+	    if (cd)
+	    {
+		cd = cd->baseClass;
+		if (!cd)
+		{   error("class %s has no 'super'", s->toChars());
+		    goto Lerr;
+		}
+		type = cd->type;
+		return this;
+	    }
+	}
+    }
+
+    fdthis = sc->parent->isFuncDeclaration();
+    fd = hasThis(sc);
+    if (!fd)
+	goto Lerr;
+    assert(fd->vthis);
+    var = fd->vthis;
+    assert(var->parent);
+
+    s = fd->toParent();
+    while (s && s->isTemplateInstance())
+	s = s->toParent();
+    assert(s);
+    cd = s->isClassDeclaration();
+//printf("parent is %s %s\n", fd->toParent()->kind(), fd->toParent()->toChars());
+    if (!cd)
+	goto Lerr;
+    if (!cd->baseClass)
+    {
+	error("no base class for %s", cd->toChars());
+	type = fd->vthis->type;
+    }
+    else
+    {
+	type = cd->baseClass->type;
+    }
+
+    var->isVarDeclaration()->checkNestedReference(sc, loc);
+#if 0
+    if (fd != fdthis)
+    {
+	fdthis->getLevel(loc, fd);
+	fd->vthis->nestedref = 1;
+	fd->nestedFrameRef = 1;
+    }
+#endif
+
+    sc->callSuper |= CSXsuper;
+    return this;
+
+
+Lerr:
+    error("'super' is only allowed in non-static class member functions");
+    type = Type::tint32;
+    return this;
+}
+
+void SuperExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("super");
+}
+
+
+/******************************** NullExp **************************/
+
+NullExp::NullExp(Loc loc)
+	: Expression(loc, TOKnull, sizeof(NullExp))
+{
+    committed = 0;
+}
+
+Expression *NullExp::semantic(Scope *sc)
+{
+#if LOGSEMANTIC
+    printf("NullExp::semantic('%s')\n", toChars());
+#endif
+    // NULL is the same as (void *)0
+    if (!type)
+	type = Type::tvoid->pointerTo();
+    return this;
+}
+
+int NullExp::isBool(int result)
+{
+    return result ? FALSE : TRUE;
+}
+
+void NullExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("null");
+}
+
+void NullExp::toMangleBuffer(OutBuffer *buf)
+{
+    buf->writeByte('n');
+}
+
+/******************************** StringExp **************************/
+
+StringExp::StringExp(Loc loc, char *string)
+	: Expression(loc, TOKstring, sizeof(StringExp))
+{
+    this->string = string;
+    this->len = strlen(string);
+    this->sz = 1;
+    this->committed = 0;
+    this->postfix = 0;
+}
+
+StringExp::StringExp(Loc loc, void *string, size_t len)
+	: Expression(loc, TOKstring, sizeof(StringExp))
+{
+    this->string = string;
+    this->len = len;
+    this->sz = 1;
+    this->committed = 0;
+    this->postfix = 0;
+}
+
+StringExp::StringExp(Loc loc, void *string, size_t len, unsigned char postfix)
+	: Expression(loc, TOKstring, sizeof(StringExp))
+{
+    this->string = string;
+    this->len = len;
+    this->sz = 1;
+    this->committed = 0;
+    this->postfix = postfix;
+}
+
+#if 0
+Expression *StringExp::syntaxCopy()
+{
+    printf("StringExp::syntaxCopy() %s\n", toChars());
+    return copy();
+}
+#endif
+
+int StringExp::equals(Object *o)
+{
+    //printf("StringExp::equals('%s')\n", o->toChars());
+    if (o && o->dyncast() == DYNCAST_EXPRESSION)
+    {	Expression *e = (Expression *)o;
+
+	if (e->op == TOKstring)
+	{
+	    return compare(o) == 0;
+	}
+    }
+    return FALSE;
+}
+
+char *StringExp::toChars()
+{
+    OutBuffer buf;
+    HdrGenState hgs;
+    char *p;
+
+    memset(&hgs, 0, sizeof(hgs));
+    toCBuffer(&buf, &hgs);
+    buf.writeByte(0);
+    p = (char *)buf.data;
+    buf.data = NULL;
+    return p;
+}
+
+Expression *StringExp::semantic(Scope *sc)
+{
+#if LOGSEMANTIC
+    printf("StringExp::semantic() %s\n", toChars());
+#endif
+    if (!type)
+    {	OutBuffer buffer;
+	size_t newlen = 0;
+	char *p;
+	size_t u;
+	unsigned c;
+
+	switch (postfix)
+	{
+	    case 'd':
+		for (u = 0; u < len;)
+		{
+		    p = utf_decodeChar((unsigned char *)string, len, &u, &c);
+		    if (p)
+		    {	error("%s", p);
+			break;
+		    }
+		    else
+		    {	buffer.write4(c);
+			newlen++;
+		    }
+		}
+		buffer.write4(0);
+		string = buffer.extractData();
+		len = newlen;
+		sz = 4;
+		type = new TypeSArray(Type::tdchar, new IntegerExp(loc, len, Type::tindex));
+		committed = 1;
+		break;
+
+	    case 'w':
+		for (u = 0; u < len;)
+		{
+		    p = utf_decodeChar((unsigned char *)string, len, &u, &c);
+		    if (p)
+		    {	error("%s", p);
+			break;
+		    }
+		    else
+		    {	buffer.writeUTF16(c);
+			newlen++;
+			if (c >= 0x10000)
+			    newlen++;
+		    }
+		}
+		buffer.writeUTF16(0);
+		string = buffer.extractData();
+		len = newlen;
+		sz = 2;
+		type = new TypeSArray(Type::twchar, new IntegerExp(loc, len, Type::tindex));
+		committed = 1;
+		break;
+
+	    case 'c':
+		committed = 1;
+	    default:
+		type = new TypeSArray(Type::tchar, new IntegerExp(loc, len, Type::tindex));
+		break;
+	}
+	type = type->semantic(loc, sc);
+    }
+    return this;
+}
+
+/****************************************
+ * Convert string to char[].
+ */
+
+StringExp *StringExp::toUTF8(Scope *sc)
+{
+    if (sz != 1)
+    {	// Convert to UTF-8 string
+	committed = 0;
+	Expression *e = castTo(sc, Type::tchar->arrayOf());
+	e = e->optimize(WANTvalue);
+	assert(e->op == TOKstring);
+	StringExp *se = (StringExp *)e;
+	assert(se->sz == 1);
+	return se;
+    }
+    return this;
+}
+
+int StringExp::compare(Object *obj)
+{
+    // Used to sort case statement expressions so we can do an efficient lookup
+    StringExp *se2 = (StringExp *)(obj);
+
+    // This is a kludge so isExpression() in template.c will return 5
+    // for StringExp's.
+    if (!se2)
+	return 5;
+
+    assert(se2->op == TOKstring);
+
+    int len1 = len;
+    int len2 = se2->len;
+
+    if (len1 == len2)
+    {
+	switch (sz)
+	{
+	    case 1:
+		return strcmp((char *)string, (char *)se2->string);
+
+	    case 2:
+	    {	unsigned u;
+		d_wchar *s1 = (d_wchar *)string;
+		d_wchar *s2 = (d_wchar *)se2->string;
+
+		for (u = 0; u < len; u++)
+		{
+		    if (s1[u] != s2[u])
+			return s1[u] - s2[u];
+		}
+	    }
+
+	    case 4:
+	    {	unsigned u;
+		d_dchar *s1 = (d_dchar *)string;
+		d_dchar *s2 = (d_dchar *)se2->string;
+
+		for (u = 0; u < len; u++)
+		{
+		    if (s1[u] != s2[u])
+			return s1[u] - s2[u];
+		}
+	    }
+	    break;
+
+	    default:
+		assert(0);
+	}
+    }
+    return len1 - len2;
+}
+
+int StringExp::isBool(int result)
+{
+    return result ? TRUE : FALSE;
+}
+
+void StringExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writeByte('"');
+    for (size_t i = 0; i < len; i++)
+    {	unsigned c;
+
+	switch (sz)
+	{
+	    case 1:
+		c = ((unsigned char *)string)[i];
+		break;
+	    case 2:
+		c = ((unsigned short *)string)[i];
+		break;
+	    case 4:
+		c = ((unsigned *)string)[i];
+		break;
+	    default:
+		assert(0);
+	}
+	switch (c)
+	{
+	    case '"':
+	    case '\\':
+		if (!hgs->console)
+		    buf->writeByte('\\');
+	    default:
+		if (c <= 0xFF)
+		{   if (c <= 0x7F && (isprint(c) || hgs->console))
+			buf->writeByte(c);
+		    else
+			buf->printf("\\x%02x", c);
+		}
+		else if (c <= 0xFFFF)
+		    buf->printf("\\x%02x\\x%02x", c & 0xFF, c >> 8);
+		else
+		    buf->printf("\\x%02x\\x%02x\\x%02x\\x%02x",
+			c & 0xFF, (c >> 8) & 0xFF, (c >> 16) & 0xFF, c >> 24);
+		break;
+	}
+    }
+    buf->writeByte('"');
+    if (postfix)
+	buf->writeByte(postfix);
+}
+
+void StringExp::toMangleBuffer(OutBuffer *buf)
+{   char m;
+    OutBuffer tmp;
+    char *p;
+    unsigned c;
+    size_t u;
+    unsigned char *q;
+    unsigned qlen;
+
+    /* Write string in UTF-8 format
+     */
+    switch (sz)
+    {	case 1:
+	    m = 'a';
+	    q = (unsigned char *)string;
+	    qlen = len;
+	    break;
+	case 2:
+	    m = 'w';
+	    for (u = 0; u < len; )
+	    {
+                p = utf_decodeWchar((unsigned short *)string, len, &u, &c);
+                if (p)
+                    error("%s", p);
+                else
+                    tmp.writeUTF8(c);
+	    }
+	    q = tmp.data;
+	    qlen = tmp.offset;
+	    break;
+	case 4:
+	    m = 'd';
+            for (u = 0; u < len; u++)
+            {
+                c = ((unsigned *)string)[u];
+                if (!utf_isValidDchar(c))
+                    error("invalid UCS-32 char \\U%08x", c);
+                else
+                    tmp.writeUTF8(c);
+            }
+	    q = tmp.data;
+	    qlen = tmp.offset;
+	    break;
+	default:
+	    assert(0);
+    }
+    buf->writeByte(m);
+    buf->printf("%d_", qlen);
+    for (size_t i = 0; i < qlen; i++)
+	buf->printf("%02x", q[i]);
+}
+
+/************************ ArrayLiteralExp ************************************/
+
+// [ e1, e2, e3, ... ]
+
+ArrayLiteralExp::ArrayLiteralExp(Loc loc, Expressions *elements)
+    : Expression(loc, TOKarrayliteral, sizeof(ArrayLiteralExp))
+{
+    this->elements = elements;
+}
+
+ArrayLiteralExp::ArrayLiteralExp(Loc loc, Expression *e)
+    : Expression(loc, TOKarrayliteral, sizeof(ArrayLiteralExp))
+{
+    elements = new Expressions;
+    elements->push(e);
+}
+
+Expression *ArrayLiteralExp::syntaxCopy()
+{
+    return new ArrayLiteralExp(loc, arraySyntaxCopy(elements));
+}
+
+Expression *ArrayLiteralExp::semantic(Scope *sc)
+{   Expression *e;
+    Type *t0 = NULL;
+
+#if LOGSEMANTIC
+    printf("ArrayLiteralExp::semantic('%s')\n", toChars());
+#endif
+
+    // Run semantic() on each element
+    for (int i = 0; i < elements->dim; i++)
+    {	e = (Expression *)elements->data[i];
+	e = e->semantic(sc);
+	elements->data[i] = (void *)e;
+    }
+    expandTuples(elements);
+    for (int i = 0; i < elements->dim; i++)
+    {	e = (Expression *)elements->data[i];
+
+	if (!e->type)
+	    error("%s has no value", e->toChars());
+	e = resolveProperties(sc, e);
+
+	unsigned char committed = 1;
+	if (e->op == TOKstring)
+	    committed = ((StringExp *)e)->committed;
+
+	if (!t0)
+	{   t0 = e->type;
+	    // Convert any static arrays to dynamic arrays
+	    if (t0->ty == Tsarray)
+	    {
+		t0 = t0->next->arrayOf();
+		e = e->implicitCastTo(sc, t0);
+	    }
+	}
+	else
+	    e = e->implicitCastTo(sc, t0);
+	if (!committed && e->op == TOKstring)
+	{   StringExp *se = (StringExp *)e;
+	    se->committed = 0;
+	}
+	elements->data[i] = (void *)e;
+    }
+
+    if (!t0)
+	t0 = Type::tvoid;
+    type = new TypeSArray(t0, new IntegerExp(elements->dim));
+    type = type->semantic(loc, sc);
+    return this;
+}
+
+int ArrayLiteralExp::checkSideEffect(int flag)
+{   int f = 0;
+
+    for (size_t i = 0; i < elements->dim; i++)
+    {	Expression *e = (Expression *)elements->data[i];
+
+	f |= e->checkSideEffect(2);
+    }
+    if (flag == 0 && f == 0)
+	Expression::checkSideEffect(0);
+    return f;
+}
+
+int ArrayLiteralExp::isBool(int result)
+{
+    size_t dim = elements ? elements->dim : 0;
+    return result ? (dim != 0) : (dim == 0);
+}
+
+void ArrayLiteralExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writeByte('[');
+    argsToCBuffer(buf, elements, hgs);
+    buf->writeByte(']');
+}
+
+void ArrayLiteralExp::toMangleBuffer(OutBuffer *buf)
+{
+    size_t dim = elements ? elements->dim : 0;
+    buf->printf("A%u", dim);
+    for (size_t i = 0; i < dim; i++)
+    {	Expression *e = (Expression *)elements->data[i];
+	e->toMangleBuffer(buf);
+    }
+}
+
+/************************ AssocArrayLiteralExp ************************************/
+
+// [ key0 : value0, key1 : value1, ... ]
+
+AssocArrayLiteralExp::AssocArrayLiteralExp(Loc loc,
+		Expressions *keys, Expressions *values)
+    : Expression(loc, TOKassocarrayliteral, sizeof(AssocArrayLiteralExp))
+{
+    assert(keys->dim == values->dim);
+    this->keys = keys;
+    this->values = values;
+}
+
+Expression *AssocArrayLiteralExp::syntaxCopy()
+{
+    return new AssocArrayLiteralExp(loc,
+	arraySyntaxCopy(keys), arraySyntaxCopy(values));
+}
+
+Expression *AssocArrayLiteralExp::semantic(Scope *sc)
+{   Expression *e;
+    Type *tkey = NULL;
+    Type *tvalue = NULL;
+
+#if LOGSEMANTIC
+    printf("AssocArrayLiteralExp::semantic('%s')\n", toChars());
+#endif
+
+    // Run semantic() on each element
+    for (size_t i = 0; i < keys->dim; i++)
+    {	Expression *key = (Expression *)keys->data[i];
+	Expression *value = (Expression *)values->data[i];
+
+	key = key->semantic(sc);
+	value = value->semantic(sc);
+
+	keys->data[i] = (void *)key;
+	values->data[i] = (void *)value;
+    }
+    expandTuples(keys);
+    expandTuples(values);
+    if (keys->dim != values->dim)
+    {
+	error("number of keys is %u, must match number of values %u", keys->dim, values->dim);
+	keys->setDim(0);
+	values->setDim(0);
+    }
+    for (size_t i = 0; i < keys->dim; i++)
+    {	Expression *key = (Expression *)keys->data[i];
+	Expression *value = (Expression *)values->data[i];
+
+	if (!key->type)
+	    error("%s has no value", key->toChars());
+	if (!value->type)
+	    error("%s has no value", value->toChars());
+	key = resolveProperties(sc, key);
+	value = resolveProperties(sc, value);
+
+	if (!tkey)
+	    tkey = key->type;
+	else
+	    key = key->implicitCastTo(sc, tkey);
+	keys->data[i] = (void *)key;
+
+	if (!tvalue)
+	    tvalue = value->type;
+	else
+	    value = value->implicitCastTo(sc, tvalue);
+	values->data[i] = (void *)value;
+    }
+
+    if (!tkey)
+	tkey = Type::tvoid;
+    if (!tvalue)
+	tvalue = Type::tvoid;
+    type = new TypeAArray(tvalue, tkey);
+    type = type->semantic(loc, sc);
+    return this;
+}
+
+int AssocArrayLiteralExp::checkSideEffect(int flag)
+{   int f = 0;
+
+    for (size_t i = 0; i < keys->dim; i++)
+    {	Expression *key = (Expression *)keys->data[i];
+	Expression *value = (Expression *)values->data[i];
+
+	f |= key->checkSideEffect(2);
+	f |= value->checkSideEffect(2);
+    }
+    if (flag == 0 && f == 0)
+	Expression::checkSideEffect(0);
+    return f;
+}
+
+int AssocArrayLiteralExp::isBool(int result)
+{
+    size_t dim = keys->dim;
+    return result ? (dim != 0) : (dim == 0);
+}
+
+void AssocArrayLiteralExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writeByte('[');
+    for (size_t i = 0; i < keys->dim; i++)
+    {	Expression *key = (Expression *)keys->data[i];
+	Expression *value = (Expression *)values->data[i];
+
+	if (i)
+	    buf->writeByte(',');
+	expToCBuffer(buf, hgs, key, PREC_assign);
+	buf->writeByte(':');
+	expToCBuffer(buf, hgs, value, PREC_assign);
+    }
+    buf->writeByte(']');
+}
+
+void AssocArrayLiteralExp::toMangleBuffer(OutBuffer *buf)
+{
+    size_t dim = keys->dim;
+    buf->printf("A%u", dim);
+    for (size_t i = 0; i < dim; i++)
+    {	Expression *key = (Expression *)keys->data[i];
+	Expression *value = (Expression *)values->data[i];
+
+	key->toMangleBuffer(buf);
+	value->toMangleBuffer(buf);
+    }
+}
+
+/************************ StructLiteralExp ************************************/
+
+// sd( e1, e2, e3, ... )
+
+StructLiteralExp::StructLiteralExp(Loc loc, StructDeclaration *sd, Expressions *elements)
+    : Expression(loc, TOKstructliteral, sizeof(StructLiteralExp))
+{
+    this->sd = sd;
+    this->elements = elements;
+    this->sym = NULL;
+    this->soffset = 0;
+    this->fillHoles = 1;
+}
+
+Expression *StructLiteralExp::syntaxCopy()
+{
+    return new StructLiteralExp(loc, sd, arraySyntaxCopy(elements));
+}
+
+Expression *StructLiteralExp::semantic(Scope *sc)
+{   Expression *e;
+
+#if LOGSEMANTIC
+    printf("StructLiteralExp::semantic('%s')\n", toChars());
+#endif
+
+    // Run semantic() on each element
+    for (size_t i = 0; i < elements->dim; i++)
+    {	e = (Expression *)elements->data[i];
+	if (!e)
+	    continue;
+	e = e->semantic(sc);
+	elements->data[i] = (void *)e;
+    }
+    expandTuples(elements);
+    size_t offset = 0;
+    for (size_t i = 0; i < elements->dim; i++)
+    {	e = (Expression *)elements->data[i];
+	if (!e)
+	    continue;
+
+	if (!e->type)
+	    error("%s has no value", e->toChars());
+	e = resolveProperties(sc, e);
+	if (i >= sd->fields.dim)
+	{   error("more initializers than fields of %s", sd->toChars());
+	    break;
+	}
+	Dsymbol *s = (Dsymbol *)sd->fields.data[i];
+	VarDeclaration *v = s->isVarDeclaration();
+	assert(v);
+	if (v->offset < offset)
+	    error("overlapping initialization for %s", v->toChars());
+	offset = v->offset + v->type->size();
+
+	Type *telem = v->type;
+	while (!e->implicitConvTo(telem) && telem->toBasetype()->ty == Tsarray)
+	{   /* Static array initialization, as in:
+	     *	T[3][5] = e;
+	     */
+	    telem = telem->toBasetype()->nextOf();
+	}
+
+	e = e->implicitCastTo(sc, telem);
+
+	elements->data[i] = (void *)e;
+    }
+
+    /* Fill out remainder of elements[] with default initializers for fields[]
+     */
+    for (size_t i = elements->dim; i < sd->fields.dim; i++)
+    {	Dsymbol *s = (Dsymbol *)sd->fields.data[i];
+	VarDeclaration *v = s->isVarDeclaration();
+	assert(v);
+
+	if (v->offset < offset)
+	{   e = NULL;
+	    sd->hasUnions = 1;
+	}
+	else
+	{
+	    if (v->init)
+	    {   e = v->init->toExpression();
+		if (!e)
+		    error("cannot make expression out of initializer for %s", v->toChars());
+	    }
+	    else
+	    {	e = v->type->defaultInit();
+		e->loc = loc;
+	    }
+	    offset = v->offset + v->type->size();
+	}
+	elements->push(e);
+    }
+
+    type = sd->type;
+    return this;
+}
+
+/**************************************
+ * Gets expression at offset of type.
+ * Returns NULL if not found.
+ */
+
+Expression *StructLiteralExp::getField(Type *type, unsigned offset)
+{   Expression *e = NULL;
+    int i = getFieldIndex(type, offset);
+
+    if (i != -1)
+    {   e = (Expression *)elements->data[i];
+	if (e)
+	{
+	    e = e->copy();
+	    e->type = type;
+	}
+    }
+    return e;
+}
+
+/************************************
+ * Get index of field.
+ * Returns -1 if not found.
+ */
+
+int StructLiteralExp::getFieldIndex(Type *type, unsigned offset)
+{
+    /* Find which field offset is by looking at the field offsets
+     */
+    for (size_t i = 0; i < sd->fields.dim; i++)
+    {
+	Dsymbol *s = (Dsymbol *)sd->fields.data[i];
+	VarDeclaration *v = s->isVarDeclaration();
+	assert(v);
+
+	if (offset == v->offset &&
+	    type->size() == v->type->size())
+	{   Expression *e = (Expression *)elements->data[i];
+	    if (e)
+	    {
+		return i;
+	    }
+	    break;
+	}
+    }
+    return -1;
+}
+
+
+Expression *StructLiteralExp::toLvalue(Scope *sc, Expression *e)
+{
+    return this;
+}
+
+
+int StructLiteralExp::checkSideEffect(int flag)
+{   int f = 0;
+
+    for (size_t i = 0; i < elements->dim; i++)
+    {	Expression *e = (Expression *)elements->data[i];
+	if (!e)
+	    continue;
+
+	f |= e->checkSideEffect(2);
+    }
+    if (flag == 0 && f == 0)
+	Expression::checkSideEffect(0);
+    return f;
+}
+
+void StructLiteralExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring(sd->toChars());
+    buf->writeByte('(');
+    argsToCBuffer(buf, elements, hgs);
+    buf->writeByte(')');
+}
+
+void StructLiteralExp::toMangleBuffer(OutBuffer *buf)
+{
+    size_t dim = elements ? elements->dim : 0;
+    buf->printf("S%u", dim);
+    for (size_t i = 0; i < dim; i++)
+    {	Expression *e = (Expression *)elements->data[i];
+	if (e)
+	    e->toMangleBuffer(buf);
+	else
+	    buf->writeByte('v');	// 'v' for void
+    }
+}
+
+/************************ TypeDotIdExp ************************************/
+
+/* Things like:
+ *	int.size
+ *	foo.size
+ *	(foo).size
+ *	cast(foo).size
+ */
+
+TypeDotIdExp::TypeDotIdExp(Loc loc, Type *type, Identifier *ident)
+    : Expression(loc, TOKtypedot, sizeof(TypeDotIdExp))
+{
+    this->type = type;
+    this->ident = ident;
+}
+
+Expression *TypeDotIdExp::syntaxCopy()
+{
+    TypeDotIdExp *te = new TypeDotIdExp(loc, type->syntaxCopy(), ident);
+    return te;
+}
+
+Expression *TypeDotIdExp::semantic(Scope *sc)
+{   Expression *e;
+
+#if LOGSEMANTIC
+    printf("TypeDotIdExp::semantic()\n");
+#endif
+    e = new DotIdExp(loc, new TypeExp(loc, type), ident);
+    e = e->semantic(sc);
+    return e;
+}
+
+void TypeDotIdExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writeByte('(');
+    type->toCBuffer(buf, NULL, hgs);
+    buf->writeByte(')');
+    buf->writeByte('.');
+    buf->writestring(ident->toChars());
+}
+
+/************************************************************/
+
+// Mainly just a placeholder
+
+TypeExp::TypeExp(Loc loc, Type *type)
+    : Expression(loc, TOKtype, sizeof(TypeExp))
+{
+    //printf("TypeExp::TypeExp(%s)\n", type->toChars());
+    this->type = type;
+}
+
+Expression *TypeExp::semantic(Scope *sc)
+{
+    //printf("TypeExp::semantic(%s)\n", type->toChars());
+    type = type->semantic(loc, sc);
+    return this;
+}
+
+void TypeExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    type->toCBuffer(buf, NULL, hgs);
+}
+
+/************************************************************/
+
+// Mainly just a placeholder
+
+ScopeExp::ScopeExp(Loc loc, ScopeDsymbol *pkg)
+    : Expression(loc, TOKimport, sizeof(ScopeExp))
+{
+    //printf("ScopeExp::ScopeExp(pkg = '%s')\n", pkg->toChars());
+    //static int count; if (++count == 38) *(char*)0=0;
+    this->sds = pkg;
+}
+
+Expression *ScopeExp::syntaxCopy()
+{
+    ScopeExp *se = new ScopeExp(loc, (ScopeDsymbol *)sds->syntaxCopy(NULL));
+    return se;
+}
+
+Expression *ScopeExp::semantic(Scope *sc)
+{
+    TemplateInstance *ti;
+    ScopeDsymbol *sds2;
+
+#if LOGSEMANTIC
+    printf("+ScopeExp::semantic('%s')\n", toChars());
+#endif
+Lagain:
+    ti = sds->isTemplateInstance();
+    if (ti && !global.errors)
+    {	Dsymbol *s;
+	if (!ti->semanticdone)
+	    ti->semantic(sc);
+	s = ti->inst->toAlias();
+	sds2 = s->isScopeDsymbol();
+	if (!sds2)
+	{   Expression *e;
+
+	    //printf("s = %s, '%s'\n", s->kind(), s->toChars());
+	    if (ti->withsym)
+	    {
+		// Same as wthis.s
+		e = new VarExp(loc, ti->withsym->withstate->wthis);
+		e = new DotVarExp(loc, e, s->isDeclaration());
+	    }
+	    else
+		e = new DsymbolExp(loc, s);
+	    e = e->semantic(sc);
+	    //printf("-1ScopeExp::semantic()\n");
+	    return e;
+	}
+	if (sds2 != sds)
+	{
+	    sds = sds2;
+	    goto Lagain;
+	}
+	//printf("sds = %s, '%s'\n", sds->kind(), sds->toChars());
+    }
+    else
+    {
+	//printf("sds = %s, '%s'\n", sds->kind(), sds->toChars());
+	//printf("\tparent = '%s'\n", sds->parent->toChars());
+	sds->semantic(sc);
+    }
+    type = Type::tvoid;
+    //printf("-2ScopeExp::semantic() %s\n", toChars());
+    return this;
+}
+
+void ScopeExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    if (sds->isTemplateInstance())
+    {
+        sds->toCBuffer(buf, hgs);
+    }
+    else
+    {
+	buf->writestring(sds->kind());
+	buf->writestring(" ");
+	buf->writestring(sds->toChars());
+    }
+}
+
+/********************** TemplateExp **************************************/
+
+// Mainly just a placeholder
+
+TemplateExp::TemplateExp(Loc loc, TemplateDeclaration *td)
+    : Expression(loc, TOKtemplate, sizeof(TemplateExp))
+{
+    //printf("TemplateExp(): %s\n", td->toChars());
+    this->td = td;
+}
+
+void TemplateExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring(td->toChars());
+}
+
+void TemplateExp::rvalue()
+{
+    error("template %s has no value", toChars());
+}
+
+/********************** NewExp **************************************/
+
+NewExp::NewExp(Loc loc, Expression *thisexp, Expressions *newargs,
+	Type *newtype, Expressions *arguments)
+    : Expression(loc, TOKnew, sizeof(NewExp))
+{
+    this->thisexp = thisexp;
+    this->newargs = newargs;
+    this->newtype = newtype;
+    this->arguments = arguments;
+    member = NULL;
+    allocator = NULL;
+    onstack = 0;
+}
+
+Expression *NewExp::syntaxCopy()
+{
+    return new NewExp(loc,
+	thisexp ? thisexp->syntaxCopy() : NULL,
+	arraySyntaxCopy(newargs),
+	newtype->syntaxCopy(), arraySyntaxCopy(arguments));
+}
+
+
+Expression *NewExp::semantic(Scope *sc)
+{   int i;
+    Type *tb;
+    ClassDeclaration *cdthis = NULL;
+
+#if LOGSEMANTIC
+    printf("NewExp::semantic() %s\n", toChars());
+    if (thisexp)
+	printf("\tthisexp = %s\n", thisexp->toChars());
+    printf("\tnewtype: %s\n", newtype->toChars());
+#endif
+    if (type)			// if semantic() already run
+	return this;
+
+Lagain:
+    if (thisexp)
+    {	thisexp = thisexp->semantic(sc);
+	cdthis = thisexp->type->isClassHandle();
+	if (cdthis)
+	{
+	    sc = sc->push(cdthis);
+	    type = newtype->semantic(loc, sc);
+	    sc = sc->pop();
+	}
+	else
+	{
+	    error("'this' for nested class must be a class type, not %s", thisexp->type->toChars());
+	    type = newtype->semantic(loc, sc);
+	}
+    }
+    else
+	type = newtype->semantic(loc, sc);
+    newtype = type;		// in case type gets cast to something else
+    tb = type->toBasetype();
+    //printf("tb: %s, deco = %s\n", tb->toChars(), tb->deco);
+
+    arrayExpressionSemantic(newargs, sc);
+    preFunctionArguments(loc, sc, newargs);
+    arrayExpressionSemantic(arguments, sc);
+    preFunctionArguments(loc, sc, arguments);
+
+    if (thisexp && tb->ty != Tclass)
+	error("e.new is only for allocating nested classes, not %s", tb->toChars());
+
+    if (tb->ty == Tclass)
+    {	TypeFunction *tf;
+
+	TypeClass *tc = (TypeClass *)(tb);
+	ClassDeclaration *cd = tc->sym->isClassDeclaration();
+	if (cd->isInterfaceDeclaration())
+	    error("cannot create instance of interface %s", cd->toChars());
+	else if (cd->isAbstract())
+	    error("cannot create instance of abstract class %s", cd->toChars());
+	checkDeprecated(sc, cd);
+	if (cd->isNested())
+	{   /* We need a 'this' pointer for the nested class.
+	     * Ensure we have the right one.
+	     */
+	    Dsymbol *s = cd->toParent2();
+	    ClassDeclaration *cdn = s->isClassDeclaration();
+
+	    //printf("isNested, cdn = %s\n", cdn ? cdn->toChars() : "null");
+	    if (cdn)
+	    {
+		if (!cdthis)
+		{
+		    // Supply an implicit 'this' and try again
+		    thisexp = new ThisExp(loc);
+		    for (Dsymbol *sp = sc->parent; 1; sp = sp->parent)
+		    {	if (!sp)
+			{
+			    error("outer class %s 'this' needed to 'new' nested class %s", cdn->toChars(), cd->toChars());
+			    break;
+			}
+			ClassDeclaration *cdp = sp->isClassDeclaration();
+			if (!cdp)
+			    continue;
+			if (cdp == cdn || cdn->isBaseOf(cdp, NULL))
+			    break;
+			// Add a '.outer' and try again
+			thisexp = new DotIdExp(loc, thisexp, Id::outer);
+		    }
+		    if (!global.errors)
+			goto Lagain;
+		}
+		if (cdthis)
+		{
+		    //printf("cdthis = %s\n", cdthis->toChars());
+		    if (cdthis != cdn && !cdn->isBaseOf(cdthis, NULL))
+			error("'this' for nested class must be of type %s, not %s", cdn->toChars(), thisexp->type->toChars());
+		}
+#if 0
+		else
+		{
+		    for (Dsymbol *sf = sc->func; 1; sf= sf->toParent2()->isFuncDeclaration())
+		    {
+			if (!sf)
+			{
+			    error("outer class %s 'this' needed to 'new' nested class %s", cdn->toChars(), cd->toChars());
+			    break;
+			}
+			printf("sf = %s\n", sf->toChars());
+			AggregateDeclaration *ad = sf->isThis();
+			if (ad && (ad == cdn || cdn->isBaseOf(ad->isClassDeclaration(), NULL)))
+			    break;
+		    }
+		}
+#endif
+	    }
+	    else if (thisexp)
+		error("e.new is only for allocating nested classes");
+	}
+	else if (thisexp)
+	    error("e.new is only for allocating nested classes");
+
+	FuncDeclaration *f = cd->ctor;
+	if (f)
+	{
+	    assert(f);
+	    f = f->overloadResolve(loc, arguments);
+	    checkDeprecated(sc, f);
+	    member = f->isCtorDeclaration();
+	    assert(member);
+
+	    cd->accessCheck(loc, sc, member);
+
+	    tf = (TypeFunction *)f->type;
+	    type = tf->next;
+
+	    if (!arguments)
+		arguments = new Expressions();
+	    functionArguments(loc, sc, tf, arguments);
+	}
+	else
+	{
+	    if (arguments && arguments->dim)
+		error("no constructor for %s", cd->toChars());
+	}
+
+	if (cd->aggNew)
+	{   Expression *e;
+
+	    f = cd->aggNew;
+
+	    // Prepend the uint size argument to newargs[]
+	    e = new IntegerExp(loc, cd->size(loc), Type::tuns32);
+	    if (!newargs)
+		newargs = new Expressions();
+	    newargs->shift(e);
+
+	    f = f->overloadResolve(loc, newargs);
+	    allocator = f->isNewDeclaration();
+	    assert(allocator);
+
+	    tf = (TypeFunction *)f->type;
+	    functionArguments(loc, sc, tf, newargs);
+	}
+	else
+	{
+	    if (newargs && newargs->dim)
+		error("no allocator for %s", cd->toChars());
+	}
+
+    }
+    else if (tb->ty == Tstruct)
+    {
+	TypeStruct *ts = (TypeStruct *)tb;
+	StructDeclaration *sd = ts->sym;
+	FuncDeclaration *f = sd->aggNew;
+	TypeFunction *tf;
+
+	if (arguments && arguments->dim)
+	    error("no constructor for %s", type->toChars());
+
+	if (f)
+	{
+	    Expression *e;
+
+	    // Prepend the uint size argument to newargs[]
+	    e = new IntegerExp(loc, sd->size(loc), Type::tuns32);
+	    if (!newargs)
+		newargs = new Expressions();
+	    newargs->shift(e);
+
+	    f = f->overloadResolve(loc, newargs);
+	    allocator = f->isNewDeclaration();
+	    assert(allocator);
+
+	    tf = (TypeFunction *)f->type;
+	    functionArguments(loc, sc, tf, newargs);
+
+	    e = new VarExp(loc, f);
+	    e = new CallExp(loc, e, newargs);
+	    e = e->semantic(sc);
+	    e->type = type->pointerTo();
+	    return e;
+	}
+
+	type = type->pointerTo();
+    }
+    else if (tb->ty == Tarray && (arguments && arguments->dim))
+    {
+	for (size_t i = 0; i < arguments->dim; i++)
+	{
+	    if (tb->ty != Tarray)
+	    {	error("too many arguments for array");
+		arguments->dim = i;
+		break;
+	    }
+
+	    Expression *arg = (Expression *)arguments->data[i];
+	    arg = resolveProperties(sc, arg);
+	    arg = arg->implicitCastTo(sc, Type::tsize_t);
+	    if (arg->op == TOKint64 && (long long)arg->toInteger() < 0)
+		error("negative array index %s", arg->toChars());
+	    arguments->data[i] = (void *) arg;
+	    tb = tb->next->toBasetype();
+	}
+    }
+    else if (tb->isscalar())
+    {
+	if (arguments && arguments->dim)
+	    error("no constructor for %s", type->toChars());
+
+	type = type->pointerTo();
+    }
+    else
+    {
+	error("new can only create structs, dynamic arrays or class objects, not %s's", type->toChars());
+	type = type->pointerTo();
+    }
+
+//printf("NewExp: '%s'\n", toChars());
+//printf("NewExp:type '%s'\n", type->toChars());
+
+    return this;
+}
+
+int NewExp::checkSideEffect(int flag)
+{
+    return 1;
+}
+
+void NewExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{   int i;
+
+    if (thisexp)
+    {	expToCBuffer(buf, hgs, thisexp, PREC_primary);
+	buf->writeByte('.');
+    }
+    buf->writestring("new ");
+    if (newargs && newargs->dim)
+    {
+	buf->writeByte('(');
+	argsToCBuffer(buf, newargs, hgs);
+	buf->writeByte(')');
+    }
+    newtype->toCBuffer(buf, NULL, hgs);
+    if (arguments && arguments->dim)
+    {
+	buf->writeByte('(');
+	argsToCBuffer(buf, arguments, hgs);
+	buf->writeByte(')');
+    }
+}
+
+/********************** NewAnonClassExp **************************************/
+
+NewAnonClassExp::NewAnonClassExp(Loc loc, Expression *thisexp,
+	Expressions *newargs, ClassDeclaration *cd, Expressions *arguments)
+    : Expression(loc, TOKnewanonclass, sizeof(NewAnonClassExp))
+{
+    this->thisexp = thisexp;
+    this->newargs = newargs;
+    this->cd = cd;
+    this->arguments = arguments;
+}
+
+Expression *NewAnonClassExp::syntaxCopy()
+{
+    return new NewAnonClassExp(loc,
+	thisexp ? thisexp->syntaxCopy() : NULL,
+	arraySyntaxCopy(newargs),
+	(ClassDeclaration *)cd->syntaxCopy(NULL),
+	arraySyntaxCopy(arguments));
+}
+
+
+Expression *NewAnonClassExp::semantic(Scope *sc)
+{
+#if LOGSEMANTIC
+    printf("NewAnonClassExp::semantic() %s\n", toChars());
+    //printf("type: %s\n", type->toChars());
+#endif
+
+    Expression *d = new DeclarationExp(loc, cd);
+    d = d->semantic(sc);
+
+    Expression *n = new NewExp(loc, thisexp, newargs, cd->type, arguments);
+
+    Expression *c = new CommaExp(loc, d, n);
+    return c->semantic(sc);
+}
+
+int NewAnonClassExp::checkSideEffect(int flag)
+{
+    return 1;
+}
+
+void NewAnonClassExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{   int i;
+
+    if (thisexp)
+    {	expToCBuffer(buf, hgs, thisexp, PREC_primary);
+	buf->writeByte('.');
+    }
+    buf->writestring("new");
+    if (newargs && newargs->dim)
+    {
+	buf->writeByte('(');
+	argsToCBuffer(buf, newargs, hgs);
+	buf->writeByte(')');
+    }
+    buf->writestring(" class ");
+    if (arguments && arguments->dim)
+    {
+	buf->writeByte('(');
+	argsToCBuffer(buf, arguments, hgs);
+	buf->writeByte(')');
+    }
+    //buf->writestring(" { }");
+    if (cd)
+    {
+        cd->toCBuffer(buf, hgs);
+    }
+}
+
+/********************** SymOffExp **************************************/
+
+SymOffExp::SymOffExp(Loc loc, Declaration *var, unsigned offset)
+    : Expression(loc, TOKsymoff, sizeof(SymOffExp))
+{
+    assert(var);
+    this->var = var;
+    this->offset = offset;
+    VarDeclaration *v = var->isVarDeclaration();
+    if (v && v->needThis())
+	error("need 'this' for address of %s", v->toChars());
+}
+
+Expression *SymOffExp::semantic(Scope *sc)
+{
+#if LOGSEMANTIC
+    printf("SymOffExp::semantic('%s')\n", toChars());
+#endif
+    //var->semantic(sc);
+    if (!type)
+	type = var->type->pointerTo();
+    VarDeclaration *v = var->isVarDeclaration();
+    if (v)
+	v->checkNestedReference(sc, loc);
+    return this;
+}
+
+int SymOffExp::isBool(int result)
+{
+    return result ? TRUE : FALSE;
+}
+
+void SymOffExp::checkEscape()
+{
+    VarDeclaration *v = var->isVarDeclaration();
+    if (v)
+    {
+	if (!v->isDataseg())
+	    error("escaping reference to local variable %s", v->toChars());
+    }
+}
+
+void SymOffExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    if (offset)
+	buf->printf("(& %s+%u)", var->toChars(), offset);
+    else
+	buf->printf("& %s", var->toChars());
+}
+
+/******************************** VarExp **************************/
+
+VarExp::VarExp(Loc loc, Declaration *var)
+	: Expression(loc, TOKvar, sizeof(VarExp))
+{
+    //printf("VarExp(this = %p, '%s')\n", this, var->toChars());
+    this->var = var;
+    this->type = var->type;
+}
+
+int VarExp::equals(Object *o)
+{   VarExp *ne;
+
+    if (this == o ||
+	(((Expression *)o)->op == TOKvar &&
+	 ((ne = (VarExp *)o), type->equals(ne->type)) &&
+	 var == ne->var))
+	return 1;
+    return 0;
+}
+
+Expression *VarExp::semantic(Scope *sc)
+{   FuncLiteralDeclaration *fd;
+
+#if LOGSEMANTIC
+    printf("VarExp::semantic(%s)\n", toChars());
+#endif
+    if (!type)
+    {	type = var->type;
+#if 0
+	if (var->storage_class & STClazy)
+	{
+	    TypeFunction *tf = new TypeFunction(NULL, type, 0, LINKd);
+	    type = new TypeDelegate(tf);
+	    type = type->semantic(loc, sc);
+	}
+#endif
+    }
+
+    VarDeclaration *v = var->isVarDeclaration();
+    if (v)
+    {
+	if (v->isConst() && type->toBasetype()->ty != Tsarray && v->init)
+	{
+	    ExpInitializer *ei = v->init->isExpInitializer();
+	    if (ei)
+	    {
+		//ei->exp->implicitCastTo(sc, type)->print();
+		return ei->exp->implicitCastTo(sc, type);
+	    }
+	}
+	v->checkNestedReference(sc, loc);
+    }
+#if 0
+    else if ((fd = var->isFuncLiteralDeclaration()) != NULL)
+    {	Expression *e;
+	e = new FuncExp(loc, fd);
+	e->type = type;
+	return e;
+    }
+#endif
+    return this;
+}
+
+char *VarExp::toChars()
+{
+    return var->toChars();
+}
+
+void VarExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring(var->toChars());
+}
+
+void VarExp::checkEscape()
+{
+    VarDeclaration *v = var->isVarDeclaration();
+    if (v)
+    {	Type *tb = v->type->toBasetype();
+	// if reference type
+	if (tb->ty == Tarray || tb->ty == Tsarray || tb->ty == Tclass)
+	{
+	    if ((v->isAuto() || v->isScope()) && !v->noauto)
+		error("escaping reference to auto local %s", v->toChars());
+	    else if (v->storage_class & STCvariadic)
+		error("escaping reference to variadic parameter %s", v->toChars());
+	}
+    }
+}
+
+Expression *VarExp::toLvalue(Scope *sc, Expression *e)
+{
+#if 0
+    tym = tybasic(e1->ET->Tty);
+    if (!(tyscalar(tym) ||
+	  tym == TYstruct ||
+	  tym == TYarray && e->Eoper == TOKaddr))
+	    synerr(EM_lvalue);	// lvalue expected
+#endif
+    if (var->storage_class & STClazy)
+	error("lazy variables cannot be lvalues");
+    return this;
+}
+
+Expression *VarExp::modifiableLvalue(Scope *sc, Expression *e)
+{
+    //printf("VarExp::modifiableLvalue('%s')\n", var->toChars());
+    if (sc->incontract && var->isParameter())
+	error("cannot modify parameter '%s' in contract", var->toChars());
+
+    if (type && type->toBasetype()->ty == Tsarray)
+	error("cannot change reference to static array '%s'", var->toChars());
+
+    VarDeclaration *v = var->isVarDeclaration();
+    if (v && v->canassign == 0 &&
+        (var->isConst() || (global.params.Dversion > 1 && var->isFinal())))
+	error("cannot modify final variable '%s'", var->toChars());
+
+    if (var->isCtorinit())
+    {	// It's only modifiable if inside the right constructor
+	Dsymbol *s = sc->func;
+	while (1)
+	{
+	    FuncDeclaration *fd = NULL;
+	    if (s)
+		fd = s->isFuncDeclaration();
+	    if (fd &&
+		((fd->isCtorDeclaration() && var->storage_class & STCfield) ||
+		 (fd->isStaticCtorDeclaration() && !(var->storage_class & STCfield))) &&
+		fd->toParent() == var->toParent()
+	       )
+	    {
+		VarDeclaration *v = var->isVarDeclaration();
+		assert(v);
+		v->ctorinit = 1;
+		//printf("setting ctorinit\n");
+	    }
+	    else
+	    {
+		if (s)
+		{   s = s->toParent2();
+		    continue;
+		}
+		else
+		{
+		    const char *p = var->isStatic() ? "static " : "";
+		    error("can only initialize %sconst %s inside %sconstructor",
+			p, var->toChars(), p);
+		}
+	    }
+	    break;
+	}
+    }
+
+    // See if this expression is a modifiable lvalue (i.e. not const)
+    return toLvalue(sc, e);
+}
+
+
+/******************************** TupleExp **************************/
+
+TupleExp::TupleExp(Loc loc, Expressions *exps)
+	: Expression(loc, TOKtuple, sizeof(TupleExp))
+{
+    //printf("TupleExp(this = %p)\n", this);
+    this->exps = exps;
+    this->type = NULL;
+}
+
+
+TupleExp::TupleExp(Loc loc, TupleDeclaration *tup)
+	: Expression(loc, TOKtuple, sizeof(TupleExp))
+{
+    exps = new Expressions();
+    type = NULL;
+
+    exps->reserve(tup->objects->dim);
+    for (size_t i = 0; i < tup->objects->dim; i++)
+    {   Object *o = (Object *)tup->objects->data[i];
+	if (o->dyncast() == DYNCAST_EXPRESSION)
+	{
+	    Expression *e = (Expression *)o;
+	    e = e->syntaxCopy();
+	    exps->push(e);
+	}
+	else if (o->dyncast() == DYNCAST_DSYMBOL)
+	{
+	    Dsymbol *s = (Dsymbol *)o;
+	    Expression *e = new DsymbolExp(loc, s);
+	    exps->push(e);
+	}
+	else if (o->dyncast() == DYNCAST_TYPE)
+	{
+	    Type *t = (Type *)o;
+	    Expression *e = new TypeExp(loc, t);
+	    exps->push(e);
+	}
+	else
+	{
+	    error("%s is not an expression", o->toChars());
+	}
+    }
+}
+
+int TupleExp::equals(Object *o)
+{   TupleExp *ne;
+
+    if (this == o)
+	return 1;
+    if (((Expression *)o)->op == TOKtuple)
+    {
+	TupleExp *te = (TupleExp *)o;
+	if (exps->dim != te->exps->dim)
+	    return 0;
+	for (size_t i = 0; i < exps->dim; i++)
+	{   Expression *e1 = (Expression *)exps->data[i];
+	    Expression *e2 = (Expression *)te->exps->data[i];
+
+	    if (!e1->equals(e2))
+		return 0;
+	}
+	return 1;
+    }
+    return 0;
+}
+
+Expression *TupleExp::syntaxCopy()
+{
+    return new TupleExp(loc, arraySyntaxCopy(exps));
+}
+
+Expression *TupleExp::semantic(Scope *sc)
+{
+#if LOGSEMANTIC
+    printf("+TupleExp::semantic(%s)\n", toChars());
+#endif
+    if (type)
+	return this;
+
+    // Run semantic() on each argument
+    for (size_t i = 0; i < exps->dim; i++)
+    {	Expression *e = (Expression *)exps->data[i];
+
+	e = e->semantic(sc);
+	if (!e->type)
+	{   error("%s has no value", e->toChars());
+	    e->type = Type::terror;
+	}
+	exps->data[i] = (void *)e;
+    }
+
+    expandTuples(exps);
+    if (0 && exps->dim == 1)
+    {
+	return (Expression *)exps->data[0];
+    }
+    type = new TypeTuple(exps);
+    //printf("-TupleExp::semantic(%s)\n", toChars());
+    return this;
+}
+
+void TupleExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("tuple(");
+    argsToCBuffer(buf, exps, hgs);
+    buf->writeByte(')');
+}
+
+int TupleExp::checkSideEffect(int flag)
+{   int f = 0;
+
+    for (int i = 0; i < exps->dim; i++)
+    {	Expression *e = (Expression *)exps->data[i];
+
+	f |= e->checkSideEffect(2);
+    }
+    if (flag == 0 && f == 0)
+	Expression::checkSideEffect(0);
+    return f;
+}
+
+void TupleExp::checkEscape()
+{
+    for (size_t i = 0; i < exps->dim; i++)
+    {   Expression *e = (Expression *)exps->data[i];
+	e->checkEscape();
+    }
+}
+
+/******************************** FuncExp *********************************/
+
+FuncExp::FuncExp(Loc loc, FuncLiteralDeclaration *fd)
+	: Expression(loc, TOKfunction, sizeof(FuncExp))
+{
+    this->fd = fd;
+}
+
+Expression *FuncExp::syntaxCopy()
+{
+    return new FuncExp(loc, (FuncLiteralDeclaration *)fd->syntaxCopy(NULL));
+}
+
+Expression *FuncExp::semantic(Scope *sc)
+{
+#if LOGSEMANTIC
+    printf("FuncExp::semantic(%s)\n", toChars());
+#endif
+    if (!type)
+    {
+	fd->semantic(sc);
+	fd->parent = sc->parent;
+	if (global.errors)
+	{
+	    if (!fd->type->next)
+		fd->type->next = Type::terror;
+	}
+	else
+	{
+	    fd->semantic2(sc);
+	    if (!global.errors)
+	    {
+		fd->semantic3(sc);
+
+		if (!global.errors && global.params.useInline)
+		    fd->inlineScan();
+	    }
+	}
+
+	// Type is a "delegate to" or "pointer to" the function literal
+	if (fd->isNested())
+	{
+	    type = new TypeDelegate(fd->type);
+	    type = type->semantic(loc, sc);
+	}
+	else
+	{
+	    type = fd->type->pointerTo();
+	}
+    }
+    return this;
+}
+
+char *FuncExp::toChars()
+{
+    return fd->toChars();
+}
+
+void FuncExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring(fd->toChars());
+}
+
+
+/******************************** DeclarationExp **************************/
+
+DeclarationExp::DeclarationExp(Loc loc, Dsymbol *declaration)
+	: Expression(loc, TOKdeclaration, sizeof(DeclarationExp))
+{
+    this->declaration = declaration;
+}
+
+Expression *DeclarationExp::syntaxCopy()
+{
+    return new DeclarationExp(loc, declaration->syntaxCopy(NULL));
+}
+
+Expression *DeclarationExp::semantic(Scope *sc)
+{
+    if (type)
+	return this;
+
+#if LOGSEMANTIC
+    printf("DeclarationExp::semantic() %s\n", toChars());
+#endif
+
+    /* This is here to support extern(linkage) declaration,
+     * where the extern(linkage) winds up being an AttribDeclaration
+     * wrapper.
+     */
+    Dsymbol *s = declaration;
+
+    AttribDeclaration *ad = declaration->isAttribDeclaration();
+    if (ad)
+    {
+	if (ad->decl && ad->decl->dim == 1)
+	    s = (Dsymbol *)ad->decl->data[0];
+    }
+
+    if (s->isVarDeclaration())
+    {	// Do semantic() on initializer first, so:
+	//	int a = a;
+	// will be illegal.
+	declaration->semantic(sc);
+	s->parent = sc->parent;
+    }
+
+    //printf("inserting '%s' %p into sc = %p\n", s->toChars(), s, sc);
+    // Insert into both local scope and function scope.
+    // Must be unique in both.
+    if (s->ident)
+    {
+	if (!sc->insert(s))
+	    error("declaration %s is already defined", s->toPrettyChars());
+	else if (sc->func)
+	{   VarDeclaration *v = s->isVarDeclaration();
+	    if ((s->isFuncDeclaration() /*|| v && v->storage_class & STCstatic*/) &&
+		!sc->func->localsymtab->insert(s))
+		error("declaration %s is already defined in another scope in %s", s->toPrettyChars(), sc->func->toChars());
+	    else if (!global.params.useDeprecated)
+	    {	// Disallow shadowing
+
+		for (Scope *scx = sc->enclosing; scx && scx->func == sc->func; scx = scx->enclosing)
+		{   Dsymbol *s2;
+
+		    if (scx->scopesym && scx->scopesym->symtab &&
+			(s2 = scx->scopesym->symtab->lookup(s->ident)) != NULL &&
+			s != s2)
+		    {
+			error("shadowing declaration %s is deprecated", s->toPrettyChars());
+		    }
+		}
+	    }
+	}
+    }
+    if (!s->isVarDeclaration())
+    {
+	declaration->semantic(sc);
+	s->parent = sc->parent;
+    }
+    if (!global.errors)
+    {
+	declaration->semantic2(sc);
+	if (!global.errors)
+	{
+	    declaration->semantic3(sc);
+
+	    if (!global.errors && global.params.useInline)
+		declaration->inlineScan();
+	}
+    }
+
+    type = Type::tvoid;
+    return this;
+}
+
+int DeclarationExp::checkSideEffect(int flag)
+{
+    return 1;
+}
+
+void DeclarationExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    declaration->toCBuffer(buf, hgs);
+}
+
+
+/************************ TypeidExp ************************************/
+
+/*
+ *	typeid(int)
+ */
+
+TypeidExp::TypeidExp(Loc loc, Type *typeidType)
+    : Expression(loc, TOKtypeid, sizeof(TypeidExp))
+{
+    this->typeidType = typeidType;
+}
+
+
+Expression *TypeidExp::syntaxCopy()
+{
+    return new TypeidExp(loc, typeidType->syntaxCopy());
+}
+
+
+Expression *TypeidExp::semantic(Scope *sc)
+{   Expression *e;
+
+#if LOGSEMANTIC
+    printf("TypeidExp::semantic()\n");
+#endif
+    typeidType = typeidType->semantic(loc, sc);
+    e = typeidType->getTypeInfo(sc);
+    return e;
+}
+
+void TypeidExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("typeid(");
+    typeidType->toCBuffer(buf, NULL, hgs);
+    buf->writeByte(')');
+}
+
+/************************************************************/
+
+HaltExp::HaltExp(Loc loc)
+	: Expression(loc, TOKhalt, sizeof(HaltExp))
+{
+}
+
+Expression *HaltExp::semantic(Scope *sc)
+{
+#if LOGSEMANTIC
+    printf("HaltExp::semantic()\n");
+#endif
+    type = Type::tvoid;
+    return this;
+}
+
+int HaltExp::checkSideEffect(int flag)
+{
+    return 1;
+}
+
+void HaltExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("halt");
+}
+
+/************************************************************/
+
+IftypeExp::IftypeExp(Loc loc, Type *targ, Identifier *id, enum TOK tok,
+	Type *tspec, enum TOK tok2)
+	: Expression(loc, TOKis, sizeof(IftypeExp))
+{
+    this->targ = targ;
+    this->id = id;
+    this->tok = tok;
+    this->tspec = tspec;
+    this->tok2 = tok2;
+}
+
+Expression *IftypeExp::syntaxCopy()
+{
+    return new IftypeExp(loc,
+	targ->syntaxCopy(),
+	id,
+	tok,
+	tspec ? tspec->syntaxCopy() : NULL,
+	tok2);
+}
+
+Expression *IftypeExp::semantic(Scope *sc)
+{   Type *tded;
+
+    //printf("IftypeExp::semantic()\n");
+    if (id && !(sc->flags & SCOPEstaticif))
+	error("can only declare type aliases within static if conditionals");
+
+    unsigned errors_save = global.errors;
+    global.errors = 0;
+    global.gag++;			// suppress printing of error messages
+    targ = targ->semantic(loc, sc);
+    global.gag--;
+    unsigned gerrors = global.errors;
+    global.errors = errors_save;
+
+    if (gerrors)			// if any errors happened
+    {					// then condition is false
+	goto Lno;
+    }
+    else if (tok2 != TOKreserved)
+    {
+	switch (tok2)
+	{
+	    case TOKtypedef:
+		if (targ->ty != Ttypedef)
+		    goto Lno;
+		tded = ((TypeTypedef *)targ)->sym->basetype;
+		break;
+
+	    case TOKstruct:
+		if (targ->ty != Tstruct)
+		    goto Lno;
+		if (((TypeStruct *)targ)->sym->isUnionDeclaration())
+		    goto Lno;
+		tded = targ;
+		break;
+
+	    case TOKunion:
+		if (targ->ty != Tstruct)
+		    goto Lno;
+		if (!((TypeStruct *)targ)->sym->isUnionDeclaration())
+		    goto Lno;
+		tded = targ;
+		break;
+
+	    case TOKclass:
+		if (targ->ty != Tclass)
+		    goto Lno;
+		if (((TypeClass *)targ)->sym->isInterfaceDeclaration())
+		    goto Lno;
+		tded = targ;
+		break;
+
+	    case TOKinterface:
+		if (targ->ty != Tclass)
+		    goto Lno;
+		if (!((TypeClass *)targ)->sym->isInterfaceDeclaration())
+		    goto Lno;
+		tded = targ;
+		break;
+
+	    case TOKsuper:
+		// If class or interface, get the base class and interfaces
+		if (targ->ty != Tclass)
+		    goto Lno;
+		else
+		{   ClassDeclaration *cd = ((TypeClass *)targ)->sym;
+		    Arguments *args = new Arguments;
+		    args->reserve(cd->baseclasses.dim);
+		    for (size_t i = 0; i < cd->baseclasses.dim; i++)
+		    {	BaseClass *b = (BaseClass *)cd->baseclasses.data[i];
+			args->push(new Argument(STCin, b->type, NULL, NULL));
+		    }
+		    tded = new TypeTuple(args);
+		}
+		break;
+
+	    case TOKenum:
+		if (targ->ty != Tenum)
+		    goto Lno;
+		tded = ((TypeEnum *)targ)->sym->memtype;
+		break;
+
+	    case TOKdelegate:
+		if (targ->ty != Tdelegate)
+		    goto Lno;
+		tded = targ->next;	// the underlying function type
+		break;
+
+	    case TOKfunction:
+	    {	if (targ->ty != Tfunction)
+		    goto Lno;
+		tded = targ;
+
+		/* Generate tuple from function parameter types.
+		 */
+		assert(tded->ty == Tfunction);
+		Arguments *params = ((TypeFunction *)tded)->parameters;
+		size_t dim = Argument::dim(params);
+		Arguments *args = new Arguments;
+		args->reserve(dim);
+		for (size_t i = 0; i < dim; i++)
+		{   Argument *arg = Argument::getNth(params, i);
+		    assert(arg && arg->type);
+		    args->push(new Argument(arg->storageClass, arg->type, NULL, NULL));
+		}
+		tded = new TypeTuple(args);
+		break;
+	    }
+	    case TOKreturn:
+		/* Get the 'return type' for the function,
+		 * delegate, or pointer to function.
+		 */
+		if (targ->ty == Tfunction)
+		    tded = targ->next;
+		else if (targ->ty == Tdelegate)
+		    tded = targ->next->next;
+		else if (targ->ty == Tpointer && targ->next->ty == Tfunction)
+		    tded = targ->next->next;
+		else
+		    goto Lno;
+		break;
+
+	    default:
+		assert(0);
+	}
+	goto Lyes;
+    }
+    else if (id && tspec)
+    {
+	/* Evaluate to TRUE if targ matches tspec.
+	 * If TRUE, declare id as an alias for the specialized type.
+	 */
+
+	MATCH m;
+	TemplateTypeParameter tp(loc, id, NULL, NULL);
+
+	TemplateParameters parameters;
+	parameters.setDim(1);
+	parameters.data[0] = (void *)&tp;
+
+	Objects dedtypes;
+	dedtypes.setDim(1);
+	dedtypes.data[0] = NULL;
+
+	m = targ->deduceType(NULL, tspec, &parameters, &dedtypes);
+	if (m == MATCHnomatch ||
+	    (m != MATCHexact && tok == TOKequal))
+	    goto Lno;
+	else
+	{
+	    assert(dedtypes.dim == 1);
+	    tded = (Type *)dedtypes.data[0];
+	    if (!tded)
+		tded = targ;
+	    goto Lyes;
+	}
+    }
+    else if (id)
+    {
+	/* Declare id as an alias for type targ. Evaluate to TRUE
+	 */
+	tded = targ;
+	goto Lyes;
+    }
+    else if (tspec)
+    {
+	/* Evaluate to TRUE if targ matches tspec
+	 */
+	tspec = tspec->semantic(loc, sc);
+	//printf("targ  = %s\n", targ->toChars());
+	//printf("tspec = %s\n", tspec->toChars());
+	if (tok == TOKcolon)
+	{   if (targ->implicitConvTo(tspec))
+		goto Lyes;
+	    else
+		goto Lno;
+	}
+	else /* == */
+	{   if (targ->equals(tspec))
+		goto Lyes;
+	    else
+		goto Lno;
+	}
+    }
+
+Lyes:
+    if (id)
+    {
+	Dsymbol *s = new AliasDeclaration(loc, id, tded);
+	s->semantic(sc);
+	sc->insert(s);
+	if (sc->sd)
+	    s->addMember(sc, sc->sd, 1);
+    }
+    return new IntegerExp(1);
+
+Lno:
+    return new IntegerExp(0);
+}
+
+void IftypeExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("is(");
+    targ->toCBuffer(buf, id, hgs);
+    if (tspec)
+    {
+	if (tok == TOKcolon)
+	    buf->writestring(" : ");
+	else
+	    buf->writestring(" == ");
+	tspec->toCBuffer(buf, NULL, hgs);
+    }
+    buf->writeByte(')');
+}
+
+
+/************************************************************/
+
+UnaExp::UnaExp(Loc loc, enum TOK op, int size, Expression *e1)
+	: Expression(loc, op, size)
+{
+    this->e1 = e1;
+}
+
+Expression *UnaExp::syntaxCopy()
+{   UnaExp *e;
+
+    e = (UnaExp *)copy();
+    e->type = NULL;
+    e->e1 = e->e1->syntaxCopy();
+    return e;
+}
+
+Expression *UnaExp::semantic(Scope *sc)
+{
+#if LOGSEMANTIC
+    printf("UnaExp::semantic('%s')\n", toChars());
+#endif
+    e1 = e1->semantic(sc);
+//    if (!e1->type)
+//	error("%s has no value", e1->toChars());
+    return this;
+}
+
+void UnaExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring(Token::toChars(op));
+    expToCBuffer(buf, hgs, e1, precedence[op]);
+}
+
+/************************************************************/
+
+BinExp::BinExp(Loc loc, enum TOK op, int size, Expression *e1, Expression *e2)
+	: Expression(loc, op, size)
+{
+    this->e1 = e1;
+    this->e2 = e2;
+}
+
+Expression *BinExp::syntaxCopy()
+{   BinExp *e;
+
+    e = (BinExp *)copy();
+    e->type = NULL;
+    e->e1 = e->e1->syntaxCopy();
+    e->e2 = e->e2->syntaxCopy();
+    return e;
+}
+
+Expression *BinExp::semantic(Scope *sc)
+{
+#if LOGSEMANTIC
+    printf("BinExp::semantic('%s')\n", toChars());
+#endif
+    e1 = e1->semantic(sc);
+    if (!e1->type)
+    {
+	error("%s has no value", e1->toChars());
+	e1->type = Type::terror;
+    }
+    e2 = e2->semantic(sc);
+    if (!e2->type)
+    {
+	error("%s has no value", e2->toChars());
+	e2->type = Type::terror;
+    }
+    assert(e1->type);
+    return this;
+}
+
+Expression *BinExp::semanticp(Scope *sc)
+{
+    BinExp::semantic(sc);
+    e1 = resolveProperties(sc, e1);
+    e2 = resolveProperties(sc, e2);
+    return this;
+}
+
+/***************************
+ * Common semantic routine for some xxxAssignExp's.
+ */
+
+Expression *BinExp::commonSemanticAssign(Scope *sc)
+{   Expression *e;
+
+    if (!type)
+    {
+	BinExp::semantic(sc);
+	e2 = resolveProperties(sc, e2);
+
+	e = op_overload(sc);
+	if (e)
+	    return e;
+
+	e1 = e1->modifiableLvalue(sc, NULL);
+	e1->checkScalar();
+	type = e1->type;
+	if (type->toBasetype()->ty == Tbool)
+	{
+	    error("operator not allowed on bool expression %s", toChars());
+	}
+	typeCombine(sc);
+	e1->checkArithmetic();
+	e2->checkArithmetic();
+
+	if (op == TOKmodass && e2->type->iscomplex())
+	{   error("cannot perform modulo complex arithmetic");
+	    return new IntegerExp(0);
+	}
+    }
+    return this;
+}
+
+Expression *BinExp::commonSemanticAssignIntegral(Scope *sc)
+{   Expression *e;
+
+    if (!type)
+    {
+	BinExp::semantic(sc);
+	e2 = resolveProperties(sc, e2);
+
+	e = op_overload(sc);
+	if (e)
+	    return e;
+
+	e1 = e1->modifiableLvalue(sc, NULL);
+	e1->checkScalar();
+	type = e1->type;
+	if (type->toBasetype()->ty == Tbool)
+	{
+	    e2 = e2->implicitCastTo(sc, type);
+	}
+
+	typeCombine(sc);
+	e1->checkIntegral();
+	e2->checkIntegral();
+    }
+    return this;
+}
+
+int BinExp::checkSideEffect(int flag)
+{
+    if (op == TOKplusplus ||
+	   op == TOKminusminus ||
+	   op == TOKassign ||
+	   op == TOKaddass ||
+	   op == TOKminass ||
+	   op == TOKcatass ||
+	   op == TOKmulass ||
+	   op == TOKdivass ||
+	   op == TOKmodass ||
+	   op == TOKshlass ||
+	   op == TOKshrass ||
+	   op == TOKushrass ||
+	   op == TOKandass ||
+	   op == TOKorass ||
+	   op == TOKxorass ||
+	   op == TOKin ||
+	   op == TOKremove)
+	return 1;
+    return Expression::checkSideEffect(flag);
+}
+
+void BinExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    expToCBuffer(buf, hgs, e1, precedence[op]);
+    buf->writeByte(' ');
+    buf->writestring(Token::toChars(op));
+    buf->writeByte(' ');
+    expToCBuffer(buf, hgs, e2, (enum PREC)(precedence[op] + 1));
+}
+
+int BinExp::isunsigned()
+{
+    return e1->type->isunsigned() || e2->type->isunsigned();
+}
+
+void BinExp::incompatibleTypes()
+{
+    error("incompatible types for ((%s) %s (%s)): '%s' and '%s'",
+         e1->toChars(), Token::toChars(op), e2->toChars(),
+         e1->type->toChars(), e2->type->toChars());
+}
+
+/************************************************************/
+
+CompileExp::CompileExp(Loc loc, Expression *e)
+	: UnaExp(loc, TOKmixin, sizeof(CompileExp), e)
+{
+}
+
+Expression *CompileExp::semantic(Scope *sc)
+{
+#if LOGSEMANTIC
+    printf("CompileExp::semantic('%s')\n", toChars());
+#endif
+    UnaExp::semantic(sc);
+    e1 = resolveProperties(sc, e1);
+    e1 = e1->optimize(WANTvalue | WANTinterpret);
+    if (e1->op != TOKstring)
+    {	error("argument to mixin must be a string, not (%s)", e1->toChars());
+	type = Type::terror;
+	return this;
+    }
+    StringExp *se = (StringExp *)e1;
+    se = se->toUTF8(sc);
+    Parser p(sc->module, (unsigned char *)se->string, se->len, 0);
+    p.loc = loc;
+    p.nextToken();
+    Expression *e = p.parseExpression();
+    if (p.token.value != TOKeof)
+	error("incomplete mixin expression (%s)", se->toChars());
+    return e->semantic(sc);
+}
+
+void CompileExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("mixin(");
+    expToCBuffer(buf, hgs, e1, PREC_assign);
+    buf->writeByte(')');
+}
+
+/************************************************************/
+
+FileExp::FileExp(Loc loc, Expression *e)
+	: UnaExp(loc, TOKmixin, sizeof(FileExp), e)
+{
+}
+
+Expression *FileExp::semantic(Scope *sc)
+{   char *name;
+    StringExp *se;
+
+#if LOGSEMANTIC
+    printf("FileExp::semantic('%s')\n", toChars());
+#endif
+    UnaExp::semantic(sc);
+    e1 = resolveProperties(sc, e1);
+    e1 = e1->optimize(WANTvalue);
+    if (e1->op != TOKstring)
+    {	error("file name argument must be a string, not (%s)", e1->toChars());
+	goto Lerror;
+    }
+    se = (StringExp *)e1;
+    se = se->toUTF8(sc);
+    name = (char *)se->string;
+
+    if (!global.params.fileImppath)
+    {	error("need -Jpath switch to import text file %s", name);
+	goto Lerror;
+    }
+
+    if (name != FileName::name(name))
+    {	error("use -Jpath switch to provide path for filename %s", name);
+	goto Lerror;
+    }
+
+    name = FileName::searchPath(global.filePath, name, 0);
+    if (!name)
+    {	error("file %s cannot be found, check -Jpath", se->toChars());
+	goto Lerror;
+    }
+
+    if (global.params.verbose)
+	printf("file      %s\t(%s)\n", se->string, name);
+
+    {	File f(name);
+	if (f.read())
+	{   error("cannot read file %s", f.toChars());
+	    goto Lerror;
+	}
+	else
+	{
+	    f.ref = 1;
+	    se = new StringExp(loc, f.buffer, f.len);
+	}
+    }
+  Lret:
+    return se->semantic(sc);
+
+  Lerror:
+    se = new StringExp(loc, "");
+    goto Lret;
+}
+
+void FileExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("import(");
+    expToCBuffer(buf, hgs, e1, PREC_assign);
+    buf->writeByte(')');
+}
+
+/************************************************************/
+
+AssertExp::AssertExp(Loc loc, Expression *e, Expression *msg)
+	: UnaExp(loc, TOKassert, sizeof(AssertExp), e)
+{
+    this->msg = msg;
+}
+
+Expression *AssertExp::syntaxCopy()
+{
+    AssertExp *ae = new AssertExp(loc, e1->syntaxCopy(),
+				       msg ? msg->syntaxCopy() : NULL);
+    return ae;
+}
+
+Expression *AssertExp::semantic(Scope *sc)
+{
+#if LOGSEMANTIC
+    printf("AssertExp::semantic('%s')\n", toChars());
+#endif
+    UnaExp::semantic(sc);
+    e1 = resolveProperties(sc, e1);
+    // BUG: see if we can do compile time elimination of the Assert
+    e1 = e1->optimize(WANTvalue);
+    e1 = e1->checkToBoolean();
+    if (msg)
+    {
+	msg = msg->semantic(sc);
+	msg = resolveProperties(sc, msg);
+	msg = msg->implicitCastTo(sc, Type::tchar->arrayOf());
+	msg = msg->optimize(WANTvalue);
+    }
+    if (e1->isBool(FALSE))
+    {
+	FuncDeclaration *fd = sc->parent->isFuncDeclaration();
+	fd->hasReturnExp |= 4;
+
+	if (!global.params.useAssert)
+	{   Expression *e = new HaltExp(loc);
+	    e = e->semantic(sc);
+	    return e;
+	}
+    }
+    type = Type::tvoid;
+    return this;
+}
+
+int AssertExp::checkSideEffect(int flag)
+{
+    return 1;
+}
+
+void AssertExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("assert(");
+    expToCBuffer(buf, hgs, e1, PREC_assign);
+    if (msg)
+    {
+	buf->writeByte(',');
+	expToCBuffer(buf, hgs, msg, PREC_assign);
+    }
+    buf->writeByte(')');
+}
+
+/************************************************************/
+
+DotIdExp::DotIdExp(Loc loc, Expression *e, Identifier *ident)
+	: UnaExp(loc, TOKdot, sizeof(DotIdExp), e)
+{
+    this->ident = ident;
+}
+
+Expression *DotIdExp::semantic(Scope *sc)
+{   Expression *e;
+    Expression *eleft;
+    Expression *eright;
+
+#if LOGSEMANTIC
+    printf("DotIdExp::semantic(this = %p, '%s')\n", this, toChars());
+    //printf("e1->op = %d, '%s'\n", e1->op, Token::toChars(e1->op));
+#endif
+
+//{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; }
+
+#if 0
+    /* Don't do semantic analysis if we'll be converting
+     * it to a string.
+     */
+    if (ident == Id::stringof)
+    {	char *s = e1->toChars();
+	e = new StringExp(loc, s, strlen(s), 'c');
+	e = e->semantic(sc);
+	return e;
+    }
+#endif
+
+    /* Special case: rewrite this.id and super.id
+     * to be classtype.id and baseclasstype.id
+     * if we have no this pointer.
+     */
+    if ((e1->op == TOKthis || e1->op == TOKsuper) && !hasThis(sc))
+    {	ClassDeclaration *cd;
+	StructDeclaration *sd;
+	AggregateDeclaration *ad;
+
+	ad = sc->getStructClassScope();
+	if (ad)
+	{
+	    cd = ad->isClassDeclaration();
+	    if (cd)
+	    {
+		if (e1->op == TOKthis)
+		{
+		    e = new TypeDotIdExp(loc, cd->type, ident);
+		    return e->semantic(sc);
+		}
+		else if (cd->baseClass && e1->op == TOKsuper)
+		{
+		    e = new TypeDotIdExp(loc, cd->baseClass->type, ident);
+		    return e->semantic(sc);
+		}
+	    }
+	    else
+	    {
+		sd = ad->isStructDeclaration();
+		if (sd)
+		{
+		    if (e1->op == TOKthis)
+		    {
+			e = new TypeDotIdExp(loc, sd->type, ident);
+			return e->semantic(sc);
+		    }
+		}
+	    }
+	}
+    }
+
+    UnaExp::semantic(sc);
+
+    if (e1->op == TOKdotexp)
+    {
+	DotExp *de = (DotExp *)e1;
+	eleft = de->e1;
+	eright = de->e2;
+    }
+    else
+    {
+	e1 = resolveProperties(sc, e1);
+	eleft = NULL;
+	eright = e1;
+    }
+
+    if (e1->op == TOKtuple && ident == Id::length)
+    {
+	TupleExp *te = (TupleExp *)e1;
+	e = new IntegerExp(loc, te->exps->dim, Type::tsize_t);
+	return e;
+    }
+
+    if (eright->op == TOKimport)	// also used for template alias's
+    {
+	Dsymbol *s;
+	ScopeExp *ie = (ScopeExp *)eright;
+
+	s = ie->sds->search(loc, ident, 0);
+	if (s)
+	{
+	    s = s->toAlias();
+	    checkDeprecated(sc, s);
+
+	    EnumMember *em = s->isEnumMember();
+	    if (em)
+	    {
+		e = em->value;
+		e = e->semantic(sc);
+		return e;
+	    }
+
+	    VarDeclaration *v = s->isVarDeclaration();
+	    if (v)
+	    {
+		//printf("DotIdExp:: Identifier '%s' is a variable, type '%s'\n", toChars(), v->type->toChars());
+		if (v->inuse)
+		{
+		    error("circular reference to '%s'", v->toChars());
+		    type = Type::tint32;
+		    return this;
+		}
+		type = v->type;
+		if (v->isConst())
+		{
+		    if (v->init)
+		    {
+			ExpInitializer *ei = v->init->isExpInitializer();
+			if (ei)
+			{
+    //printf("\tei: %p (%s)\n", ei->exp, ei->exp->toChars());
+    //ei->exp = ei->exp->semantic(sc);
+			    if (ei->exp->type == type)
+			    {
+				e = ei->exp->copy();	// make copy so we can change loc
+				e->loc = loc;
+				return e;
+			    }
+			}
+		    }
+		    else if (type->isscalar())
+		    {
+			e = type->defaultInit();
+			e->loc = loc;
+			return e;
+		    }
+		}
+		if (v->needThis())
+		{
+		    if (!eleft)
+			eleft = new ThisExp(loc);
+		    e = new DotVarExp(loc, eleft, v);
+		    e = e->semantic(sc);
+		}
+		else
+		{
+		    e = new VarExp(loc, v);
+		    if (eleft)
+		    {	e = new CommaExp(loc, eleft, e);
+			e->type = v->type;
+		    }
+		}
+		return e->deref();
+	    }
+
+	    FuncDeclaration *f = s->isFuncDeclaration();
+	    if (f)
+	    {
+		//printf("it's a function\n");
+		if (f->needThis())
+		{
+		    if (!eleft)
+			eleft = new ThisExp(loc);
+		    e = new DotVarExp(loc, eleft, f);
+		    e = e->semantic(sc);
+		}
+		else
+		{
+		    e = new VarExp(loc, f);
+		    if (eleft)
+		    {	e = new CommaExp(loc, eleft, e);
+			e->type = f->type;
+		    }
+		}
+		return e;
+	    }
+
+	    Type *t = s->getType();
+	    if (t)
+	    {
+		return new TypeExp(loc, t);
+	    }
+
+	    ScopeDsymbol *sds = s->isScopeDsymbol();
+	    if (sds)
+	    {
+		//printf("it's a ScopeDsymbol\n");
+		e = new ScopeExp(loc, sds);
+		e = e->semantic(sc);
+		if (eleft)
+		    e = new DotExp(loc, eleft, e);
+		return e;
+	    }
+
+	    Import *imp = s->isImport();
+	    if (imp)
+	    {
+		ScopeExp *ie;
+
+		ie = new ScopeExp(loc, imp->pkg);
+		return ie->semantic(sc);
+	    }
+
+	    // BUG: handle other cases like in IdentifierExp::semantic()
+#ifdef DEBUG
+	    printf("s = '%s', kind = '%s'\n", s->toChars(), s->kind());
+#endif
+	    assert(0);
+	}
+	else if (ident == Id::stringof)
+	{   char *s = ie->toChars();
+	    e = new StringExp(loc, s, strlen(s), 'c');
+	    e = e->semantic(sc);
+	    return e;
+	}
+	error("undefined identifier %s", toChars());
+	type = Type::tvoid;
+	return this;
+    }
+    else if (e1->type->ty == Tpointer &&
+	     ident != Id::init && ident != Id::__sizeof &&
+	     ident != Id::alignof && ident != Id::offsetof &&
+	     ident != Id::mangleof && ident != Id::stringof)
+    {
+	e = new PtrExp(loc, e1);
+	e->type = e1->type->next;
+	return e->type->dotExp(sc, e, ident);
+    }
+    else
+    {
+	e = e1->type->dotExp(sc, e1, ident);
+	e = e->semantic(sc);
+	return e;
+    }
+}
+
+void DotIdExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    //printf("DotIdExp::toCBuffer()\n");
+    expToCBuffer(buf, hgs, e1, PREC_primary);
+    buf->writeByte('.');
+    buf->writestring(ident->toChars());
+}
+
+/********************** DotTemplateExp ***********************************/
+
+// Mainly just a placeholder
+
+DotTemplateExp::DotTemplateExp(Loc loc, Expression *e, TemplateDeclaration *td)
+	: UnaExp(loc, TOKdottd, sizeof(DotTemplateExp), e)
+
+{
+    this->td = td;
+}
+
+void DotTemplateExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    expToCBuffer(buf, hgs, e1, PREC_primary);
+    buf->writeByte('.');
+    buf->writestring(td->toChars());
+}
+
+
+/************************************************************/
+
+DotVarExp::DotVarExp(Loc loc, Expression *e, Declaration *v)
+	: UnaExp(loc, TOKdotvar, sizeof(DotVarExp), e)
+{
+    //printf("DotVarExp()\n");
+    this->var = v;
+}
+
+Expression *DotVarExp::semantic(Scope *sc)
+{
+#if LOGSEMANTIC
+    printf("DotVarExp::semantic('%s')\n", toChars());
+#endif
+    if (!type)
+    {
+	var = var->toAlias()->isDeclaration();
+
+	TupleDeclaration *tup = var->isTupleDeclaration();
+	if (tup)
+	{   /* Replace:
+	     *	e1.tuple(a, b, c)
+	     * with:
+	     *	tuple(e1.a, e1.b, e1.c)
+	     */
+	    Expressions *exps = new Expressions;
+
+	    exps->reserve(tup->objects->dim);
+	    for (size_t i = 0; i < tup->objects->dim; i++)
+	    {   Object *o = (Object *)tup->objects->data[i];
+		if (o->dyncast() != DYNCAST_EXPRESSION)
+		{
+		    error("%s is not an expression", o->toChars());
+		}
+		else
+		{
+		    Expression *e = (Expression *)o;
+		    if (e->op != TOKdsymbol)
+			error("%s is not a member", e->toChars());
+		    else
+		    {	DsymbolExp *ve = (DsymbolExp *)e;
+
+			e = new DotVarExp(loc, e1, ve->s->isDeclaration());
+			exps->push(e);
+		    }
+		}
+	    }
+	    Expression *e = new TupleExp(loc, exps);
+	    e = e->semantic(sc);
+	    return e;
+	}
+
+	e1 = e1->semantic(sc);
+	type = var->type;
+	if (!type && global.errors)
+	{   // var is goofed up, just return 0
+	    return new IntegerExp(0);
+	}
+	assert(type);
+
+	if (!var->isFuncDeclaration())	// for functions, do checks after overload resolution
+	{
+	    AggregateDeclaration *ad = var->toParent()->isAggregateDeclaration();
+	L1:
+	    Type *t = e1->type;
+
+	    if (ad &&
+		!(t->ty == Tpointer && t->next->ty == Tstruct &&
+		  ((TypeStruct *)t->next)->sym == ad)
+		&&
+		!(t->ty == Tstruct &&
+		  ((TypeStruct *)t)->sym == ad)
+	       )
+	    {
+		ClassDeclaration *cd = ad->isClassDeclaration();
+		ClassDeclaration *tcd = t->isClassHandle();
+
+		if (!cd || !tcd ||
+		    !(tcd == cd || cd->isBaseOf(tcd, NULL))
+		   )
+		{
+		    if (tcd && tcd->isNested())
+		    {	// Try again with outer scope
+
+			e1 = new DotVarExp(loc, e1, tcd->vthis);
+			e1 = e1->semantic(sc);
+
+			// Skip over nested functions, and get the enclosing
+			// class type.
+			Dsymbol *s = tcd->toParent();
+			while (s && s->isFuncDeclaration())
+			{   FuncDeclaration *f = s->isFuncDeclaration();
+			    if (f->vthis)
+			    {
+				e1 = new VarExp(loc, f->vthis);
+			    }
+			    s = s->toParent();
+			}
+			if (s && s->isClassDeclaration())
+			    e1->type = s->isClassDeclaration()->type;
+
+			goto L1;
+		    }
+#ifdef DEBUG
+		    printf("2: ");
+#endif
+		    error("this for %s needs to be type %s not type %s",
+			var->toChars(), ad->toChars(), t->toChars());
+		}
+	    }
+	    accessCheck(loc, sc, e1, var);
+	}
+    }
+    //printf("-DotVarExp::semantic('%s')\n", toChars());
+    return this;
+}
+
+Expression *DotVarExp::toLvalue(Scope *sc, Expression *e)
+{
+    //printf("DotVarExp::toLvalue(%s)\n", toChars());
+    return this;
+}
+
+Expression *DotVarExp::modifiableLvalue(Scope *sc, Expression *e)
+{
+    //printf("DotVarExp::modifiableLvalue(%s)\n", toChars());
+
+    if (var->isCtorinit())
+    {	// It's only modifiable if inside the right constructor
+	Dsymbol *s = sc->func;
+	while (1)
+	{
+	    FuncDeclaration *fd = NULL;
+	    if (s)
+		fd = s->isFuncDeclaration();
+	    if (fd &&
+		((fd->isCtorDeclaration() && var->storage_class & STCfield) ||
+		 (fd->isStaticCtorDeclaration() && !(var->storage_class & STCfield))) &&
+		fd->toParent() == var->toParent() &&
+		e1->op == TOKthis
+	       )
+	    {
+		VarDeclaration *v = var->isVarDeclaration();
+		assert(v);
+		v->ctorinit = 1;
+		//printf("setting ctorinit\n");
+	    }
+	    else
+	    {
+		if (s)
+		{   s = s->toParent2();
+		    continue;
+		}
+		else
+		{
+		    const char *p = var->isStatic() ? "static " : "";
+		    error("can only initialize %sconst member %s inside %sconstructor",
+			p, var->toChars(), p);
+		}
+	    }
+	    break;
+	}
+    }
+    return this;
+}
+
+void DotVarExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    expToCBuffer(buf, hgs, e1, PREC_primary);
+    buf->writeByte('.');
+    buf->writestring(var->toChars());
+}
+
+/************************************************************/
+
+/* Things like:
+ *	foo.bar!(args)
+ */
+
+DotTemplateInstanceExp::DotTemplateInstanceExp(Loc loc, Expression *e, TemplateInstance *ti)
+	: UnaExp(loc, TOKdotti, sizeof(DotTemplateInstanceExp), e)
+{
+    //printf("DotTemplateInstanceExp()\n");
+    this->ti = ti;
+}
+
+Expression *DotTemplateInstanceExp::syntaxCopy()
+{
+    DotTemplateInstanceExp *de = new DotTemplateInstanceExp(loc,
+	e1->syntaxCopy(),
+	(TemplateInstance *)ti->syntaxCopy(NULL));
+    return de;
+}
+
+Expression *DotTemplateInstanceExp::semantic(Scope *sc)
+{   Dsymbol *s;
+    Dsymbol *s2;
+    TemplateDeclaration *td;
+    Expression *e;
+    Identifier *id;
+    Type *t1;
+    Expression *eleft = NULL;
+    Expression *eright;
+
+#if LOGSEMANTIC
+    printf("DotTemplateInstanceExp::semantic('%s')\n", toChars());
+#endif
+    //e1->print();
+    //print();
+    e1 = e1->semantic(sc);
+    t1 = e1->type;
+    if (t1)
+	t1 = t1->toBasetype();
+    //t1->print();
+    if (e1->op == TOKdotexp)
+    {	DotExp *de = (DotExp *)e1;
+	eleft = de->e1;
+	eright = de->e2;
+    }
+    else
+    {	eleft = NULL;
+	eright = e1;
+    }
+    if (eright->op == TOKimport)
+    {
+	s = ((ScopeExp *)eright)->sds;
+    }
+    else if (e1->op == TOKtype)
+    {
+	s = t1->isClassHandle();
+	if (!s)
+	{   if (t1->ty == Tstruct)
+		s = ((TypeStruct *)t1)->sym;
+	    else
+		goto L1;
+	}
+    }
+    else if (t1 && (t1->ty == Tstruct || t1->ty == Tclass))
+    {
+	s = t1->toDsymbol(sc);
+	eleft = e1;
+    }
+    else if (t1 && t1->ty == Tpointer)
+    {
+	t1 = t1->next->toBasetype();
+	if (t1->ty != Tstruct)
+	    goto L1;
+	s = t1->toDsymbol(sc);
+	eleft = e1;
+    }
+    else
+    {
+      L1:
+	error("template %s is not a member of %s", ti->toChars(), e1->toChars());
+	goto Lerr;
+    }
+
+    assert(s);
+    id = ti->name;
+    s2 = s->search(loc, id, 0);
+    if (!s2)
+    {	error("template identifier %s is not a member of %s %s", id->toChars(), s->kind(), s->ident->toChars());
+	goto Lerr;
+    }
+    s = s2;
+    s->semantic(sc);
+    s = s->toAlias();
+    td = s->isTemplateDeclaration();
+    if (!td)
+    {
+	error("%s is not a template", id->toChars());
+	goto Lerr;
+    }
+    if (global.errors)
+	goto Lerr;
+
+    ti->tempdecl = td;
+
+    if (eleft)
+    {	Declaration *v;
+
+	ti->semantic(sc);
+	s = ti->inst->toAlias();
+	v = s->isDeclaration();
+	if (v)
+	{   e = new DotVarExp(loc, eleft, v);
+	    e = e->semantic(sc);
+	    return e;
+	}
+    }
+
+    e = new ScopeExp(loc, ti);
+    if (eleft)
+    {
+	e = new DotExp(loc, eleft, e);
+    }
+    e = e->semantic(sc);
+    return e;
+
+Lerr:
+    return new IntegerExp(0);
+}
+
+void DotTemplateInstanceExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    expToCBuffer(buf, hgs, e1, PREC_primary);
+    buf->writeByte('.');
+    ti->toCBuffer(buf, hgs);
+}
+
+/************************************************************/
+
+DelegateExp::DelegateExp(Loc loc, Expression *e, FuncDeclaration *f)
+	: UnaExp(loc, TOKdelegate, sizeof(DelegateExp), e)
+{
+    this->func = f;
+}
+
+Expression *DelegateExp::semantic(Scope *sc)
+{
+#if LOGSEMANTIC
+    printf("DelegateExp::semantic('%s')\n", toChars());
+#endif
+    if (!type)
+    {
+	e1 = e1->semantic(sc);
+	type = new TypeDelegate(func->type);
+	type = type->semantic(loc, sc);
+//-----------------
+	/* For func, we need to get the
+	 * right 'this' pointer if func is in an outer class, but our
+	 * existing 'this' pointer is in an inner class.
+	 * This code is analogous to that used for variables
+	 * in DotVarExp::semantic().
+	 */
+	AggregateDeclaration *ad = func->toParent()->isAggregateDeclaration();
+    L10:
+	Type *t = e1->type;
+	if (func->needThis() && ad &&
+	    !(t->ty == Tpointer && t->next->ty == Tstruct &&
+	      ((TypeStruct *)t->next)->sym == ad) &&
+	    !(t->ty == Tstruct && ((TypeStruct *)t)->sym == ad)
+	   )
+	{
+	    ClassDeclaration *cd = ad->isClassDeclaration();
+	    ClassDeclaration *tcd = t->isClassHandle();
+
+	    if (!cd || !tcd ||
+		!(tcd == cd || cd->isBaseOf(tcd, NULL))
+	       )
+	    {
+		if (tcd && tcd->isNested())
+		{   // Try again with outer scope
+
+		    e1 = new DotVarExp(loc, e1, tcd->vthis);
+		    e1 = e1->semantic(sc);
+		    goto L10;
+		}
+#ifdef DEBUG
+		printf("3: ");
+#endif
+		error("this for %s needs to be type %s not type %s",
+		    func->toChars(), ad->toChars(), t->toChars());
+	    }
+	}
+//-----------------
+    }
+    return this;
+}
+
+void DelegateExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writeByte('&');
+    if (!func->isNested())
+    {
+	expToCBuffer(buf, hgs, e1, PREC_primary);
+	buf->writeByte('.');
+    }
+    buf->writestring(func->toChars());
+}
+
+/************************************************************/
+
+DotTypeExp::DotTypeExp(Loc loc, Expression *e, Dsymbol *s)
+	: UnaExp(loc, TOKdottype, sizeof(DotTypeExp), e)
+{
+    this->sym = s;
+    this->type = s->getType();
+}
+
+Expression *DotTypeExp::semantic(Scope *sc)
+{
+#if LOGSEMANTIC
+    printf("DotTypeExp::semantic('%s')\n", toChars());
+#endif
+    UnaExp::semantic(sc);
+    return this;
+}
+
+void DotTypeExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    expToCBuffer(buf, hgs, e1, PREC_primary);
+    buf->writeByte('.');
+    buf->writestring(sym->toChars());
+}
+
+/************************************************************/
+
+CallExp::CallExp(Loc loc, Expression *e, Expressions *exps)
+	: UnaExp(loc, TOKcall, sizeof(CallExp), e)
+{
+    this->arguments = exps;
+}
+
+CallExp::CallExp(Loc loc, Expression *e)
+	: UnaExp(loc, TOKcall, sizeof(CallExp), e)
+{
+    this->arguments = NULL;
+}
+
+CallExp::CallExp(Loc loc, Expression *e, Expression *earg1)
+	: UnaExp(loc, TOKcall, sizeof(CallExp), e)
+{
+    Expressions *arguments = new Expressions();
+    arguments->setDim(1);
+    arguments->data[0] = (void *)earg1;
+
+    this->arguments = arguments;
+}
+
+CallExp::CallExp(Loc loc, Expression *e, Expression *earg1, Expression *earg2)
+	: UnaExp(loc, TOKcall, sizeof(CallExp), e)
+{
+    Expressions *arguments = new Expressions();
+    arguments->setDim(2);
+    arguments->data[0] = (void *)earg1;
+    arguments->data[1] = (void *)earg2;
+
+    this->arguments = arguments;
+}
+
+Expression *CallExp::syntaxCopy()
+{
+    return new CallExp(loc, e1->syntaxCopy(), arraySyntaxCopy(arguments));
+}
+
+
+Expression *CallExp::semantic(Scope *sc)
+{
+    TypeFunction *tf;
+    FuncDeclaration *f;
+    int i;
+    Type *t1;
+    int istemp;
+
+#if LOGSEMANTIC
+    printf("CallExp::semantic('%s')\n", toChars());
+#endif
+    if (type)
+	return this;		// semantic() already run
+#if 0
+    if (arguments && arguments->dim)
+    {
+	Expression *earg = (Expression *)arguments->data[0];
+	earg->print();
+	if (earg->type) earg->type->print();
+    }
+#endif
+
+    if (e1->op == TOKdelegate)
+    {	DelegateExp *de = (DelegateExp *)e1;
+
+	e1 = new DotVarExp(de->loc, de->e1, de->func);
+	return semantic(sc);
+    }
+
+    /* Transform:
+     *	array.id(args) into id(array,args)
+     *	aa.remove(arg) into delete aa[arg]
+     */
+    if (e1->op == TOKdot)
+    {
+	// BUG: we should handle array.a.b.c.e(args) too
+
+	DotIdExp *dotid = (DotIdExp *)(e1);
+	dotid->e1 = dotid->e1->semantic(sc);
+	assert(dotid->e1);
+	if (dotid->e1->type)
+	{
+	    TY e1ty = dotid->e1->type->toBasetype()->ty;
+	    if (e1ty == Taarray && dotid->ident == Id::remove)
+	    {
+		if (!arguments || arguments->dim != 1)
+		{   error("expected key as argument to aa.remove()");
+		    goto Lagain;
+		}
+		Expression *key = (Expression *)arguments->data[0];
+		key = key->semantic(sc);
+		key = resolveProperties(sc, key);
+		key->rvalue();
+
+		TypeAArray *taa = (TypeAArray *)dotid->e1->type->toBasetype();
+		key = key->implicitCastTo(sc, taa->index);
+		key = key->implicitCastTo(sc, taa->key);
+
+		return new RemoveExp(loc, dotid->e1, key);
+	    }
+	    else if (e1ty == Tarray || e1ty == Tsarray || e1ty == Taarray)
+	    {
+		if (!arguments)
+		    arguments = new Expressions();
+		arguments->shift(dotid->e1);
+		e1 = new IdentifierExp(dotid->loc, dotid->ident);
+	    }
+	}
+    }
+
+    istemp = 0;
+Lagain:
+    f = NULL;
+    if (e1->op == TOKthis || e1->op == TOKsuper)
+    {
+	// semantic() run later for these
+    }
+    else
+    {
+	UnaExp::semantic(sc);
+
+	/* Look for e1 being a lazy parameter
+	 */
+	if (e1->op == TOKvar)
+	{   VarExp *ve = (VarExp *)e1;
+
+	    if (ve->var->storage_class & STClazy)
+	    {
+		TypeFunction *tf = new TypeFunction(NULL, ve->var->type, 0, LINKd);
+		TypeDelegate *t = new TypeDelegate(tf);
+		ve->type = t->semantic(loc, sc);
+	    }
+	}
+
+	if (e1->op == TOKimport)
+	{   // Perhaps this should be moved to ScopeExp::semantic()
+	    ScopeExp *se = (ScopeExp *)e1;
+	    e1 = new DsymbolExp(loc, se->sds);
+	    e1 = e1->semantic(sc);
+	}
+#if 1	// patch for #540 by Oskar Linde
+	else if (e1->op == TOKdotexp)
+	{
+	    DotExp *de = (DotExp *) e1;
+
+	    if (de->e2->op == TOKimport)
+	    {   // This should *really* be moved to ScopeExp::semantic()
+		ScopeExp *se = (ScopeExp *)de->e2;
+		de->e2 = new DsymbolExp(loc, se->sds);
+		de->e2 = de->e2->semantic(sc);
+	    }
+
+	    if (de->e2->op == TOKtemplate)
+	    {   TemplateExp *te = (TemplateExp *) de->e2;
+		e1 = new DotTemplateExp(loc,de->e1,te->td);
+	    }
+	}
+#endif
+    }
+
+    if (e1->op == TOKcomma)
+    {
+	CommaExp *ce = (CommaExp *)e1;
+
+	e1 = ce->e2;
+	e1->type = ce->type;
+	ce->e2 = this;
+	ce->type = NULL;
+	return ce->semantic(sc);
+    }
+
+    t1 = NULL;
+    if (e1->type)
+	t1 = e1->type->toBasetype();
+
+    // Check for call operator overload
+    if (t1)
+    {	AggregateDeclaration *ad;
+
+	if (t1->ty == Tstruct)
+	{
+	    ad = ((TypeStruct *)t1)->sym;
+	    if (search_function(ad, Id::call))
+		goto L1;	// overload of opCall, therefore it's a call
+	    /* It's a struct literal
+	     */
+	    Expression *e = new StructLiteralExp(loc, (StructDeclaration *)ad, arguments);
+	    e = e->semantic(sc);
+	    return e;
+	}
+	else if (t1->ty == Tclass)
+	{
+	    ad = ((TypeClass *)t1)->sym;
+	    goto L1;
+	L1:
+	    // Rewrite as e1.call(arguments)
+	    Expression *e = new DotIdExp(loc, e1, Id::call);
+	    e = new CallExp(loc, e, arguments);
+	    e = e->semantic(sc);
+	    return e;
+	}
+    }
+
+    arrayExpressionSemantic(arguments, sc);
+    preFunctionArguments(loc, sc, arguments);
+
+    if (e1->op == TOKdotvar && t1->ty == Tfunction ||
+        e1->op == TOKdottd)
+    {
+	DotVarExp *dve;
+	DotTemplateExp *dte;
+	AggregateDeclaration *ad;
+	UnaExp *ue = (UnaExp *)(e1);
+
+    	if (e1->op == TOKdotvar)
+        {   // Do overload resolution
+	    dve = (DotVarExp *)(e1);
+
+	    f = dve->var->isFuncDeclaration();
+	    assert(f);
+	    f = f->overloadResolve(loc, arguments);
+
+	    ad = f->toParent()->isAggregateDeclaration();
+	}
+        else
+        {   dte = (DotTemplateExp *)(e1);
+	    TemplateDeclaration *td = dte->td;
+	    assert(td);
+	    if (!arguments)
+		// Should fix deduce() so it works on NULL argument
+		arguments = new Expressions();
+	    f = td->deduce(sc, loc, NULL, arguments);
+	    if (!f)
+	    {	type = Type::terror;
+		return this;
+	    }
+	    ad = td->toParent()->isAggregateDeclaration();
+	}
+	/* Now that we have the right function f, we need to get the
+	 * right 'this' pointer if f is in an outer class, but our
+	 * existing 'this' pointer is in an inner class.
+	 * This code is analogous to that used for variables
+	 * in DotVarExp::semantic().
+	 */
+    L10:
+	Type *t = ue->e1->type->toBasetype();
+	if (f->needThis() && ad &&
+	    !(t->ty == Tpointer && t->next->ty == Tstruct &&
+	      ((TypeStruct *)t->next)->sym == ad) &&
+	    !(t->ty == Tstruct && ((TypeStruct *)t)->sym == ad)
+	   )
+	{
+	    ClassDeclaration *cd = ad->isClassDeclaration();
+	    ClassDeclaration *tcd = t->isClassHandle();
+
+	    if (!cd || !tcd ||
+		!(tcd == cd || cd->isBaseOf(tcd, NULL))
+	       )
+	    {
+		if (tcd && tcd->isNested())
+		{   // Try again with outer scope
+
+		    ue->e1 = new DotVarExp(loc, ue->e1, tcd->vthis);
+		    ue->e1 = ue->e1->semantic(sc);
+		    goto L10;
+		}
+#ifdef DEBUG
+		printf("1: ");
+#endif
+		error("this for %s needs to be type %s not type %s",
+		    f->toChars(), ad->toChars(), t->toChars());
+	    }
+	}
+
+	checkDeprecated(sc, f);
+	accessCheck(loc, sc, ue->e1, f);
+	if (!f->needThis())
+	{
+	    VarExp *ve = new VarExp(loc, f);
+	    e1 = new CommaExp(loc, ue->e1, ve);
+	    e1->type = f->type;
+	}
+	else
+	{
+	    if (e1->op == TOKdotvar)
+		dve->var = f;
+	    else
+		e1 = new DotVarExp(loc, dte->e1, f);
+	    e1->type = f->type;
+
+	    // See if we need to adjust the 'this' pointer
+	    AggregateDeclaration *ad = f->isThis();
+	    ClassDeclaration *cd = ue->e1->type->isClassHandle();
+	    if (ad && cd && ad->isClassDeclaration() && ad != cd &&
+		ue->e1->op != TOKsuper)
+	    {
+		ue->e1 = ue->e1->castTo(sc, ad->type); //new CastExp(loc, ue->e1, ad->type);
+		ue->e1 = ue->e1->semantic(sc);
+	    }
+	}
+	t1 = e1->type;
+    }
+    else if (e1->op == TOKsuper)
+    {
+	// Base class constructor call
+	ClassDeclaration *cd = NULL;
+
+	if (sc->func)
+	    cd = sc->func->toParent()->isClassDeclaration();
+	if (!cd || !cd->baseClass || !sc->func->isCtorDeclaration())
+	{
+	    error("super class constructor call must be in a constructor");
+	    type = Type::terror;
+	    return this;
+	}
+	else
+	{
+	    f = cd->baseClass->ctor;
+	    if (!f)
+	    {	error("no super class constructor for %s", cd->baseClass->toChars());
+		type = Type::terror;
+		return this;
+	    }
+	    else
+	    {
+#if 0
+		if (sc->callSuper & (CSXthis | CSXsuper))
+		    error("reference to this before super()");
+#endif
+		if (sc->noctor || sc->callSuper & CSXlabel)
+		    error("constructor calls not allowed in loops or after labels");
+		if (sc->callSuper & (CSXsuper_ctor | CSXthis_ctor))
+		    error("multiple constructor calls");
+		sc->callSuper |= CSXany_ctor | CSXsuper_ctor;
+
+		f = f->overloadResolve(loc, arguments);
+		checkDeprecated(sc, f);
+		e1 = new DotVarExp(e1->loc, e1, f);
+		e1 = e1->semantic(sc);
+		t1 = e1->type;
+	    }
+	}
+    }
+    else if (e1->op == TOKthis)
+    {
+	// same class constructor call
+	ClassDeclaration *cd = NULL;
+
+	if (sc->func)
+	    cd = sc->func->toParent()->isClassDeclaration();
+	if (!cd || !sc->func->isCtorDeclaration())
+	{
+	    error("class constructor call must be in a constructor");
+	    type = Type::terror;
+	    return this;
+	}
+	else
+	{
+#if 0
+	    if (sc->callSuper & (CSXthis | CSXsuper))
+		error("reference to this before super()");
+#endif
+	    if (sc->noctor || sc->callSuper & CSXlabel)
+		error("constructor calls not allowed in loops or after labels");
+	    if (sc->callSuper & (CSXsuper_ctor | CSXthis_ctor))
+		error("multiple constructor calls");
+	    sc->callSuper |= CSXany_ctor | CSXthis_ctor;
+
+	    f = cd->ctor;
+	    f = f->overloadResolve(loc, arguments);
+	    checkDeprecated(sc, f);
+	    e1 = new DotVarExp(e1->loc, e1, f);
+	    e1 = e1->semantic(sc);
+	    t1 = e1->type;
+
+	    // BUG: this should really be done by checking the static
+	    // call graph
+	    if (f == sc->func)
+		error("cyclic constructor call");
+	}
+    }
+    else if (!t1)
+    {
+	error("function expected before (), not '%s'", e1->toChars());
+	type = Type::terror;
+	return this;
+    }
+    else if (t1->ty != Tfunction)
+    {
+	if (t1->ty == Tdelegate)
+	{
+	    assert(t1->next->ty == Tfunction);
+	    tf = (TypeFunction *)(t1->next);
+	    goto Lcheckargs;
+	}
+	else if (t1->ty == Tpointer && t1->next->ty == Tfunction)
+	{   Expression *e;
+
+	    e = new PtrExp(loc, e1);
+	    t1 = t1->next;
+	    e->type = t1;
+	    e1 = e;
+	}
+	else if (e1->op == TOKtemplate)
+	{
+	    TemplateExp *te = (TemplateExp *)e1;
+	    f = te->td->deduce(sc, loc, NULL, arguments);
+	    if (!f)
+	    {	type = Type::terror;
+		return this;
+	    }
+	    if (f->needThis() && hasThis(sc))
+	    {
+		// Supply an implicit 'this', as in
+		//	  this.ident
+
+		e1 = new DotTemplateExp(loc, (new ThisExp(loc))->semantic(sc), te->td);
+		goto Lagain;
+	    }
+
+	    e1 = new VarExp(loc, f);
+	    goto Lagain;
+	}
+	else
+	{   error("function expected before (), not %s of type %s", e1->toChars(), e1->type->toChars());
+	    type = Type::terror;
+	    return this;
+	}
+    }
+    else if (e1->op == TOKvar)
+    {
+	// Do overload resolution
+	VarExp *ve = (VarExp *)e1;
+
+	f = ve->var->isFuncDeclaration();
+	assert(f);
+
+	// Look to see if f is really a function template
+	if (0 && !istemp && f->parent)
+	{   TemplateInstance *ti = f->parent->isTemplateInstance();
+
+	    if (ti &&
+		(ti->name == f->ident ||
+		 ti->toAlias()->ident == f->ident)
+		&&
+		ti->tempdecl)
+	    {
+		/* This is so that one can refer to the enclosing
+		 * template, even if it has the same name as a member
+		 * of the template, if it has a !(arguments)
+		 */
+		TemplateDeclaration *tempdecl = ti->tempdecl;
+		if (tempdecl->overroot)         // if not start of overloaded list of TemplateDeclaration's
+		    tempdecl = tempdecl->overroot; // then get the start
+		e1 = new TemplateExp(loc, tempdecl);
+		istemp = 1;
+		goto Lagain;
+	    }
+	}
+
+	f = f->overloadResolve(loc, arguments);
+	checkDeprecated(sc, f);
+
+	if (f->needThis() && hasThis(sc))
+	{
+	    // Supply an implicit 'this', as in
+	    //	  this.ident
+
+	    e1 = new DotVarExp(loc, new ThisExp(loc), f);
+	    goto Lagain;
+	}
+
+	accessCheck(loc, sc, NULL, f);
+
+	ve->var = f;
+	ve->type = f->type;
+	t1 = f->type;
+    }
+    assert(t1->ty == Tfunction);
+    tf = (TypeFunction *)(t1);
+
+Lcheckargs:
+    assert(tf->ty == Tfunction);
+    type = tf->next;
+
+    if (!arguments)
+	arguments = new Expressions();
+    functionArguments(loc, sc, tf, arguments);
+
+    assert(type);
+
+    if (f && f->tintro)
+    {
+	Type *t = type;
+	int offset = 0;
+
+	if (f->tintro->next->isBaseOf(t, &offset) && offset)
+	{
+	    type = f->tintro->next;
+	    return castTo(sc, t);
+	}
+    }
+
+    return this;
+}
+
+int CallExp::checkSideEffect(int flag)
+{
+    return 1;
+}
+
+Expression *CallExp::toLvalue(Scope *sc, Expression *e)
+{
+    if (type->toBasetype()->ty == Tstruct)
+	return this;
+    else
+	return Expression::toLvalue(sc, e);
+}
+
+void CallExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{   int i;
+
+    expToCBuffer(buf, hgs, e1, precedence[op]);
+    buf->writeByte('(');
+    argsToCBuffer(buf, arguments, hgs);
+    buf->writeByte(')');
+}
+
+
+/************************************************************/
+
+AddrExp::AddrExp(Loc loc, Expression *e)
+	: UnaExp(loc, TOKaddress, sizeof(AddrExp), e)
+{
+}
+
+Expression *AddrExp::semantic(Scope *sc)
+{
+#if LOGSEMANTIC
+    printf("AddrExp::semantic('%s')\n", toChars());
+#endif
+    if (!type)
+    {
+	UnaExp::semantic(sc);
+	e1 = e1->toLvalue(sc, NULL);
+	if (!e1->type)
+	{
+	    error("cannot take address of %s", e1->toChars());
+	    type = Type::tint32;
+	    return this;
+	}
+	type = e1->type->pointerTo();
+
+	// See if this should really be a delegate
+	if (e1->op == TOKdotvar)
+	{
+	    DotVarExp *dve = (DotVarExp *)e1;
+	    FuncDeclaration *f = dve->var->isFuncDeclaration();
+
+	    if (f)
+	    {	Expression *e;
+
+		e = new DelegateExp(loc, dve->e1, f);
+		e = e->semantic(sc);
+		return e;
+	    }
+	}
+	else if (e1->op == TOKvar)
+	{
+	    VarExp *dve = (VarExp *)e1;
+	    FuncDeclaration *f = dve->var->isFuncDeclaration();
+
+	    if (f && f->isNested())
+	    {	Expression *e;
+
+		e = new DelegateExp(loc, e1, f);
+		e = e->semantic(sc);
+		return e;
+	    }
+	}
+	else if (e1->op == TOKarray)
+	{
+	    if (e1->type->toBasetype()->ty == Tbit)
+		error("cannot take address of bit in array");
+	}
+	return optimize(WANTvalue);
+    }
+    return this;
+}
+
+/************************************************************/
+
+PtrExp::PtrExp(Loc loc, Expression *e)
+	: UnaExp(loc, TOKstar, sizeof(PtrExp), e)
+{
+    if (e->type)
+	type = e->type->next;
+}
+
+PtrExp::PtrExp(Loc loc, Expression *e, Type *t)
+	: UnaExp(loc, TOKstar, sizeof(PtrExp), e)
+{
+    type = t;
+}
+
+Expression *PtrExp::semantic(Scope *sc)
+{   Type *tb;
+
+#if LOGSEMANTIC
+    printf("PtrExp::semantic('%s')\n", toChars());
+#endif
+    UnaExp::semantic(sc);
+    e1 = resolveProperties(sc, e1);
+    if (type)
+	return this;
+    if (!e1->type)
+	printf("PtrExp::semantic('%s')\n", toChars());
+    tb = e1->type->toBasetype();
+    switch (tb->ty)
+    {
+	case Tpointer:
+	    type = tb->next;
+	    if (type->isbit())
+	    {	Expression *e;
+
+		// Rewrite *p as p[0]
+		e = new IndexExp(loc, e1, new IntegerExp(0));
+		return e->semantic(sc);
+	    }
+	    break;
+
+	case Tsarray:
+	case Tarray:
+	    type = tb->next;
+	    e1 = e1->castTo(sc, type->pointerTo());
+	    break;
+
+	default:
+	    error("can only * a pointer, not a '%s'", e1->type->toChars());
+	    type = Type::tint32;
+	    break;
+    }
+    rvalue();
+    return this;
+}
+
+Expression *PtrExp::toLvalue(Scope *sc, Expression *e)
+{
+#if 0
+    tym = tybasic(e1->ET->Tty);
+    if (!(tyscalar(tym) ||
+	  tym == TYstruct ||
+	  tym == TYarray && e->Eoper == TOKaddr))
+	    synerr(EM_lvalue);	// lvalue expected
+#endif
+    return this;
+}
+
+void PtrExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writeByte('*');
+    expToCBuffer(buf, hgs, e1, precedence[op]);
+}
+
+/************************************************************/
+
+NegExp::NegExp(Loc loc, Expression *e)
+	: UnaExp(loc, TOKneg, sizeof(NegExp), e)
+{
+}
+
+Expression *NegExp::semantic(Scope *sc)
+{   Expression *e;
+
+#if LOGSEMANTIC
+    printf("NegExp::semantic('%s')\n", toChars());
+#endif
+    if (!type)
+    {
+	UnaExp::semantic(sc);
+	e1 = resolveProperties(sc, e1);
+	e = op_overload(sc);
+	if (e)
+	    return e;
+
+	e1->checkNoBool();
+	e1->checkArithmetic();
+	type = e1->type;
+    }
+    return this;
+}
+
+/************************************************************/
+
+UAddExp::UAddExp(Loc loc, Expression *e)
+	: UnaExp(loc, TOKuadd, sizeof(UAddExp), e)
+{
+}
+
+Expression *UAddExp::semantic(Scope *sc)
+{   Expression *e;
+
+#if LOGSEMANTIC
+    printf("UAddExp::semantic('%s')\n", toChars());
+#endif
+    assert(!type);
+    UnaExp::semantic(sc);
+    e1 = resolveProperties(sc, e1);
+    e = op_overload(sc);
+    if (e)
+	return e;
+    e1->checkNoBool();
+    e1->checkArithmetic();
+    return e1;
+}
+
+/************************************************************/
+
+ComExp::ComExp(Loc loc, Expression *e)
+	: UnaExp(loc, TOKtilde, sizeof(ComExp), e)
+{
+}
+
+Expression *ComExp::semantic(Scope *sc)
+{   Expression *e;
+
+    if (!type)
+    {
+	UnaExp::semantic(sc);
+	e1 = resolveProperties(sc, e1);
+	e = op_overload(sc);
+	if (e)
+	    return e;
+
+	e1->checkNoBool();
+	e1 = e1->checkIntegral();
+	type = e1->type;
+    }
+    return this;
+}
+
+/************************************************************/
+
+NotExp::NotExp(Loc loc, Expression *e)
+	: UnaExp(loc, TOKnot, sizeof(NotExp), e)
+{
+}
+
+Expression *NotExp::semantic(Scope *sc)
+{
+    UnaExp::semantic(sc);
+    e1 = resolveProperties(sc, e1);
+    e1 = e1->checkToBoolean();
+    type = Type::tboolean;
+    return this;
+}
+
+int NotExp::isBit()
+{
+    return TRUE;
+}
+
+
+
+/************************************************************/
+
+BoolExp::BoolExp(Loc loc, Expression *e, Type *t)
+	: UnaExp(loc, TOKtobool, sizeof(BoolExp), e)
+{
+    type = t;
+}
+
+Expression *BoolExp::semantic(Scope *sc)
+{
+    UnaExp::semantic(sc);
+    e1 = resolveProperties(sc, e1);
+    e1 = e1->checkToBoolean();
+    type = Type::tboolean;
+    return this;
+}
+
+int BoolExp::isBit()
+{
+    return TRUE;
+}
+
+/************************************************************/
+
+DeleteExp::DeleteExp(Loc loc, Expression *e)
+	: UnaExp(loc, TOKdelete, sizeof(DeleteExp), e)
+{
+}
+
+Expression *DeleteExp::semantic(Scope *sc)
+{
+    Type *tb;
+
+    UnaExp::semantic(sc);
+    e1 = resolveProperties(sc, e1);
+    e1 = e1->toLvalue(sc, NULL);
+    type = Type::tvoid;
+
+    tb = e1->type->toBasetype();
+    switch (tb->ty)
+    {	case Tclass:
+	{   TypeClass *tc = (TypeClass *)tb;
+	    ClassDeclaration *cd = tc->sym;
+
+	    if (cd->isInterfaceDeclaration() && cd->isCOMclass())
+		error("cannot delete instance of COM interface %s", cd->toChars());
+	    break;
+	}
+	case Tpointer:
+	    tb = tb->next->toBasetype();
+	    if (tb->ty == Tstruct)
+	    {
+		TypeStruct *ts = (TypeStruct *)tb;
+		StructDeclaration *sd = ts->sym;
+		FuncDeclaration *f = sd->aggDelete;
+
+		if (f)
+		{
+		    Expression *e;
+		    Expression *ec;
+		    Type *tpv = Type::tvoid->pointerTo();
+
+		    e = e1;
+		    e->type = tpv;
+		    ec = new VarExp(loc, f);
+		    e = new CallExp(loc, ec, e);
+		    return e->semantic(sc);
+		}
+	    }
+	    break;
+
+	case Tarray:
+	    break;
+
+	default:
+	    if (e1->op == TOKindex)
+	    {
+		IndexExp *ae = (IndexExp *)(e1);
+		Type *tb1 = ae->e1->type->toBasetype();
+		if (tb1->ty == Taarray)
+		    break;
+	    }
+	    error("cannot delete type %s", e1->type->toChars());
+	    break;
+    }
+
+    if (e1->op == TOKindex)
+    {
+	IndexExp *ae = (IndexExp *)(e1);
+	Type *tb1 = ae->e1->type->toBasetype();
+	if (tb1->ty == Taarray)
+	{   if (!global.params.useDeprecated)
+		error("delete aa[key] deprecated, use aa.remove(key)");
+	}
+    }
+
+    return this;
+}
+
+int DeleteExp::checkSideEffect(int flag)
+{
+    return 1;
+}
+
+Expression *DeleteExp::checkToBoolean()
+{
+    error("delete does not give a boolean result");
+    return this;
+}
+
+void DeleteExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("delete ");
+    expToCBuffer(buf, hgs, e1, precedence[op]);
+}
+
+/************************************************************/
+
+CastExp::CastExp(Loc loc, Expression *e, Type *t)
+	: UnaExp(loc, TOKcast, sizeof(CastExp), e)
+{
+    to = t;
+}
+
+Expression *CastExp::syntaxCopy()
+{
+    return new CastExp(loc, e1->syntaxCopy(), to->syntaxCopy());
+}
+
+
+Expression *CastExp::semantic(Scope *sc)
+{   Expression *e;
+    BinExp *b;
+    UnaExp *u;
+
+#if LOGSEMANTIC
+    printf("CastExp::semantic('%s')\n", toChars());
+#endif
+
+//static int x; assert(++x < 10);
+
+    if (type)
+	return this;
+    UnaExp::semantic(sc);
+    if (e1->type)		// if not a tuple
+    {
+	e1 = resolveProperties(sc, e1);
+	to = to->semantic(loc, sc);
+
+	e = op_overload(sc);
+	if (e)
+	{
+	    return e->implicitCastTo(sc, to);
+	}
+
+	Type *tob = to->toBasetype();
+	if (tob->ty == Tstruct && !tob->equals(e1->type->toBasetype()))
+	{
+	    /* Look to replace:
+	     *	cast(S)t
+	     * with:
+	     *	S(t)
+	     */
+
+	    // Rewrite as to.call(e1)
+	    e = new TypeExp(loc, to);
+	    e = new DotIdExp(loc, e, Id::call);
+	    e = new CallExp(loc, e, e1);
+	    e = e->semantic(sc);
+	    return e;
+	}
+    }
+    e = e1->castTo(sc, to);
+    return e;
+}
+
+int CastExp::checkSideEffect(int flag)
+{
+    /* if not:
+     *  cast(void)
+     *  cast(classtype)func()
+     */
+    if (!to->equals(Type::tvoid) &&
+	!(to->ty == Tclass && e1->op == TOKcall && e1->type->ty == Tclass))
+	return Expression::checkSideEffect(flag);
+    return 1;
+}
+
+void CastExp::checkEscape()
+{   Type *tb = type->toBasetype();
+    if (tb->ty == Tarray && e1->op == TOKvar &&
+	e1->type->toBasetype()->ty == Tsarray)
+    {	VarExp *ve = (VarExp *)e1;
+	VarDeclaration *v = ve->var->isVarDeclaration();
+	if (v)
+	{
+	    if (!v->isDataseg() && !v->isParameter())
+		error("escaping reference to local %s", v->toChars());
+	}
+    }
+}
+
+void CastExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("cast(");
+    to->toCBuffer(buf, NULL, hgs);
+    buf->writeByte(')');
+    expToCBuffer(buf, hgs, e1, precedence[op]);
+}
+
+
+/************************************************************/
+
+SliceExp::SliceExp(Loc loc, Expression *e1, Expression *lwr, Expression *upr)
+	: UnaExp(loc, TOKslice, sizeof(SliceExp), e1)
+{
+    this->upr = upr;
+    this->lwr = lwr;
+    lengthVar = NULL;
+}
+
+Expression *SliceExp::syntaxCopy()
+{
+    Expression *lwr = NULL;
+    if (this->lwr)
+	lwr = this->lwr->syntaxCopy();
+
+    Expression *upr = NULL;
+    if (this->upr)
+	upr = this->upr->syntaxCopy();
+
+    return new SliceExp(loc, e1->syntaxCopy(), lwr, upr);
+}
+
+Expression *SliceExp::semantic(Scope *sc)
+{   Expression *e;
+    AggregateDeclaration *ad;
+    //FuncDeclaration *fd;
+    ScopeDsymbol *sym;
+
+#if LOGSEMANTIC
+    printf("SliceExp::semantic('%s')\n", toChars());
+#endif
+    if (type)
+	return this;
+
+    UnaExp::semantic(sc);
+    e1 = resolveProperties(sc, e1);
+
+    e = this;
+
+    Type *t = e1->type->toBasetype();
+    if (t->ty == Tpointer)
+    {
+	if (!lwr || !upr)
+	    error("need upper and lower bound to slice pointer");
+    }
+    else if (t->ty == Tarray)
+    {
+    }
+    else if (t->ty == Tsarray)
+    {
+    }
+    else if (t->ty == Tclass)
+    {
+        ad = ((TypeClass *)t)->sym;
+        goto L1;
+    }
+    else if (t->ty == Tstruct)
+    {
+        ad = ((TypeStruct *)t)->sym;
+
+    L1:
+	if (search_function(ad, Id::slice))
+        {
+            // Rewrite as e1.slice(lwr, upr)
+	    e = new DotIdExp(loc, e1, Id::slice);
+
+	    if (lwr)
+	    {
+		assert(upr);
+		e = new CallExp(loc, e, lwr, upr);
+	    }
+	    else
+	    {	assert(!upr);
+		e = new CallExp(loc, e);
+	    }
+	    e = e->semantic(sc);
+	    return e;
+        }
+	goto Lerror;
+    }
+    else if (t->ty == Ttuple)
+    {
+	if (!lwr && !upr)
+	    return e1;
+	if (!lwr || !upr)
+	{   error("need upper and lower bound to slice tuple");
+	    goto Lerror;
+	}
+    }
+    else
+	goto Lerror;
+
+    if (t->ty == Tsarray || t->ty == Tarray || t->ty == Ttuple)
+    {
+	sym = new ArrayScopeSymbol(this);
+	sym->loc = loc;
+	sym->parent = sc->scopesym;
+	sc = sc->push(sym);
+    }
+
+    if (lwr)
+    {	lwr = lwr->semantic(sc);
+	lwr = resolveProperties(sc, lwr);
+	lwr = lwr->implicitCastTo(sc, Type::tsize_t);
+    }
+    if (upr)
+    {	upr = upr->semantic(sc);
+	upr = resolveProperties(sc, upr);
+	upr = upr->implicitCastTo(sc, Type::tsize_t);
+    }
+
+    if (t->ty == Tsarray || t->ty == Tarray || t->ty == Ttuple)
+	sc->pop();
+
+    if (t->ty == Ttuple)
+    {
+	lwr = lwr->optimize(WANTvalue);
+	upr = upr->optimize(WANTvalue);
+	uinteger_t i1 = lwr->toUInteger();
+	uinteger_t i2 = upr->toUInteger();
+
+	size_t length;
+	TupleExp *te;
+	TypeTuple *tup;
+
+	if (e1->op == TOKtuple)		// slicing an expression tuple
+	{   te = (TupleExp *)e1;
+	    length = te->exps->dim;
+	}
+	else if (e1->op == TOKtype)	// slicing a type tuple
+	{   tup = (TypeTuple *)t;
+	    length = Argument::dim(tup->arguments);
+	}
+	else
+	    assert(0);
+
+	if (i1 <= i2 && i2 <= length)
+	{   size_t j1 = (size_t) i1;
+	    size_t j2 = (size_t) i2;
+
+	    if (e1->op == TOKtuple)
+	    {	Expressions *exps = new Expressions;
+		exps->setDim(j2 - j1);
+		for (size_t i = 0; i < j2 - j1; i++)
+		{   Expression *e = (Expression *)te->exps->data[j1 + i];
+		    exps->data[i] = (void *)e;
+		}
+		e = new TupleExp(loc, exps);
+	    }
+	    else
+	    {	Arguments *args = new Arguments;
+		args->reserve(j2 - j1);
+		for (size_t i = j1; i < j2; i++)
+		{   Argument *arg = Argument::getNth(tup->arguments, i);
+		    args->push(arg);
+		}
+		e = new TypeExp(e1->loc, new TypeTuple(args));
+	    }
+	    e = e->semantic(sc);
+	}
+	else
+	{
+	    error("string slice [%ju .. %ju] is out of bounds", i1, i2);
+	    e = e1;
+	}
+	return e;
+    }
+
+    type = t->next->arrayOf();
+    return e;
+
+Lerror:
+    char *s;
+    if (t->ty == Tvoid)
+	s = e1->toChars();
+    else
+	s = t->toChars();
+    error("%s cannot be sliced with []", s);
+    type = Type::terror;
+    return e;
+}
+
+void SliceExp::checkEscape()
+{
+    e1->checkEscape();
+}
+
+Expression *SliceExp::toLvalue(Scope *sc, Expression *e)
+{
+    return this;
+}
+
+Expression *SliceExp::modifiableLvalue(Scope *sc, Expression *e)
+{
+    error("slice expression %s is not a modifiable lvalue", toChars());
+    return this;
+}
+
+void SliceExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    expToCBuffer(buf, hgs, e1, precedence[op]);
+    buf->writeByte('[');
+    if (upr || lwr)
+    {
+	if (lwr)
+	    expToCBuffer(buf, hgs, lwr, PREC_assign);
+	else
+	    buf->writeByte('0');
+	buf->writestring("..");
+	if (upr)
+	    expToCBuffer(buf, hgs, upr, PREC_assign);
+	else
+	    buf->writestring("length");		// BUG: should be array.length
+    }
+    buf->writeByte(']');
+}
+
+/********************** ArrayLength **************************************/
+
+ArrayLengthExp::ArrayLengthExp(Loc loc, Expression *e1)
+	: UnaExp(loc, TOKarraylength, sizeof(ArrayLengthExp), e1)
+{
+}
+
+Expression *ArrayLengthExp::semantic(Scope *sc)
+{   Expression *e;
+
+#if LOGSEMANTIC
+    printf("ArrayLengthExp::semantic('%s')\n", toChars());
+#endif
+    if (!type)
+    {
+	UnaExp::semantic(sc);
+	e1 = resolveProperties(sc, e1);
+
+	type = Type::tsize_t;
+    }
+    return this;
+}
+
+void ArrayLengthExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    expToCBuffer(buf, hgs, e1, PREC_primary);
+    buf->writestring(".length");
+}
+
+/*********************** ArrayExp *************************************/
+
+// e1 [ i1, i2, i3, ... ]
+
+ArrayExp::ArrayExp(Loc loc, Expression *e1, Expressions *args)
+	: UnaExp(loc, TOKarray, sizeof(ArrayExp), e1)
+{
+    arguments = args;
+}
+
+Expression *ArrayExp::syntaxCopy()
+{
+    return new ArrayExp(loc, e1->syntaxCopy(), arraySyntaxCopy(arguments));
+}
+
+Expression *ArrayExp::semantic(Scope *sc)
+{   Expression *e;
+    Type *t1;
+
+#if LOGSEMANTIC
+    printf("ArrayExp::semantic('%s')\n", toChars());
+#endif
+    UnaExp::semantic(sc);
+    e1 = resolveProperties(sc, e1);
+
+    t1 = e1->type->toBasetype();
+    if (t1->ty != Tclass && t1->ty != Tstruct)
+    {	// Convert to IndexExp
+	if (arguments->dim != 1)
+	    error("only one index allowed to index %s", t1->toChars());
+	e = new IndexExp(loc, e1, (Expression *)arguments->data[0]);
+	return e->semantic(sc);
+    }
+
+    // Run semantic() on each argument
+    for (size_t i = 0; i < arguments->dim; i++)
+    {	e = (Expression *)arguments->data[i];
+
+	e = e->semantic(sc);
+	if (!e->type)
+	    error("%s has no value", e->toChars());
+	arguments->data[i] = (void *)e;
+    }
+
+    expandTuples(arguments);
+    assert(arguments && arguments->dim);
+
+    e = op_overload(sc);
+    if (!e)
+    {	error("no [] operator overload for type %s", e1->type->toChars());
+	e = e1;
+    }
+    return e;
+}
+
+
+Expression *ArrayExp::toLvalue(Scope *sc, Expression *e)
+{
+    if (type && type->toBasetype()->ty == Tvoid)
+	error("voids have no value");
+    return this;
+}
+
+
+void ArrayExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{   int i;
+
+    expToCBuffer(buf, hgs, e1, PREC_primary);
+    buf->writeByte('[');
+    argsToCBuffer(buf, arguments, hgs);
+    buf->writeByte(']');
+}
+
+/************************* DotExp ***********************************/
+
+DotExp::DotExp(Loc loc, Expression *e1, Expression *e2)
+	: BinExp(loc, TOKdotexp, sizeof(DotExp), e1, e2)
+{
+}
+
+Expression *DotExp::semantic(Scope *sc)
+{
+#if LOGSEMANTIC
+    printf("DotExp::semantic('%s')\n", toChars());
+    if (type) printf("\ttype = %s\n", type->toChars());
+#endif
+    e1 = e1->semantic(sc);
+    e2 = e2->semantic(sc);
+    if (e2->op == TOKimport)
+    {
+	ScopeExp *se = (ScopeExp *)e2;
+	TemplateDeclaration *td = se->sds->isTemplateDeclaration();
+	if (td)
+	{   Expression *e = new DotTemplateExp(loc, e1, td);
+	    e = e->semantic(sc);
+	    return e;
+	}
+    }
+    if (!type)
+	type = e2->type;
+    return this;
+}
+
+
+/************************* CommaExp ***********************************/
+
+CommaExp::CommaExp(Loc loc, Expression *e1, Expression *e2)
+	: BinExp(loc, TOKcomma, sizeof(CommaExp), e1, e2)
+{
+}
+
+Expression *CommaExp::semantic(Scope *sc)
+{
+    if (!type)
+    {	BinExp::semanticp(sc);
+	type = e2->type;
+    }
+    return this;
+}
+
+void CommaExp::checkEscape()
+{
+    e2->checkEscape();
+}
+
+Expression *CommaExp::toLvalue(Scope *sc, Expression *e)
+{
+    e2 = e2->toLvalue(sc, NULL);
+    return this;
+}
+
+Expression *CommaExp::modifiableLvalue(Scope *sc, Expression *e)
+{
+    e2 = e2->modifiableLvalue(sc, e);
+    return this;
+}
+
+int CommaExp::isBool(int result)
+{
+    return e2->isBool(result);
+}
+
+int CommaExp::checkSideEffect(int flag)
+{
+    if (flag == 2)
+	return e1->checkSideEffect(2) || e2->checkSideEffect(2);
+    else
+    {
+	// Don't check e1 until we cast(void) the a,b code generation
+	return e2->checkSideEffect(flag);
+    }
+}
+
+/************************** IndexExp **********************************/
+
+// e1 [ e2 ]
+
+IndexExp::IndexExp(Loc loc, Expression *e1, Expression *e2)
+	: BinExp(loc, TOKindex, sizeof(IndexExp), e1, e2)
+{
+    //printf("IndexExp::IndexExp('%s')\n", toChars());
+    lengthVar = NULL;
+    modifiable = 0;	// assume it is an rvalue
+}
+
+Expression *IndexExp::semantic(Scope *sc)
+{   Expression *e;
+    BinExp *b;
+    UnaExp *u;
+    Type *t1;
+    ScopeDsymbol *sym;
+
+#if LOGSEMANTIC
+    printf("IndexExp::semantic('%s')\n", toChars());
+#endif
+    if (type)
+	return this;
+    if (!e1->type)
+	e1 = e1->semantic(sc);
+    assert(e1->type);		// semantic() should already be run on it
+    e = this;
+
+    // Note that unlike C we do not implement the int[ptr]
+
+    t1 = e1->type->toBasetype();
+
+    if (t1->ty == Tsarray || t1->ty == Tarray || t1->ty == Ttuple)
+    {	// Create scope for 'length' variable
+	sym = new ArrayScopeSymbol(this);
+	sym->loc = loc;
+	sym->parent = sc->scopesym;
+	sc = sc->push(sym);
+    }
+
+    e2 = e2->semantic(sc);
+    if (!e2->type)
+    {
+	error("%s has no value", e2->toChars());
+	e2->type = Type::terror;
+    }
+    e2 = resolveProperties(sc, e2);
+
+    if (t1->ty == Tsarray || t1->ty == Tarray || t1->ty == Ttuple)
+	sc = sc->pop();
+
+    switch (t1->ty)
+    {
+	case Tpointer:
+	case Tarray:
+	    e2 = e2->implicitCastTo(sc, Type::tsize_t);
+	    e->type = t1->next;
+	    break;
+
+	case Tsarray:
+	{
+	    e2 = e2->implicitCastTo(sc, Type::tsize_t);
+
+	    TypeSArray *tsa = (TypeSArray *)t1;
+
+#if 0 	// Don't do now, because it might be short-circuit evaluated
+	    // Do compile time array bounds checking if possible
+	    e2 = e2->optimize(WANTvalue);
+	    if (e2->op == TOKint64)
+	    {
+		integer_t index = e2->toInteger();
+		integer_t length = tsa->dim->toInteger();
+		if (index < 0 || index >= length)
+		    error("array index [%lld] is outside array bounds [0 .. %lld]",
+			    index, length);
+	    }
+#endif
+	    e->type = t1->next;
+	    break;
+	}
+
+	case Taarray:
+	{   TypeAArray *taa = (TypeAArray *)t1;
+
+	    e2 = e2->implicitCastTo(sc, taa->index);	// type checking
+	    e2 = e2->implicitCastTo(sc, taa->key);	// actual argument type
+	    type = taa->next;
+	    break;
+	}
+
+	case Ttuple:
+	{
+	    e2 = e2->implicitCastTo(sc, Type::tsize_t);
+	    e2 = e2->optimize(WANTvalue);
+	    uinteger_t index = e2->toUInteger();
+	    size_t length;
+	    TupleExp *te;
+	    TypeTuple *tup;
+
+	    if (e1->op == TOKtuple)
+	    {	te = (TupleExp *)e1;
+		length = te->exps->dim;
+	    }
+	    else if (e1->op == TOKtype)
+	    {
+		tup = (TypeTuple *)t1;
+		length = Argument::dim(tup->arguments);
+	    }
+	    else
+		assert(0);
+
+	    if (index < length)
+	    {
+
+		if (e1->op == TOKtuple)
+		    e = (Expression *)te->exps->data[(size_t)index];
+		else
+		    e = new TypeExp(e1->loc, Argument::getNth(tup->arguments, (size_t)index)->type);
+	    }
+	    else
+	    {
+		error("array index [%ju] is outside array bounds [0 .. %zu]",
+			index, length);
+		e = e1;
+	    }
+	    break;
+	}
+
+	default:
+	    error("%s must be an array or pointer type, not %s",
+		e1->toChars(), e1->type->toChars());
+	    type = Type::tint32;
+	    break;
+    }
+    return e;
+}
+
+Expression *IndexExp::toLvalue(Scope *sc, Expression *e)
+{
+//    if (type && type->toBasetype()->ty == Tvoid)
+//	error("voids have no value");
+    return this;
+}
+
+Expression *IndexExp::modifiableLvalue(Scope *sc, Expression *e)
+{
+    //printf("IndexExp::modifiableLvalue(%s)\n", toChars());
+    modifiable = 1;
+    if (e1->op == TOKstring)
+	error("string literals are immutable");
+    if (e1->type->toBasetype()->ty == Taarray)
+	e1 = e1->modifiableLvalue(sc, e1);
+    return toLvalue(sc, e);
+}
+
+void IndexExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    expToCBuffer(buf, hgs, e1, PREC_primary);
+    buf->writeByte('[');
+    expToCBuffer(buf, hgs, e2, PREC_assign);
+    buf->writeByte(']');
+}
+
+
+/************************* PostExp ***********************************/
+
+PostExp::PostExp(enum TOK op, Loc loc, Expression *e)
+	: BinExp(loc, op, sizeof(PostExp), e,
+	  new IntegerExp(loc, 1, Type::tint32))
+{
+}
+
+Expression *PostExp::semantic(Scope *sc)
+{   Expression *e = this;
+
+    if (!type)
+    {
+	BinExp::semantic(sc);
+	e2 = resolveProperties(sc, e2);
+
+	e = op_overload(sc);
+	if (e)
+	    return e;
+
+	e = this;
+	e1 = e1->modifiableLvalue(sc, NULL);
+	e1->checkScalar();
+	e1->checkNoBool();
+	if (e1->type->ty == Tpointer)
+	    e = scaleFactor(sc);
+	else
+	    e2 = e2->castTo(sc, e1->type);
+	e->type = e1->type;
+    }
+    return e;
+}
+
+void PostExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    expToCBuffer(buf, hgs, e1, precedence[op]);
+    buf->writestring((op == TOKplusplus) ? (char *)"++" : (char *)"--");
+}
+
+/************************************************************/
+
+/* Can be TOKconstruct too */
+
+AssignExp::AssignExp(Loc loc, Expression *e1, Expression *e2)
+	: BinExp(loc, TOKassign, sizeof(AssignExp), e1, e2)
+{
+    ismemset = 0;
+}
+
+Expression *AssignExp::semantic(Scope *sc)
+{   Type *t1;
+    Expression *e1old = e1;
+
+#if LOGSEMANTIC
+    printf("AssignExp::semantic('%s')\n", toChars());
+#endif
+    //printf("e1->op = %d, '%s'\n", e1->op, Token::toChars(e1->op));
+
+    /* Look for operator overloading of a[i]=value.
+     * Do it before semantic() otherwise the a[i] will have been
+     * converted to a.opIndex() already.
+     */
+    if (e1->op == TOKarray)
+    {	Type *t1;
+	ArrayExp *ae = (ArrayExp *)e1;
+	AggregateDeclaration *ad;
+	Identifier *id = Id::index;
+
+	ae->e1 = ae->e1->semantic(sc);
+	t1 = ae->e1->type->toBasetype();
+	if (t1->ty == Tstruct)
+	{
+	    ad = ((TypeStruct *)t1)->sym;
+	    goto L1;
+	}
+	else if (t1->ty == Tclass)
+	{
+	    ad = ((TypeClass *)t1)->sym;
+	  L1:
+	    // Rewrite (a[i] = value) to (a.opIndexAssign(value, i))
+	    if (search_function(ad, Id::indexass))
+	    {	Expression *e = new DotIdExp(loc, ae->e1, Id::indexass);
+		Expressions *a = (Expressions *)ae->arguments->copy();
+
+		a->insert(0, e2);
+		e = new CallExp(loc, e, a);
+		e = e->semantic(sc);
+		return e;
+	    }
+	    else
+	    {
+		// Rewrite (a[i] = value) to (a.opIndex(i, value))
+		if (search_function(ad, id))
+		{   Expression *e = new DotIdExp(loc, ae->e1, id);
+
+		    if (1 || !global.params.useDeprecated)
+			error("operator [] assignment overload with opIndex(i, value) illegal, use opIndexAssign(value, i)");
+
+		    e = new CallExp(loc, e, (Expression *)ae->arguments->data[0], e2);
+		    e = e->semantic(sc);
+		    return e;
+		}
+	    }
+	}
+    }
+    /* Look for operator overloading of a[i..j]=value.
+     * Do it before semantic() otherwise the a[i..j] will have been
+     * converted to a.opSlice() already.
+     */
+    if (e1->op == TOKslice)
+    {	Type *t1;
+	SliceExp *ae = (SliceExp *)e1;
+	AggregateDeclaration *ad;
+	Identifier *id = Id::index;
+
+	ae->e1 = ae->e1->semantic(sc);
+	ae->e1 = resolveProperties(sc, ae->e1);
+	t1 = ae->e1->type->toBasetype();
+	if (t1->ty == Tstruct)
+	{
+	    ad = ((TypeStruct *)t1)->sym;
+	    goto L2;
+	}
+	else if (t1->ty == Tclass)
+	{
+	    ad = ((TypeClass *)t1)->sym;
+	  L2:
+	    // Rewrite (a[i..j] = value) to (a.opIndexAssign(value, i, j))
+	    if (search_function(ad, Id::sliceass))
+	    {	Expression *e = new DotIdExp(loc, ae->e1, Id::sliceass);
+		Expressions *a = new Expressions();
+
+		a->push(e2);
+		if (ae->lwr)
+		{   a->push(ae->lwr);
+		    assert(ae->upr);
+		    a->push(ae->upr);
+		}
+		else
+		    assert(!ae->upr);
+		e = new CallExp(loc, e, a);
+		e = e->semantic(sc);
+		return e;
+	    }
+	}
+    }
+
+    BinExp::semantic(sc);
+    e2 = resolveProperties(sc, e2);
+    assert(e1->type);
+
+    t1 = e1->type->toBasetype();
+
+    if (t1->ty == Tfunction)
+    {	// Rewrite f=value to f(value)
+	Expression *e;
+
+	e = new CallExp(loc, e1, e2);
+	e = e->semantic(sc);
+	return e;
+    }
+
+    /* If it is an assignment from a 'foreign' type,
+     * check for operator overloading.
+     */
+    if (t1->ty == Tclass || t1->ty == Tstruct)
+    {
+	if (!e2->type->implicitConvTo(e1->type))
+	{
+	    Expression *e = op_overload(sc);
+	    if (e)
+		return e;
+	}
+    }
+
+    e2->rvalue();
+
+    if (e1->op == TOKarraylength)
+    {
+	// e1 is not an lvalue, but we let code generator handle it
+	ArrayLengthExp *ale = (ArrayLengthExp *)e1;
+
+	ale->e1 = ale->e1->modifiableLvalue(sc, NULL);
+    }
+    else if (e1->op == TOKslice)
+	;
+    else
+    {	// Try to do a decent error message with the expression
+	// before it got constant folded
+	e1 = e1->modifiableLvalue(sc, e1old);
+    }
+
+    if (e1->op == TOKslice &&
+	t1->next &&
+	!(t1->next->equals(e2->type->next) /*||
+	  (t1->next->ty == Tchar && e2->op == TOKstring)*/)
+       )
+    {	// memset
+	e2 = e2->implicitCastTo(sc, t1->next);
+    }
+#if 0
+    else if (e1->op == TOKslice &&
+	     e2->op == TOKstring &&
+	     ((StringExp *)e2)->len == 1)
+    {	// memset
+	e2 = e2->implicitCastTo(sc, e1->type->next);
+    }
+#endif
+    else if (t1->ty == Tsarray)
+    {
+	error("cannot assign to static array %s", e1->toChars());
+    }
+    else
+    {
+	e2 = e2->implicitCastTo(sc, e1->type);
+    }
+    type = e1->type;
+    assert(type);
+    return this;
+}
+
+Expression *AssignExp::checkToBoolean()
+{
+    // Things like:
+    //	if (a = b) ...
+    // are usually mistakes.
+
+    error("'=' does not give a boolean result");
+    return this;
+}
+
+/************************************************************/
+
+AddAssignExp::AddAssignExp(Loc loc, Expression *e1, Expression *e2)
+	: BinExp(loc, TOKaddass, sizeof(AddAssignExp), e1, e2)
+{
+}
+
+Expression *AddAssignExp::semantic(Scope *sc)
+{   Expression *e;
+
+    if (type)
+	return this;
+
+    BinExp::semantic(sc);
+    e2 = resolveProperties(sc, e2);
+
+    e = op_overload(sc);
+    if (e)
+	return e;
+
+    e1 = e1->modifiableLvalue(sc, NULL);
+
+    Type *tb1 = e1->type->toBasetype();
+    Type *tb2 = e2->type->toBasetype();
+
+    if ((tb1->ty == Tarray || tb1->ty == Tsarray) &&
+	(tb2->ty == Tarray || tb2->ty == Tsarray) &&
+	tb1->next->equals(tb2->next)
+       )
+    {
+	type = e1->type;
+	e = this;
+    }
+    else
+    {
+	e1->checkScalar();
+	e1->checkNoBool();
+	if (tb1->ty == Tpointer && tb2->isintegral())
+	    e = scaleFactor(sc);
+	else if (tb1->ty == Tbit || tb1->ty == Tbool)
+	{
+#if 0
+	    // Need to rethink this
+	    if (e1->op != TOKvar)
+	    {   // Rewrite e1+=e2 to (v=&e1),*v=*v+e2
+		VarDeclaration *v;
+		Expression *ea;
+		Expression *ex;
+
+		char name[6+6+1];
+		Identifier *id;
+		static int idn;
+		sprintf(name, "__name%d", ++idn);
+		id = Lexer::idPool(name);
+
+		v = new VarDeclaration(loc, tb1->pointerTo(), id, NULL);
+		v->semantic(sc);
+		if (!sc->insert(v))
+		    assert(0);
+		v->parent = sc->func;
+
+		ea = new AddrExp(loc, e1);
+		ea = new AssignExp(loc, new VarExp(loc, v), ea);
+
+		ex = new VarExp(loc, v);
+		ex = new PtrExp(loc, ex);
+		e = new AddExp(loc, ex, e2);
+		e = new CastExp(loc, e, e1->type);
+		e = new AssignExp(loc, ex->syntaxCopy(), e);
+
+		e = new CommaExp(loc, ea, e);
+	    }
+	    else
+#endif
+	    {   // Rewrite e1+=e2 to e1=e1+e2
+		// BUG: doesn't account for side effects in e1
+		// BUG: other assignment operators for bits aren't handled at all
+		e = new AddExp(loc, e1, e2);
+		e = new CastExp(loc, e, e1->type);
+		e = new AssignExp(loc, e1->syntaxCopy(), e);
+	    }
+	    e = e->semantic(sc);
+	}
+	else
+	{
+	    type = e1->type;
+	    typeCombine(sc);
+	    e1->checkArithmetic();
+	    e2->checkArithmetic();
+	    if (type->isreal() || type->isimaginary())
+	    {
+		assert(global.errors || e2->type->isfloating());
+		e2 = e2->castTo(sc, e1->type);
+	    }
+	    e = this;
+	}
+    }
+    return e;
+}
+
+/************************************************************/
+
+MinAssignExp::MinAssignExp(Loc loc, Expression *e1, Expression *e2)
+	: BinExp(loc, TOKminass, sizeof(MinAssignExp), e1, e2)
+{
+}
+
+Expression *MinAssignExp::semantic(Scope *sc)
+{   Expression *e;
+
+    if (type)
+	return this;
+
+    BinExp::semantic(sc);
+    e2 = resolveProperties(sc, e2);
+
+    e = op_overload(sc);
+    if (e)
+	return e;
+
+    e1 = e1->modifiableLvalue(sc, NULL);
+    e1->checkScalar();
+    e1->checkNoBool();
+    if (e1->type->ty == Tpointer && e2->type->isintegral())
+	e = scaleFactor(sc);
+    else
+    {
+	type = e1->type;
+	typeCombine(sc);
+	e1->checkArithmetic();
+	e2->checkArithmetic();
+	if (type->isreal() || type->isimaginary())
+	{
+	    assert(e2->type->isfloating());
+	    e2 = e2->castTo(sc, e1->type);
+	}
+	e = this;
+    }
+    return e;
+}
+
+/************************************************************/
+
+CatAssignExp::CatAssignExp(Loc loc, Expression *e1, Expression *e2)
+	: BinExp(loc, TOKcatass, sizeof(CatAssignExp), e1, e2)
+{
+}
+
+Expression *CatAssignExp::semantic(Scope *sc)
+{   Expression *e;
+
+    BinExp::semantic(sc);
+    e2 = resolveProperties(sc, e2);
+
+    e = op_overload(sc);
+    if (e)
+	return e;
+
+    if (e1->op == TOKslice)
+    {	SliceExp *se = (SliceExp *)e1;
+
+	if (se->e1->type->toBasetype()->ty == Tsarray)
+	    error("cannot append to static array %s", se->e1->type->toChars());
+    }
+
+    e1 = e1->modifiableLvalue(sc, NULL);
+
+    Type *tb1 = e1->type->toBasetype();
+    Type *tb2 = e2->type->toBasetype();
+
+    if ((tb1->ty == Tarray) &&
+	(tb2->ty == Tarray || tb2->ty == Tsarray) &&
+	e2->implicitConvTo(e1->type)
+	//e1->type->next->equals(e2->type->next)
+       )
+    {	// Append array
+	e2 = e2->castTo(sc, e1->type);
+	type = e1->type;
+	e = this;
+    }
+    else if ((tb1->ty == Tarray) &&
+	e2->implicitConvTo(tb1->next)
+       )
+    {	// Append element
+	e2 = e2->castTo(sc, tb1->next);
+	type = e1->type;
+	e = this;
+    }
+    else
+    {
+	error("cannot append type %s to type %s", tb2->toChars(), tb1->toChars());
+	type = Type::tint32;
+	e = this;
+    }
+    return e;
+}
+
+/************************************************************/
+
+MulAssignExp::MulAssignExp(Loc loc, Expression *e1, Expression *e2)
+	: BinExp(loc, TOKmulass, sizeof(MulAssignExp), e1, e2)
+{
+}
+
+Expression *MulAssignExp::semantic(Scope *sc)
+{   Expression *e;
+
+    BinExp::semantic(sc);
+    e2 = resolveProperties(sc, e2);
+
+    e = op_overload(sc);
+    if (e)
+	return e;
+
+    e1 = e1->modifiableLvalue(sc, NULL);
+    e1->checkScalar();
+    e1->checkNoBool();
+    type = e1->type;
+    typeCombine(sc);
+    e1->checkArithmetic();
+    e2->checkArithmetic();
+    if (e2->type->isfloating())
+    {	Type *t1;
+	Type *t2;
+
+	t1 = e1->type;
+	t2 = e2->type;
+	if (t1->isreal())
+	{
+	    if (t2->isimaginary() || t2->iscomplex())
+	    {
+		e2 = e2->castTo(sc, t1);
+	    }
+	}
+	else if (t1->isimaginary())
+	{
+	    if (t2->isimaginary() || t2->iscomplex())
+	    {
+		switch (t1->ty)
+		{
+		    case Timaginary32: t2 = Type::tfloat32; break;
+		    case Timaginary64: t2 = Type::tfloat64; break;
+		    case Timaginary80: t2 = Type::tfloat80; break;
+		    default:
+			assert(0);
+		}
+		e2 = e2->castTo(sc, t2);
+	    }
+	}
+    }
+    return this;
+}
+
+/************************************************************/
+
+DivAssignExp::DivAssignExp(Loc loc, Expression *e1, Expression *e2)
+	: BinExp(loc, TOKdivass, sizeof(DivAssignExp), e1, e2)
+{
+}
+
+Expression *DivAssignExp::semantic(Scope *sc)
+{   Expression *e;
+
+    BinExp::semantic(sc);
+    e2 = resolveProperties(sc, e2);
+
+    e = op_overload(sc);
+    if (e)
+	return e;
+
+    e1 = e1->modifiableLvalue(sc, NULL);
+    e1->checkScalar();
+    e1->checkNoBool();
+    type = e1->type;
+    typeCombine(sc);
+    e1->checkArithmetic();
+    e2->checkArithmetic();
+    if (e2->type->isimaginary())
+    {	Type *t1;
+	Type *t2;
+
+	t1 = e1->type;
+	if (t1->isreal())
+	{   // x/iv = i(-x/v)
+	    // Therefore, the result is 0
+	    e2 = new CommaExp(loc, e2, new RealExp(loc, 0, t1));
+	    e2->type = t1;
+	    e = new AssignExp(loc, e1, e2);
+	    e->type = t1;
+	    return e;
+	}
+	else if (t1->isimaginary())
+	{   Expression *e;
+
+	    switch (t1->ty)
+	    {
+		case Timaginary32: t2 = Type::tfloat32; break;
+		case Timaginary64: t2 = Type::tfloat64; break;
+		case Timaginary80: t2 = Type::tfloat80; break;
+		default:
+		    assert(0);
+	    }
+	    e2 = e2->castTo(sc, t2);
+	    e = new AssignExp(loc, e1, e2);
+	    e->type = t1;
+	    return e;
+	}
+    }
+    return this;
+}
+
+/************************************************************/
+
+ModAssignExp::ModAssignExp(Loc loc, Expression *e1, Expression *e2)
+	: BinExp(loc, TOKmodass, sizeof(ModAssignExp), e1, e2)
+{
+}
+
+Expression *ModAssignExp::semantic(Scope *sc)
+{
+    return commonSemanticAssign(sc);
+}
+
+/************************************************************/
+
+ShlAssignExp::ShlAssignExp(Loc loc, Expression *e1, Expression *e2)
+	: BinExp(loc, TOKshlass, sizeof(ShlAssignExp), e1, e2)
+{
+}
+
+Expression *ShlAssignExp::semantic(Scope *sc)
+{   Expression *e;
+
+    //printf("ShlAssignExp::semantic()\n");
+    BinExp::semantic(sc);
+    e2 = resolveProperties(sc, e2);
+
+    e = op_overload(sc);
+    if (e)
+	return e;
+
+    e1 = e1->modifiableLvalue(sc, NULL);
+    e1->checkScalar();
+    e1->checkNoBool();
+    type = e1->type;
+    typeCombine(sc);
+    e1->checkIntegral();
+    e2 = e2->checkIntegral();
+    e2 = e2->castTo(sc, Type::tshiftcnt);
+    return this;
+}
+
+/************************************************************/
+
+ShrAssignExp::ShrAssignExp(Loc loc, Expression *e1, Expression *e2)
+	: BinExp(loc, TOKshrass, sizeof(ShrAssignExp), e1, e2)
+{
+}
+
+Expression *ShrAssignExp::semantic(Scope *sc)
+{   Expression *e;
+
+    BinExp::semantic(sc);
+    e2 = resolveProperties(sc, e2);
+
+    e = op_overload(sc);
+    if (e)
+	return e;
+
+    e1 = e1->modifiableLvalue(sc, NULL);
+    e1->checkScalar();
+    e1->checkNoBool();
+    type = e1->type;
+    typeCombine(sc);
+    e1->checkIntegral();
+    e2 = e2->checkIntegral();
+    e2 = e2->castTo(sc, Type::tshiftcnt);
+    return this;
+}
+
+/************************************************************/
+
+UshrAssignExp::UshrAssignExp(Loc loc, Expression *e1, Expression *e2)
+	: BinExp(loc, TOKushrass, sizeof(UshrAssignExp), e1, e2)
+{
+}
+
+Expression *UshrAssignExp::semantic(Scope *sc)
+{   Expression *e;
+
+    BinExp::semantic(sc);
+    e2 = resolveProperties(sc, e2);
+
+    e = op_overload(sc);
+    if (e)
+	return e;
+
+    e1 = e1->modifiableLvalue(sc, NULL);
+    e1->checkScalar();
+    e1->checkNoBool();
+    type = e1->type;
+    typeCombine(sc);
+    e1->checkIntegral();
+    e2 = e2->checkIntegral();
+    e2 = e2->castTo(sc, Type::tshiftcnt);
+    return this;
+}
+
+/************************************************************/
+
+AndAssignExp::AndAssignExp(Loc loc, Expression *e1, Expression *e2)
+	: BinExp(loc, TOKandass, sizeof(AndAssignExp), e1, e2)
+{
+}
+
+Expression *AndAssignExp::semantic(Scope *sc)
+{
+    return commonSemanticAssignIntegral(sc);
+}
+
+/************************************************************/
+
+OrAssignExp::OrAssignExp(Loc loc, Expression *e1, Expression *e2)
+	: BinExp(loc, TOKorass, sizeof(OrAssignExp), e1, e2)
+{
+}
+
+Expression *OrAssignExp::semantic(Scope *sc)
+{
+    return commonSemanticAssignIntegral(sc);
+}
+
+/************************************************************/
+
+XorAssignExp::XorAssignExp(Loc loc, Expression *e1, Expression *e2)
+	: BinExp(loc, TOKxorass, sizeof(XorAssignExp), e1, e2)
+{
+}
+
+Expression *XorAssignExp::semantic(Scope *sc)
+{
+    return commonSemanticAssignIntegral(sc);
+}
+
+/************************* AddExp *****************************/
+
+AddExp::AddExp(Loc loc, Expression *e1, Expression *e2)
+	: BinExp(loc, TOKadd, sizeof(AddExp), e1, e2)
+{
+}
+
+Expression *AddExp::semantic(Scope *sc)
+{   Expression *e;
+
+#if LOGSEMANTIC
+    printf("AddExp::semantic('%s')\n", toChars());
+#endif
+    if (!type)
+    {
+	BinExp::semanticp(sc);
+
+	e = op_overload(sc);
+	if (e)
+	    return e;
+
+	Type *tb1 = e1->type->toBasetype();
+	Type *tb2 = e2->type->toBasetype();
+
+        if ((tb1->ty == Tarray || tb1->ty == Tsarray) &&
+            (tb2->ty == Tarray || tb2->ty == Tsarray) &&
+            tb1->next->equals(tb2->next)
+           )
+        {
+            type = e1->type;
+            e = this;
+        }
+	else if (tb1->ty == Tpointer && e2->type->isintegral() ||
+	    tb2->ty == Tpointer && e1->type->isintegral())
+	    e = scaleFactor(sc);
+	else if (tb1->ty == Tpointer && tb2->ty == Tpointer)
+	{
+	    incompatibleTypes();
+	    type = e1->type;
+	    e = this;
+	}
+	else
+	{
+	    typeCombine(sc);
+	    if ((e1->type->isreal() && e2->type->isimaginary()) ||
+		(e1->type->isimaginary() && e2->type->isreal()))
+	    {
+		switch (type->toBasetype()->ty)
+		{
+		    case Tfloat32:
+		    case Timaginary32:
+			type = Type::tcomplex32;
+			break;
+
+		    case Tfloat64:
+		    case Timaginary64:
+			type = Type::tcomplex64;
+			break;
+
+		    case Tfloat80:
+		    case Timaginary80:
+			type = Type::tcomplex80;
+			break;
+
+		    default:
+			assert(0);
+		}
+	    }
+	    e = this;
+	}
+	return e;
+    }
+    return this;
+}
+
+/************************************************************/
+
+MinExp::MinExp(Loc loc, Expression *e1, Expression *e2)
+	: BinExp(loc, TOKmin, sizeof(MinExp), e1, e2)
+{
+}
+
+Expression *MinExp::semantic(Scope *sc)
+{   Expression *e;
+    Type *t1;
+    Type *t2;
+
+#if LOGSEMANTIC
+    printf("MinExp::semantic('%s')\n", toChars());
+#endif
+    if (type)
+	return this;
+
+    BinExp::semanticp(sc);
+
+    e = op_overload(sc);
+    if (e)
+	return e;
+
+    e = this;
+    t1 = e1->type->toBasetype();
+    t2 = e2->type->toBasetype();
+    if (t1->ty == Tpointer)
+    {
+	if (t2->ty == Tpointer)
+	{   // Need to divide the result by the stride
+	    // Replace (ptr - ptr) with (ptr - ptr) / stride
+	    d_int64 stride;
+	    Expression *e;
+
+	    typeCombine(sc);		// make sure pointer types are compatible
+	    type = Type::tptrdiff_t;
+	    stride = t2->next->size();
+	    e = new DivExp(loc, this, new IntegerExp(0, stride, Type::tptrdiff_t));
+	    e->type = Type::tptrdiff_t;
+	    return e;
+	}
+	else if (t2->isintegral())
+	    e = scaleFactor(sc);
+	else
+	{   error("incompatible types for -");
+	    return new IntegerExp(0);
+	}
+    }
+    else if (t2->ty == Tpointer)
+    {
+	type = e2->type;
+	error("can't subtract pointer from %s", e1->type->toChars());
+	return new IntegerExp(0);
+    }
+    else
+    {
+	typeCombine(sc);
+	t1 = e1->type->toBasetype();
+	t2 = e2->type->toBasetype();
+	if ((t1->isreal() && t2->isimaginary()) ||
+	    (t1->isimaginary() && t2->isreal()))
+	{
+	    switch (type->ty)
+	    {
+		case Tfloat32:
+		case Timaginary32:
+		    type = Type::tcomplex32;
+		    break;
+
+		case Tfloat64:
+		case Timaginary64:
+		    type = Type::tcomplex64;
+		    break;
+
+		case Tfloat80:
+		case Timaginary80:
+		    type = Type::tcomplex80;
+		    break;
+
+		default:
+		    assert(0);
+	    }
+	}
+    }
+    return e;
+}
+
+/************************* CatExp *****************************/
+
+CatExp::CatExp(Loc loc, Expression *e1, Expression *e2)
+	: BinExp(loc, TOKcat, sizeof(CatExp), e1, e2)
+{
+}
+
+Expression *CatExp::semantic(Scope *sc)
+{   Expression *e;
+
+    //printf("CatExp::semantic() %s\n", toChars());
+    if (!type)
+    {
+	BinExp::semanticp(sc);
+	e = op_overload(sc);
+	if (e)
+	    return e;
+
+	Type *tb1 = e1->type->toBasetype();
+	Type *tb2 = e2->type->toBasetype();
+
+
+	/* BUG: Should handle things like:
+	 *	char c;
+	 *	c ~ ' '
+	 *	' ' ~ c;
+	 */
+
+#if 0
+	e1->type->print();
+	e2->type->print();
+#endif
+	if ((tb1->ty == Tsarray || tb1->ty == Tarray) &&
+	    e2->type->equals(tb1->next))
+	{
+	    type = tb1->next->arrayOf();
+	    if (tb2->ty == Tarray)
+	    {	// Make e2 into [e2]
+		e2 = new ArrayLiteralExp(e2->loc, e2);
+		e2->type = type;
+	    }
+	    return this;
+	}
+	else if ((tb2->ty == Tsarray || tb2->ty == Tarray) &&
+	    e1->type->equals(tb2->next))
+	{
+	    type = tb2->next->arrayOf();
+	    if (tb1->ty == Tarray)
+	    {	// Make e1 into [e1]
+		e1 = new ArrayLiteralExp(e1->loc, e1);
+		e1->type = type;
+	    }
+	    return this;
+	}
+
+	typeCombine(sc);
+
+	if (type->toBasetype()->ty == Tsarray)
+	    type = type->toBasetype()->next->arrayOf();
+#if 0
+	e1->type->print();
+	e2->type->print();
+	type->print();
+	print();
+#endif
+	if (e1->op == TOKstring && e2->op == TOKstring)
+	    e = optimize(WANTvalue);
+	else if (e1->type->equals(e2->type) &&
+		(e1->type->toBasetype()->ty == Tarray ||
+		 e1->type->toBasetype()->ty == Tsarray))
+	{
+	    e = this;
+	}
+	else
+	{
+	    error("Can only concatenate arrays, not (%s ~ %s)",
+		e1->type->toChars(), e2->type->toChars());
+	    type = Type::tint32;
+	    e = this;
+	}
+	e->type = e->type->semantic(loc, sc);
+	return e;
+    }
+    return this;
+}
+
+/************************************************************/
+
+MulExp::MulExp(Loc loc, Expression *e1, Expression *e2)
+	: BinExp(loc, TOKmul, sizeof(MulExp), e1, e2)
+{
+}
+
+Expression *MulExp::semantic(Scope *sc)
+{   Expression *e;
+
+#if 0
+    printf("MulExp::semantic() %s\n", toChars());
+#endif
+    if (type)
+    {
+	return this;
+    }
+
+    BinExp::semanticp(sc);
+    e = op_overload(sc);
+    if (e)
+	return e;
+
+    typeCombine(sc);
+    e1->checkArithmetic();
+    e2->checkArithmetic();
+    if (type->isfloating())
+    {	Type *t1 = e1->type;
+	Type *t2 = e2->type;
+
+	if (t1->isreal())
+	{
+	    type = t2;
+	}
+	else if (t2->isreal())
+	{
+	    type = t1;
+	}
+	else if (t1->isimaginary())
+	{
+	    if (t2->isimaginary())
+	    {	Expression *e;
+
+		switch (t1->ty)
+		{
+		    case Timaginary32:	type = Type::tfloat32;	break;
+		    case Timaginary64:	type = Type::tfloat64;	break;
+		    case Timaginary80:	type = Type::tfloat80;	break;
+		    default:		assert(0);
+		}
+
+		// iy * iv = -yv
+		e1->type = type;
+		e2->type = type;
+		e = new NegExp(loc, this);
+		e = e->semantic(sc);
+		return e;
+	    }
+	    else
+		type = t2;	// t2 is complex
+	}
+	else if (t2->isimaginary())
+	{
+	    type = t1;	// t1 is complex
+	}
+    }
+    return this;
+}
+
+/************************************************************/
+
+DivExp::DivExp(Loc loc, Expression *e1, Expression *e2)
+	: BinExp(loc, TOKdiv, sizeof(DivExp), e1, e2)
+{
+}
+
+Expression *DivExp::semantic(Scope *sc)
+{   Expression *e;
+
+    if (type)
+	return this;
+
+    BinExp::semanticp(sc);
+    e = op_overload(sc);
+    if (e)
+	return e;
+
+    typeCombine(sc);
+    e1->checkArithmetic();
+    e2->checkArithmetic();
+    if (type->isfloating())
+    {	Type *t1 = e1->type;
+	Type *t2 = e2->type;
+
+	if (t1->isreal())
+	{
+	    type = t2;
+	    if (t2->isimaginary())
+	    {	Expression *e;
+
+		// x/iv = i(-x/v)
+		e2->type = t1;
+		e = new NegExp(loc, this);
+		e = e->semantic(sc);
+		return e;
+	    }
+	}
+	else if (t2->isreal())
+	{
+	    type = t1;
+	}
+	else if (t1->isimaginary())
+	{
+	    if (t2->isimaginary())
+	    {
+		switch (t1->ty)
+		{
+		    case Timaginary32:	type = Type::tfloat32;	break;
+		    case Timaginary64:	type = Type::tfloat64;	break;
+		    case Timaginary80:	type = Type::tfloat80;	break;
+		    default:		assert(0);
+		}
+	    }
+	    else
+		type = t2;	// t2 is complex
+	}
+	else if (t2->isimaginary())
+	{
+	    type = t1;	// t1 is complex
+	}
+    }
+    return this;
+}
+
+/************************************************************/
+
+ModExp::ModExp(Loc loc, Expression *e1, Expression *e2)
+	: BinExp(loc, TOKmod, sizeof(ModExp), e1, e2)
+{
+}
+
+Expression *ModExp::semantic(Scope *sc)
+{   Expression *e;
+
+    if (type)
+	return this;
+
+    BinExp::semanticp(sc);
+    e = op_overload(sc);
+    if (e)
+	return e;
+
+    typeCombine(sc);
+    e1->checkArithmetic();
+    e2->checkArithmetic();
+    if (type->isfloating())
+    {	type = e1->type;
+	if (e2->type->iscomplex())
+	{   error("cannot perform modulo complex arithmetic");
+	    return new IntegerExp(0);
+	}
+    }
+    return this;
+}
+
+/************************************************************/
+
+ShlExp::ShlExp(Loc loc, Expression *e1, Expression *e2)
+	: BinExp(loc, TOKshl, sizeof(ShlExp), e1, e2)
+{
+}
+
+Expression *ShlExp::semantic(Scope *sc)
+{   Expression *e;
+
+    //printf("ShlExp::semantic(), type = %p\n", type);
+    if (!type)
+    {	BinExp::semanticp(sc);
+	e = op_overload(sc);
+	if (e)
+	    return e;
+	e1 = e1->checkIntegral();
+	e2 = e2->checkIntegral();
+	e1 = e1->integralPromotions(sc);
+	e2 = e2->castTo(sc, Type::tshiftcnt);
+	type = e1->type;
+    }
+    return this;
+}
+
+/************************************************************/
+
+ShrExp::ShrExp(Loc loc, Expression *e1, Expression *e2)
+	: BinExp(loc, TOKshr, sizeof(ShrExp), e1, e2)
+{
+}
+
+Expression *ShrExp::semantic(Scope *sc)
+{   Expression *e;
+
+    if (!type)
+    {	BinExp::semanticp(sc);
+	e = op_overload(sc);
+	if (e)
+	    return e;
+	e1 = e1->checkIntegral();
+	e2 = e2->checkIntegral();
+	e1 = e1->integralPromotions(sc);
+	e2 = e2->castTo(sc, Type::tshiftcnt);
+	type = e1->type;
+    }
+    return this;
+}
+
+/************************************************************/
+
+UshrExp::UshrExp(Loc loc, Expression *e1, Expression *e2)
+	: BinExp(loc, TOKushr, sizeof(UshrExp), e1, e2)
+{
+}
+
+Expression *UshrExp::semantic(Scope *sc)
+{   Expression *e;
+
+    if (!type)
+    {	BinExp::semanticp(sc);
+	e = op_overload(sc);
+	if (e)
+	    return e;
+	e1 = e1->checkIntegral();
+	e2 = e2->checkIntegral();
+	e1 = e1->integralPromotions(sc);
+	e2 = e2->castTo(sc, Type::tshiftcnt);
+	type = e1->type;
+    }
+    return this;
+}
+
+/************************************************************/
+
+AndExp::AndExp(Loc loc, Expression *e1, Expression *e2)
+	: BinExp(loc, TOKand, sizeof(AndExp), e1, e2)
+{
+}
+
+Expression *AndExp::semantic(Scope *sc)
+{   Expression *e;
+
+    if (!type)
+    {	BinExp::semanticp(sc);
+	e = op_overload(sc);
+	if (e)
+	    return e;
+	if (e1->type->toBasetype()->ty == Tbool &&
+	    e2->type->toBasetype()->ty == Tbool)
+	{
+	    type = e1->type;
+	    e = this;
+	}
+	else
+	{
+	    typeCombine(sc);
+	    e1->checkIntegral();
+	    e2->checkIntegral();
+	}
+    }
+    return this;
+}
+
+/************************************************************/
+
+OrExp::OrExp(Loc loc, Expression *e1, Expression *e2)
+	: BinExp(loc, TOKor, sizeof(OrExp), e1, e2)
+{
+}
+
+Expression *OrExp::semantic(Scope *sc)
+{   Expression *e;
+
+    if (!type)
+    {	BinExp::semanticp(sc);
+	e = op_overload(sc);
+	if (e)
+	    return e;
+	if (e1->type->toBasetype()->ty == Tbool &&
+	    e2->type->toBasetype()->ty == Tbool)
+	{
+	    type = e1->type;
+	    e = this;
+	}
+	else
+	{
+	    typeCombine(sc);
+	    e1->checkIntegral();
+	    e2->checkIntegral();
+	}
+    }
+    return this;
+}
+
+/************************************************************/
+
+XorExp::XorExp(Loc loc, Expression *e1, Expression *e2)
+	: BinExp(loc, TOKxor, sizeof(XorExp), e1, e2)
+{
+}
+
+Expression *XorExp::semantic(Scope *sc)
+{   Expression *e;
+
+    if (!type)
+    {	BinExp::semanticp(sc);
+	e = op_overload(sc);
+	if (e)
+	    return e;
+	if (e1->type->toBasetype()->ty == Tbool &&
+	    e2->type->toBasetype()->ty == Tbool)
+	{
+	    type = e1->type;
+	    e = this;
+	}
+	else
+	{
+	    typeCombine(sc);
+	    e1->checkIntegral();
+	    e2->checkIntegral();
+	}
+    }
+    return this;
+}
+
+
+/************************************************************/
+
+OrOrExp::OrOrExp(Loc loc, Expression *e1, Expression *e2)
+	: BinExp(loc, TOKoror, sizeof(OrOrExp), e1, e2)
+{
+}
+
+Expression *OrOrExp::semantic(Scope *sc)
+{
+    unsigned cs1;
+
+    // same as for AndAnd
+    e1 = e1->semantic(sc);
+    e1 = resolveProperties(sc, e1);
+    e1 = e1->checkToPointer();
+    e1 = e1->checkToBoolean();
+    cs1 = sc->callSuper;
+
+    if (sc->flags & SCOPEstaticif)
+    {
+	/* If in static if, don't evaluate e2 if we don't have to.
+	 */
+	e1 = e1->optimize(WANTflags);
+	if (e1->isBool(TRUE))
+	{
+	    return new IntegerExp(loc, 1, Type::tboolean);
+	}
+    }
+
+    e2 = e2->semantic(sc);
+    sc->mergeCallSuper(loc, cs1);
+    e2 = resolveProperties(sc, e2);
+    e2 = e2->checkToPointer();
+
+    type = Type::tboolean;
+    if (e1->type->ty == Tvoid)
+	type = Type::tvoid;
+    if (e2->op == TOKtype || e2->op == TOKimport)
+	error("%s is not an expression", e2->toChars());
+    return this;
+}
+
+Expression *OrOrExp::checkToBoolean()
+{
+    e2 = e2->checkToBoolean();
+    return this;
+}
+
+int OrOrExp::isBit()
+{
+    return TRUE;
+}
+
+int OrOrExp::checkSideEffect(int flag)
+{
+    if (flag == 2)
+    {
+	return e1->checkSideEffect(2) || e2->checkSideEffect(2);
+    }
+    else
+    {	e1->checkSideEffect(1);
+	return e2->checkSideEffect(flag);
+    }
+}
+
+/************************************************************/
+
+AndAndExp::AndAndExp(Loc loc, Expression *e1, Expression *e2)
+	: BinExp(loc, TOKandand, sizeof(AndAndExp), e1, e2)
+{
+}
+
+Expression *AndAndExp::semantic(Scope *sc)
+{
+    unsigned cs1;
+
+    // same as for OrOr
+    e1 = e1->semantic(sc);
+    e1 = resolveProperties(sc, e1);
+    e1 = e1->checkToPointer();
+    e1 = e1->checkToBoolean();
+    cs1 = sc->callSuper;
+
+    if (sc->flags & SCOPEstaticif)
+    {
+	/* If in static if, don't evaluate e2 if we don't have to.
+	 */
+	e1 = e1->optimize(WANTflags);
+	if (e1->isBool(FALSE))
+	{
+	    return new IntegerExp(loc, 0, Type::tboolean);
+	}
+    }
+
+    e2 = e2->semantic(sc);
+    sc->mergeCallSuper(loc, cs1);
+    e2 = resolveProperties(sc, e2);
+    e2 = e2->checkToPointer();
+
+    type = Type::tboolean;
+    if (e1->type->ty == Tvoid)
+	type = Type::tvoid;
+    if (e2->op == TOKtype || e2->op == TOKimport)
+	error("%s is not an expression", e2->toChars());
+    return this;
+}
+
+Expression *AndAndExp::checkToBoolean()
+{
+    e2 = e2->checkToBoolean();
+    return this;
+}
+
+int AndAndExp::isBit()
+{
+    return TRUE;
+}
+
+int AndAndExp::checkSideEffect(int flag)
+{
+    if (flag == 2)
+    {
+	return e1->checkSideEffect(2) || e2->checkSideEffect(2);
+    }
+    else
+    {
+	e1->checkSideEffect(1);
+	return e2->checkSideEffect(flag);
+    }
+}
+
+/************************************************************/
+
+InExp::InExp(Loc loc, Expression *e1, Expression *e2)
+	: BinExp(loc, TOKin, sizeof(InExp), e1, e2)
+{
+}
+
+Expression *InExp::semantic(Scope *sc)
+{   Expression *e;
+
+    if (type)
+	return this;
+
+    BinExp::semanticp(sc);
+    e = op_overload(sc);
+    if (e)
+	return e;
+
+    //type = Type::tboolean;
+    Type *t2b = e2->type->toBasetype();
+    if (t2b->ty != Taarray)
+    {
+	error("rvalue of in expression must be an associative array, not %s", e2->type->toChars());
+	type = Type::terror;
+    }
+    else
+    {
+	TypeAArray *ta = (TypeAArray *)t2b;
+
+	// Convert key to type of key
+	e1 = e1->implicitCastTo(sc, ta->index);
+
+	// Return type is pointer to value
+	type = ta->next->pointerTo();
+    }
+    return this;
+}
+
+int InExp::isBit()
+{
+    return FALSE;
+}
+
+
+/************************************************************/
+
+/* This deletes the key e1 from the associative array e2
+ */
+
+RemoveExp::RemoveExp(Loc loc, Expression *e1, Expression *e2)
+	: BinExp(loc, TOKremove, sizeof(RemoveExp), e1, e2)
+{
+    type = Type::tvoid;
+}
+
+/************************************************************/
+
+CmpExp::CmpExp(enum TOK op, Loc loc, Expression *e1, Expression *e2)
+	: BinExp(loc, op, sizeof(CmpExp), e1, e2)
+{
+}
+
+Expression *CmpExp::semantic(Scope *sc)
+{   Expression *e;
+    Type *t1;
+    Type *t2;
+
+#if LOGSEMANTIC
+    printf("CmpExp::semantic('%s')\n", toChars());
+#endif
+    if (type)
+	return this;
+
+    BinExp::semanticp(sc);
+    e = op_overload(sc);
+    if (e)
+    {
+	e = new CmpExp(op, loc, e, new IntegerExp(loc, 0, Type::tint32));
+	e = e->semantic(sc);
+	return e;
+    }
+
+    typeCombine(sc);
+    type = Type::tboolean;
+
+    // Special handling for array comparisons
+    t1 = e1->type->toBasetype();
+    t2 = e2->type->toBasetype();
+    if ((t1->ty == Tarray || t1->ty == Tsarray) &&
+	(t2->ty == Tarray || t2->ty == Tsarray))
+    {
+	if (!t1->next->equals(t2->next))
+	    error("array comparison type mismatch, %s vs %s", t1->next->toChars(), t2->next->toChars());
+	e = this;
+    }
+    else if (t1->ty == Tstruct || t2->ty == Tstruct ||
+	     (t1->ty == Tclass && t2->ty == Tclass))
+    {
+	if (t2->ty == Tstruct)
+	    error("need member function opCmp() for %s %s to compare", t2->toDsymbol(sc)->kind(), t2->toChars());
+	else
+	    error("need member function opCmp() for %s %s to compare", t1->toDsymbol(sc)->kind(), t1->toChars());
+	e = this;
+    }
+#if 1
+    else if (t1->iscomplex() || t2->iscomplex())
+    {
+	error("compare not defined for complex operands");
+	e = new IntegerExp(0);
+    }
+#endif
+    else
+	e = this;
+    return e;
+}
+
+int CmpExp::isBit()
+{
+    return TRUE;
+}
+
+
+/************************************************************/
+
+EqualExp::EqualExp(enum TOK op, Loc loc, Expression *e1, Expression *e2)
+	: BinExp(loc, op, sizeof(EqualExp), e1, e2)
+{
+}
+
+Expression *EqualExp::semantic(Scope *sc)
+{   Expression *e;
+    Type *t1;
+    Type *t2;
+
+    //printf("EqualExp::semantic('%s')\n", toChars());
+    if (type)
+	return this;
+
+    BinExp::semanticp(sc);
+
+    /* Before checking for operator overloading, check to see if we're
+     * comparing the addresses of two statics. If so, we can just see
+     * if they are the same symbol.
+     */
+    if (e1->op == TOKaddress && e2->op == TOKaddress)
+    {	AddrExp *ae1 = (AddrExp *)e1;
+	AddrExp *ae2 = (AddrExp *)e2;
+
+	if (ae1->e1->op == TOKvar && ae2->e1->op == TOKvar)
+	{   VarExp *ve1 = (VarExp *)ae1->e1;
+	    VarExp *ve2 = (VarExp *)ae2->e1;
+
+	    if (ve1->var == ve2->var /*|| ve1->var->toSymbol() == ve2->var->toSymbol()*/)
+	    {
+		// They are the same, result is 'true' for ==, 'false' for !=
+		e = new IntegerExp(loc, (op == TOKequal), Type::tboolean);
+		return e;
+	    }
+	}
+    }
+
+    //if (e2->op != TOKnull)
+    {
+	e = op_overload(sc);
+	if (e)
+	{
+	    if (op == TOKnotequal)
+	    {
+		e = new NotExp(e->loc, e);
+		e = e->semantic(sc);
+	    }
+	    return e;
+	}
+    }
+
+    e = typeCombine(sc);
+    type = Type::tboolean;
+
+    // Special handling for array comparisons
+    t1 = e1->type->toBasetype();
+    t2 = e2->type->toBasetype();
+    if ((t1->ty == Tarray || t1->ty == Tsarray) &&
+	(t2->ty == Tarray || t2->ty == Tsarray))
+    {
+	if (!t1->next->equals(t2->next))
+	    error("array comparison type mismatch, %s vs %s", t1->next->toChars(), t2->next->toChars());
+    }
+    else
+    {
+	if (e1->type != e2->type && e1->type->isfloating() && e2->type->isfloating())
+	{
+	    // Cast both to complex
+	    e1 = e1->castTo(sc, Type::tcomplex80);
+	    e2 = e2->castTo(sc, Type::tcomplex80);
+	}
+    }
+    return e;
+}
+
+int EqualExp::isBit()
+{
+    return TRUE;
+}
+
+
+
+/************************************************************/
+
+IdentityExp::IdentityExp(enum TOK op, Loc loc, Expression *e1, Expression *e2)
+	: BinExp(loc, op, sizeof(IdentityExp), e1, e2)
+{
+}
+
+Expression *IdentityExp::semantic(Scope *sc)
+{
+    if (type)
+	return this;
+
+    BinExp::semanticp(sc);
+    type = Type::tboolean;
+    typeCombine(sc);
+    if (e1->type != e2->type && e1->type->isfloating() && e2->type->isfloating())
+    {
+	// Cast both to complex
+	e1 = e1->castTo(sc, Type::tcomplex80);
+	e2 = e2->castTo(sc, Type::tcomplex80);
+    }
+    return this;
+}
+
+int IdentityExp::isBit()
+{
+    return TRUE;
+}
+
+
+/****************************************************************/
+
+CondExp::CondExp(Loc loc, Expression *econd, Expression *e1, Expression *e2)
+	: BinExp(loc, TOKquestion, sizeof(CondExp), e1, e2)
+{
+    this->econd = econd;
+}
+
+Expression *CondExp::syntaxCopy()
+{
+    return new CondExp(loc, econd->syntaxCopy(), e1->syntaxCopy(), e2->syntaxCopy());
+}
+
+
+Expression *CondExp::semantic(Scope *sc)
+{   Type *t1;
+    Type *t2;
+    unsigned cs0;
+    unsigned cs1;
+
+#if LOGSEMANTIC
+    printf("CondExp::semantic('%s')\n", toChars());
+#endif
+    if (type)
+	return this;
+
+    econd = econd->semantic(sc);
+    econd = resolveProperties(sc, econd);
+    econd = econd->checkToPointer();
+    econd = econd->checkToBoolean();
+
+#if 0	/* this cannot work right because the types of e1 and e2
+ 	 * both contribute to the type of the result.
+	 */
+    if (sc->flags & SCOPEstaticif)
+    {
+	/* If in static if, don't evaluate what we don't have to.
+	 */
+	econd = econd->optimize(WANTflags);
+	if (econd->isBool(TRUE))
+	{
+	    e1 = e1->semantic(sc);
+	    e1 = resolveProperties(sc, e1);
+	    return e1;
+	}
+	else if (econd->isBool(FALSE))
+	{
+	    e2 = e2->semantic(sc);
+	    e2 = resolveProperties(sc, e2);
+	    return e2;
+	}
+    }
+#endif
+
+
+    cs0 = sc->callSuper;
+    e1 = e1->semantic(sc);
+    e1 = resolveProperties(sc, e1);
+    cs1 = sc->callSuper;
+    sc->callSuper = cs0;
+    e2 = e2->semantic(sc);
+    e2 = resolveProperties(sc, e2);
+    sc->mergeCallSuper(loc, cs1);
+
+
+    // If either operand is void, the result is void
+    t1 = e1->type;
+    t2 = e2->type;
+    if (t1->ty == Tvoid || t2->ty == Tvoid)
+	type = Type::tvoid;
+    else if (t1 == t2)
+	type = t1;
+    else
+    {
+	typeCombine(sc);
+	switch (e1->type->toBasetype()->ty)
+	{
+	    case Tcomplex32:
+	    case Tcomplex64:
+	    case Tcomplex80:
+		e2 = e2->castTo(sc, e1->type);
+		break;
+	}
+	switch (e2->type->toBasetype()->ty)
+	{
+	    case Tcomplex32:
+	    case Tcomplex64:
+	    case Tcomplex80:
+		e1 = e1->castTo(sc, e2->type);
+		break;
+	}
+    }
+    return this;
+}
+
+Expression *CondExp::toLvalue(Scope *sc, Expression *ex)
+{
+    PtrExp *e;
+
+    // convert (econd ? e1 : e2) to *(econd ? &e1 : &e2)
+    e = new PtrExp(loc, this, type);
+
+    e1 = e1->addressOf(sc);
+    //e1 = e1->toLvalue(sc, NULL);
+
+    e2 = e2->addressOf(sc);
+    //e2 = e2->toLvalue(sc, NULL);
+
+    typeCombine(sc);
+
+    type = e2->type;
+    return e;
+}
+
+Expression *CondExp::modifiableLvalue(Scope *sc, Expression *e)
+{
+    error("conditional expression %s is not a modifiable lvalue", toChars());
+    return this;
+}
+
+void CondExp::checkEscape()
+{
+    e1->checkEscape();
+    e2->checkEscape();
+}
+
+
+Expression *CondExp::checkToBoolean()
+{
+    e1 = e1->checkToBoolean();
+    e2 = e2->checkToBoolean();
+    return this;
+}
+
+int CondExp::checkSideEffect(int flag)
+{
+    if (flag == 2)
+    {
+	return econd->checkSideEffect(2) ||
+		e1->checkSideEffect(2) ||
+		e2->checkSideEffect(2);
+    }
+    else
+    {
+	econd->checkSideEffect(1);
+	e1->checkSideEffect(flag);
+	return e2->checkSideEffect(flag);
+    }
+}
+
+void CondExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    expToCBuffer(buf, hgs, econd, PREC_oror);
+    buf->writestring(" ? ");
+    expToCBuffer(buf, hgs, e1, PREC_expr);
+    buf->writestring(" : ");
+    expToCBuffer(buf, hgs, e2, PREC_cond);
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/expression.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,1410 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#ifndef DMD_EXPRESSION_H
+#define DMD_EXPRESSION_H
+
+#include "mars.h"
+#include "identifier.h"
+#include "lexer.h"
+#include "arraytypes.h"
+
+struct Type;
+struct Scope;
+struct TupleDeclaration;
+struct VarDeclaration;
+struct FuncDeclaration;
+struct FuncLiteralDeclaration;
+struct Declaration;
+struct CtorDeclaration;
+struct NewDeclaration;
+struct Dsymbol;
+struct Import;
+struct Module;
+struct ScopeDsymbol;
+struct InlineCostState;
+struct InlineDoState;
+struct InlineScanState;
+struct Expression;
+struct Declaration;
+struct AggregateDeclaration;
+struct StructDeclaration;
+struct TemplateInstance;
+struct TemplateDeclaration;
+struct ClassDeclaration;
+struct HdrGenState;
+struct BinExp;
+struct InterState;
+struct Symbol;		// back end symbol
+
+namespace llvm
+{
+    class ConstantInt;
+}
+
+enum TOK;
+
+// Back end
+struct IRState;
+struct dt_t;
+
+#ifdef IN_GCC
+union tree_node; typedef union tree_node elem;
+#else
+struct elem;
+#endif
+
+void initPrecedence();
+
+Expression *resolveProperties(Scope *sc, Expression *e);
+void accessCheck(Loc loc, Scope *sc, Expression *e, Declaration *d);
+Dsymbol *search_function(AggregateDeclaration *ad, Identifier *funcid);
+void inferApplyArgTypes(enum TOK op, Arguments *arguments, Expression *aggr);
+void argExpTypesToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs);
+void argsToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs);
+void expandTuples(Expressions *exps);
+
+struct Expression : Object
+{
+    Loc loc;			// file location
+    enum TOK op;		// handy to minimize use of dynamic_cast
+    Type *type;			// !=NULL means that semantic() has been run
+    int size;			// # of bytes in Expression so we can copy() it
+
+    Expression(Loc loc, enum TOK op, int size);
+    Expression *copy();
+    virtual Expression *syntaxCopy();
+    virtual Expression *semantic(Scope *sc);
+
+    int dyncast() { return DYNCAST_EXPRESSION; }	// kludge for template.isExpression()
+
+    void print();
+    char *toChars();
+    virtual void dump(int indent);
+    void error(const char *format, ...);
+    virtual void rvalue();
+
+    static Expression *combine(Expression *e1, Expression *e2);
+    static Expressions *arraySyntaxCopy(Expressions *exps);
+
+    virtual integer_t toInteger();
+    virtual uinteger_t toUInteger();
+    virtual real_t toReal();
+    virtual real_t toImaginary();
+    virtual complex_t toComplex();
+    virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    virtual void toMangleBuffer(OutBuffer *buf);
+    virtual Expression *toLvalue(Scope *sc, Expression *e);
+    virtual Expression *modifiableLvalue(Scope *sc, Expression *e);
+    Expression *implicitCastTo(Scope *sc, Type *t);
+    virtual MATCH implicitConvTo(Type *t);
+    virtual Expression *castTo(Scope *sc, Type *t);
+    virtual void checkEscape();
+    void checkScalar();
+    void checkNoBool();
+    Expression *checkIntegral();
+    void checkArithmetic();
+    void checkDeprecated(Scope *sc, Dsymbol *s);
+    virtual Expression *checkToBoolean();
+    Expression *checkToPointer();
+    Expression *addressOf(Scope *sc);
+    Expression *deref();
+    Expression *integralPromotions(Scope *sc);
+
+    Expression *toDelegate(Scope *sc, Type *t);
+    virtual void scanForNestedRef(Scope *sc);
+
+    virtual Expression *optimize(int result);
+    #define WANTflags	1
+    #define WANTvalue	2
+    #define WANTinterpret 4
+
+    virtual Expression *interpret(InterState *istate);
+
+    virtual int isConst();
+    virtual int isBool(int result);
+    virtual int isBit();
+    virtual int checkSideEffect(int flag);
+
+    virtual int inlineCost(InlineCostState *ics);
+    virtual Expression *doInline(InlineDoState *ids);
+    virtual Expression *inlineScan(InlineScanState *iss);
+
+    // For operator overloading
+    virtual int isCommutative();
+    virtual Identifier *opId();
+    virtual Identifier *opId_r();
+
+    // Back end
+    virtual elem *toElem(IRState *irs);
+    virtual dt_t **toDt(dt_t **pdt);
+};
+
+struct IntegerExp : Expression
+{
+    integer_t value;
+
+    IntegerExp(Loc loc, integer_t value, Type *type);
+    IntegerExp(integer_t value);
+    int equals(Object *o);
+    Expression *semantic(Scope *sc);
+    Expression *interpret(InterState *istate);
+    char *toChars();
+    void dump(int indent);
+    integer_t toInteger();
+    real_t toReal();
+    real_t toImaginary();
+    complex_t toComplex();
+    int isConst();
+    int isBool(int result);
+    MATCH implicitConvTo(Type *t);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    void toMangleBuffer(OutBuffer *buf);
+    Expression *toLvalue(Scope *sc, Expression *e);
+    elem *toElem(IRState *irs);
+    dt_t **toDt(dt_t **pdt);
+};
+
+struct RealExp : Expression
+{
+    real_t value;
+
+    RealExp(Loc loc, real_t value, Type *type);
+    int equals(Object *o);
+    Expression *semantic(Scope *sc);
+    Expression *interpret(InterState *istate);
+    char *toChars();
+    integer_t toInteger();
+    uinteger_t toUInteger();
+    real_t toReal();
+    real_t toImaginary();
+    complex_t toComplex();
+    Expression *castTo(Scope *sc, Type *t);
+    int isConst();
+    int isBool(int result);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    void toMangleBuffer(OutBuffer *buf);
+    elem *toElem(IRState *irs);
+    dt_t **toDt(dt_t **pdt);
+};
+
+struct ComplexExp : Expression
+{
+    complex_t value;
+
+    ComplexExp(Loc loc, complex_t value, Type *type);
+    int equals(Object *o);
+    Expression *semantic(Scope *sc);
+    Expression *interpret(InterState *istate);
+    char *toChars();
+    integer_t toInteger();
+    uinteger_t toUInteger();
+    real_t toReal();
+    real_t toImaginary();
+    complex_t toComplex();
+    Expression *castTo(Scope *sc, Type *t);
+    int isConst();
+    int isBool(int result);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    void toMangleBuffer(OutBuffer *buf);
+#ifdef _DH
+    OutBuffer hexp;
+#endif
+    elem *toElem(IRState *irs);
+    dt_t **toDt(dt_t **pdt);
+};
+
+struct IdentifierExp : Expression
+{
+    Identifier *ident;
+    Declaration *var;
+
+    IdentifierExp(Loc loc, Identifier *ident);
+    IdentifierExp(Loc loc, Declaration *var);
+    Expression *semantic(Scope *sc);
+    char *toChars();
+    void dump(int indent);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    Expression *toLvalue(Scope *sc, Expression *e);
+};
+
+struct DollarExp : IdentifierExp
+{
+    DollarExp(Loc loc);
+};
+
+struct DsymbolExp : Expression
+{
+    Dsymbol *s;
+
+    DsymbolExp(Loc loc, Dsymbol *s);
+    Expression *semantic(Scope *sc);
+    char *toChars();
+    void dump(int indent);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    Expression *toLvalue(Scope *sc, Expression *e);
+};
+
+struct ThisExp : Expression
+{
+    Declaration *var;
+
+    ThisExp(Loc loc);
+    Expression *semantic(Scope *sc);
+    int isBool(int result);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    Expression *toLvalue(Scope *sc, Expression *e);
+    void scanForNestedRef(Scope *sc);
+
+    int inlineCost(InlineCostState *ics);
+    Expression *doInline(InlineDoState *ids);
+    //Expression *inlineScan(InlineScanState *iss);
+
+    elem *toElem(IRState *irs);
+};
+
+struct SuperExp : ThisExp
+{
+    SuperExp(Loc loc);
+    Expression *semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    void scanForNestedRef(Scope *sc);
+
+    int inlineCost(InlineCostState *ics);
+    Expression *doInline(InlineDoState *ids);
+    //Expression *inlineScan(InlineScanState *iss);
+};
+
+struct NullExp : Expression
+{
+    unsigned char committed;	// !=0 if type is committed
+
+    NullExp(Loc loc);
+    Expression *semantic(Scope *sc);
+    int isBool(int result);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    void toMangleBuffer(OutBuffer *buf);
+    MATCH implicitConvTo(Type *t);
+    Expression *castTo(Scope *sc, Type *t);
+    Expression *interpret(InterState *istate);
+    elem *toElem(IRState *irs);
+    dt_t **toDt(dt_t **pdt);
+};
+
+struct StringExp : Expression
+{
+    void *string;	// char, wchar, or dchar data
+    size_t len;		// number of chars, wchars, or dchars
+    unsigned char sz;	// 1: char, 2: wchar, 4: dchar
+    unsigned char committed;	// !=0 if type is committed
+    unsigned char postfix;	// 'c', 'w', 'd'
+
+    StringExp(Loc loc, char *s);
+    StringExp(Loc loc, void *s, size_t len);
+    StringExp(Loc loc, void *s, size_t len, unsigned char postfix);
+    //Expression *syntaxCopy();
+    int equals(Object *o);
+    char *toChars();
+    Expression *semantic(Scope *sc);
+    Expression *interpret(InterState *istate);
+    StringExp *toUTF8(Scope *sc);
+    MATCH implicitConvTo(Type *t);
+    Expression *castTo(Scope *sc, Type *t);
+    int compare(Object *obj);
+    int isBool(int result);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    void toMangleBuffer(OutBuffer *buf);
+    elem *toElem(IRState *irs);
+    dt_t **toDt(dt_t **pdt);
+};
+
+// Tuple
+
+struct TupleExp : Expression
+{
+    Expressions *exps;
+
+    TupleExp(Loc loc, Expressions *exps);
+    TupleExp(Loc loc, TupleDeclaration *tup);
+    Expression *syntaxCopy();
+    int equals(Object *o);
+    Expression *semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    void scanForNestedRef(Scope *sc);
+    void checkEscape();
+    int checkSideEffect(int flag);
+    Expression *optimize(int result);
+    Expression *interpret(InterState *istate);
+    Expression *castTo(Scope *sc, Type *t);
+
+    int inlineCost(InlineCostState *ics);
+    Expression *doInline(InlineDoState *ids);
+    Expression *inlineScan(InlineScanState *iss);
+};
+
+struct ArrayLiteralExp : Expression
+{
+    Expressions *elements;
+
+    ArrayLiteralExp(Loc loc, Expressions *elements);
+    ArrayLiteralExp(Loc loc, Expression *e);
+
+    Expression *syntaxCopy();
+    Expression *semantic(Scope *sc);
+    int isBool(int result);
+    elem *toElem(IRState *irs);
+    int checkSideEffect(int flag);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    void toMangleBuffer(OutBuffer *buf);
+    void scanForNestedRef(Scope *sc);
+    Expression *optimize(int result);
+    Expression *interpret(InterState *istate);
+    MATCH implicitConvTo(Type *t);
+    Expression *castTo(Scope *sc, Type *t);
+    dt_t **toDt(dt_t **pdt);
+
+    int inlineCost(InlineCostState *ics);
+    Expression *doInline(InlineDoState *ids);
+    Expression *inlineScan(InlineScanState *iss);
+};
+
+struct AssocArrayLiteralExp : Expression
+{
+    Expressions *keys;
+    Expressions *values;
+
+    AssocArrayLiteralExp(Loc loc, Expressions *keys, Expressions *values);
+
+    Expression *syntaxCopy();
+    Expression *semantic(Scope *sc);
+    int isBool(int result);
+    elem *toElem(IRState *irs);
+    int checkSideEffect(int flag);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    void toMangleBuffer(OutBuffer *buf);
+    void scanForNestedRef(Scope *sc);
+    Expression *optimize(int result);
+    Expression *interpret(InterState *istate);
+    MATCH implicitConvTo(Type *t);
+    Expression *castTo(Scope *sc, Type *t);
+
+    int inlineCost(InlineCostState *ics);
+    Expression *doInline(InlineDoState *ids);
+    Expression *inlineScan(InlineScanState *iss);
+};
+
+struct StructLiteralExp : Expression
+{
+    StructDeclaration *sd;		// which aggregate this is for
+    Expressions *elements;	// parallels sd->fields[] with
+				// NULL entries for fields to skip
+
+    Symbol *sym;		// back end symbol to initialize with literal
+    size_t soffset;		// offset from start of s
+    int fillHoles;		// fill alignment 'holes' with zero
+
+    StructLiteralExp(Loc loc, StructDeclaration *sd, Expressions *elements);
+
+    Expression *syntaxCopy();
+    Expression *semantic(Scope *sc);
+    Expression *getField(Type *type, unsigned offset);
+    int getFieldIndex(Type *type, unsigned offset);
+    elem *toElem(IRState *irs);
+    int checkSideEffect(int flag);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    void toMangleBuffer(OutBuffer *buf);
+    void scanForNestedRef(Scope *sc);
+    Expression *optimize(int result);
+    Expression *interpret(InterState *istate);
+    dt_t **toDt(dt_t **pdt);
+    Expression *toLvalue(Scope *sc, Expression *e);
+
+    int inlineCost(InlineCostState *ics);
+    Expression *doInline(InlineDoState *ids);
+    Expression *inlineScan(InlineScanState *iss);
+};
+
+struct TypeDotIdExp : Expression
+{
+    Identifier *ident;
+
+    TypeDotIdExp(Loc loc, Type *type, Identifier *ident);
+    Expression *syntaxCopy();
+    Expression *semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    elem *toElem(IRState *irs);
+};
+
+struct TypeExp : Expression
+{
+    TypeExp(Loc loc, Type *type);
+    Expression *semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    Expression *optimize(int result);
+    elem *toElem(IRState *irs);
+};
+
+struct ScopeExp : Expression
+{
+    ScopeDsymbol *sds;
+
+    ScopeExp(Loc loc, ScopeDsymbol *sds);
+    Expression *syntaxCopy();
+    Expression *semantic(Scope *sc);
+    elem *toElem(IRState *irs);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+struct TemplateExp : Expression
+{
+    TemplateDeclaration *td;
+
+    TemplateExp(Loc loc, TemplateDeclaration *td);
+    void rvalue();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+struct NewExp : Expression
+{
+    /* thisexp.new(newargs) newtype(arguments)
+     */
+    Expression *thisexp;	// if !NULL, 'this' for class being allocated
+    Expressions *newargs;	// Array of Expression's to call new operator
+    Type *newtype;
+    Expressions *arguments;	// Array of Expression's
+
+    CtorDeclaration *member;	// constructor function
+    NewDeclaration *allocator;	// allocator function
+    int onstack;		// allocate on stack
+
+    NewExp(Loc loc, Expression *thisexp, Expressions *newargs,
+	Type *newtype, Expressions *arguments);
+    Expression *syntaxCopy();
+    Expression *semantic(Scope *sc);
+    elem *toElem(IRState *irs);
+    int checkSideEffect(int flag);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    void scanForNestedRef(Scope *sc);
+
+    //int inlineCost(InlineCostState *ics);
+    Expression *doInline(InlineDoState *ids);
+    //Expression *inlineScan(InlineScanState *iss);
+};
+
+struct NewAnonClassExp : Expression
+{
+    /* thisexp.new(newargs) class baseclasses { } (arguments)
+     */
+    Expression *thisexp;	// if !NULL, 'this' for class being allocated
+    Expressions *newargs;	// Array of Expression's to call new operator
+    ClassDeclaration *cd;	// class being instantiated
+    Expressions *arguments;	// Array of Expression's to call class constructor
+
+    NewAnonClassExp(Loc loc, Expression *thisexp, Expressions *newargs,
+	ClassDeclaration *cd, Expressions *arguments);
+    Expression *syntaxCopy();
+    Expression *semantic(Scope *sc);
+    int checkSideEffect(int flag);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+// Offset from symbol
+
+struct SymOffExp : Expression
+{
+    Declaration *var;
+    unsigned offset;
+
+    SymOffExp(Loc loc, Declaration *var, unsigned offset);
+    Expression *semantic(Scope *sc);
+    void checkEscape();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    int isConst();
+    int isBool(int result);
+    Expression *doInline(InlineDoState *ids);
+    MATCH implicitConvTo(Type *t);
+    Expression *castTo(Scope *sc, Type *t);
+    void scanForNestedRef(Scope *sc);
+
+    elem *toElem(IRState *irs);
+    dt_t **toDt(dt_t **pdt);
+};
+
+// Variable
+
+struct VarExp : Expression
+{
+    Declaration *var;
+
+    VarExp(Loc loc, Declaration *var);
+    int equals(Object *o);
+    Expression *semantic(Scope *sc);
+    Expression *optimize(int result);
+    Expression *interpret(InterState *istate);
+    void dump(int indent);
+    char *toChars();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    void checkEscape();
+    Expression *toLvalue(Scope *sc, Expression *e);
+    Expression *modifiableLvalue(Scope *sc, Expression *e);
+    elem *toElem(IRState *irs);
+    dt_t **toDt(dt_t **pdt);
+    void scanForNestedRef(Scope *sc);
+
+    int inlineCost(InlineCostState *ics);
+    Expression *doInline(InlineDoState *ids);
+    //Expression *inlineScan(InlineScanState *iss);
+};
+
+// Function/Delegate literal
+
+struct FuncExp : Expression
+{
+    FuncLiteralDeclaration *fd;
+
+    FuncExp(Loc loc, FuncLiteralDeclaration *fd);
+    Expression *syntaxCopy();
+    Expression *semantic(Scope *sc);
+    void scanForNestedRef(Scope *sc);
+    char *toChars();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    elem *toElem(IRState *irs);
+
+    int inlineCost(InlineCostState *ics);
+    //Expression *doInline(InlineDoState *ids);
+    //Expression *inlineScan(InlineScanState *iss);
+};
+
+// Declaration of a symbol
+
+struct DeclarationExp : Expression
+{
+    Dsymbol *declaration;
+
+    DeclarationExp(Loc loc, Dsymbol *declaration);
+    Expression *syntaxCopy();
+    Expression *semantic(Scope *sc);
+    Expression *interpret(InterState *istate);
+    int checkSideEffect(int flag);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    elem *toElem(IRState *irs);
+    void scanForNestedRef(Scope *sc);
+
+    int inlineCost(InlineCostState *ics);
+    Expression *doInline(InlineDoState *ids);
+    Expression *inlineScan(InlineScanState *iss);
+};
+
+struct TypeidExp : Expression
+{
+    Type *typeidType;
+
+    TypeidExp(Loc loc, Type *typeidType);
+    Expression *syntaxCopy();
+    Expression *semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+struct HaltExp : Expression
+{
+    HaltExp(Loc loc);
+    Expression *semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    int checkSideEffect(int flag);
+
+    elem *toElem(IRState *irs);
+};
+
+struct IftypeExp : Expression
+{
+    /* is(targ id tok tspec)
+     * is(targ id == tok2)
+     */
+    Type *targ;
+    Identifier *id;	// can be NULL
+    enum TOK tok;	// ':' or '=='
+    Type *tspec;	// can be NULL
+    enum TOK tok2;	// 'struct', 'union', 'typedef', etc.
+
+    IftypeExp(Loc loc, Type *targ, Identifier *id, enum TOK tok, Type *tspec, enum TOK tok2);
+    Expression *syntaxCopy();
+    Expression *semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+/****************************************************************/
+
+struct UnaExp : Expression
+{
+    Expression *e1;
+
+    UnaExp(Loc loc, enum TOK op, int size, Expression *e1);
+    Expression *syntaxCopy();
+    Expression *semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    Expression *optimize(int result);
+    void dump(int indent);
+    void scanForNestedRef(Scope *sc);
+    Expression *interpretCommon(InterState *istate, Expression *(*fp)(Type *, Expression *));
+
+    int inlineCost(InlineCostState *ics);
+    Expression *doInline(InlineDoState *ids);
+    Expression *inlineScan(InlineScanState *iss);
+
+    Expression *op_overload(Scope *sc);	// doesn't need to be virtual
+};
+
+struct BinExp : Expression
+{
+    Expression *e1;
+    Expression *e2;
+
+    BinExp(Loc loc, enum TOK op, int size, Expression *e1, Expression *e2);
+    Expression *syntaxCopy();
+    Expression *semantic(Scope *sc);
+    Expression *semanticp(Scope *sc);
+    Expression *commonSemanticAssign(Scope *sc);
+    Expression *commonSemanticAssignIntegral(Scope *sc);
+    int checkSideEffect(int flag);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    Expression *scaleFactor(Scope *sc);
+    Expression *typeCombine(Scope *sc);
+    Expression *optimize(int result);
+    int isunsigned();
+    void incompatibleTypes();
+    void dump(int indent);
+    void scanForNestedRef(Scope *sc);
+    Expression *interpretCommon(InterState *istate, Expression *(*fp)(Type *, Expression *, Expression *));
+    Expression *interpretCommon2(InterState *istate, Expression *(*fp)(TOK, Type *, Expression *, Expression *));
+    Expression *interpretAssignCommon(InterState *istate, Expression *(*fp)(Type *, Expression *, Expression *), int post = 0);
+
+    int inlineCost(InlineCostState *ics);
+    Expression *doInline(InlineDoState *ids);
+    Expression *inlineScan(InlineScanState *iss);
+
+    Expression *op_overload(Scope *sc);
+
+    elem *toElemBin(IRState *irs, int op);
+};
+
+struct BinAssignExp : BinExp
+{
+    BinAssignExp(Loc loc, enum TOK op, int size, Expression *e1, Expression *e2);
+    int checkSideEffect(int flag);
+};
+
+/****************************************************************/
+
+struct CompileExp : UnaExp
+{
+    CompileExp(Loc loc, Expression *e);
+    Expression *semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+struct FileExp : UnaExp
+{
+    FileExp(Loc loc, Expression *e);
+    Expression *semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+struct AssertExp : UnaExp
+{
+    Expression *msg;
+
+    AssertExp(Loc loc, Expression *e, Expression *msg = NULL);
+    Expression *syntaxCopy();
+    Expression *semantic(Scope *sc);
+    Expression *interpret(InterState *istate);
+    int checkSideEffect(int flag);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    int inlineCost(InlineCostState *ics);
+    Expression *doInline(InlineDoState *ids);
+    Expression *inlineScan(InlineScanState *iss);
+
+    elem *toElem(IRState *irs);
+};
+
+struct DotIdExp : UnaExp
+{
+    Identifier *ident;
+
+    DotIdExp(Loc loc, Expression *e, Identifier *ident);
+    Expression *semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    void dump(int i);
+};
+
+struct DotTemplateExp : UnaExp
+{
+    TemplateDeclaration *td;
+
+    DotTemplateExp(Loc loc, Expression *e, TemplateDeclaration *td);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+struct DotVarExp : UnaExp
+{
+    Declaration *var;
+
+    DotVarExp(Loc loc, Expression *e, Declaration *var);
+    Expression *semantic(Scope *sc);
+    Expression *toLvalue(Scope *sc, Expression *e);
+    Expression *modifiableLvalue(Scope *sc, Expression *e);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    void dump(int indent);
+    elem *toElem(IRState *irs);
+};
+
+struct DotTemplateInstanceExp : UnaExp
+{
+    TemplateInstance *ti;
+
+    DotTemplateInstanceExp(Loc loc, Expression *e, TemplateInstance *ti);
+    Expression *syntaxCopy();
+    Expression *semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    void dump(int indent);
+};
+
+struct DelegateExp : UnaExp
+{
+    FuncDeclaration *func;
+
+    DelegateExp(Loc loc, Expression *e, FuncDeclaration *func);
+    Expression *semantic(Scope *sc);
+    MATCH implicitConvTo(Type *t);
+    Expression *castTo(Scope *sc, Type *t);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    void dump(int indent);
+
+    int inlineCost(InlineCostState *ics);
+    elem *toElem(IRState *irs);
+};
+
+struct DotTypeExp : UnaExp
+{
+    Dsymbol *sym;		// symbol that represents a type
+
+    DotTypeExp(Loc loc, Expression *e, Dsymbol *sym);
+    Expression *semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    elem *toElem(IRState *irs);
+};
+
+struct CallExp : UnaExp
+{
+    Expressions *arguments;	// function arguments
+
+    CallExp(Loc loc, Expression *e, Expressions *exps);
+    CallExp(Loc loc, Expression *e);
+    CallExp(Loc loc, Expression *e, Expression *earg1);
+    CallExp(Loc loc, Expression *e, Expression *earg1, Expression *earg2);
+
+    Expression *syntaxCopy();
+    Expression *semantic(Scope *sc);
+    Expression *optimize(int result);
+    Expression *interpret(InterState *istate);
+    int checkSideEffect(int flag);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    void dump(int indent);
+    elem *toElem(IRState *irs);
+    void scanForNestedRef(Scope *sc);
+    Expression *toLvalue(Scope *sc, Expression *e);
+
+    int inlineCost(InlineCostState *ics);
+    Expression *doInline(InlineDoState *ids);
+    Expression *inlineScan(InlineScanState *iss);
+};
+
+struct AddrExp : UnaExp
+{
+    AddrExp(Loc loc, Expression *e);
+    Expression *semantic(Scope *sc);
+    elem *toElem(IRState *irs);
+    MATCH implicitConvTo(Type *t);
+    Expression *castTo(Scope *sc, Type *t);
+    Expression *optimize(int result);
+};
+
+struct PtrExp : UnaExp
+{
+    PtrExp(Loc loc, Expression *e);
+    PtrExp(Loc loc, Expression *e, Type *t);
+    Expression *semantic(Scope *sc);
+    Expression *toLvalue(Scope *sc, Expression *e);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    elem *toElem(IRState *irs);
+    Expression *optimize(int result);
+    Expression *interpret(InterState *istate);
+};
+
+struct NegExp : UnaExp
+{
+    NegExp(Loc loc, Expression *e);
+    Expression *semantic(Scope *sc);
+    Expression *optimize(int result);
+    Expression *interpret(InterState *istate);
+
+    // For operator overloading
+    Identifier *opId();
+
+    elem *toElem(IRState *irs);
+};
+
+struct UAddExp : UnaExp
+{
+    UAddExp(Loc loc, Expression *e);
+    Expression *semantic(Scope *sc);
+
+    // For operator overloading
+    Identifier *opId();
+};
+
+struct ComExp : UnaExp
+{
+    ComExp(Loc loc, Expression *e);
+    Expression *semantic(Scope *sc);
+    Expression *optimize(int result);
+    Expression *interpret(InterState *istate);
+
+    // For operator overloading
+    Identifier *opId();
+
+    elem *toElem(IRState *irs);
+};
+
+struct NotExp : UnaExp
+{
+    NotExp(Loc loc, Expression *e);
+    Expression *semantic(Scope *sc);
+    Expression *optimize(int result);
+    Expression *interpret(InterState *istate);
+    int isBit();
+    elem *toElem(IRState *irs);
+};
+
+struct BoolExp : UnaExp
+{
+    BoolExp(Loc loc, Expression *e, Type *type);
+    Expression *semantic(Scope *sc);
+    Expression *optimize(int result);
+    Expression *interpret(InterState *istate);
+    int isBit();
+    elem *toElem(IRState *irs);
+};
+
+struct DeleteExp : UnaExp
+{
+    DeleteExp(Loc loc, Expression *e);
+    Expression *semantic(Scope *sc);
+    Expression *checkToBoolean();
+    int checkSideEffect(int flag);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    elem *toElem(IRState *irs);
+};
+
+struct CastExp : UnaExp
+{
+    // Possible to cast to one type while painting to another type
+    Type *to;			// type to cast to
+
+    CastExp(Loc loc, Expression *e, Type *t);
+    Expression *syntaxCopy();
+    Expression *semantic(Scope *sc);
+    Expression *optimize(int result);
+    Expression *interpret(InterState *istate);
+    int checkSideEffect(int flag);
+    void checkEscape();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    elem *toElem(IRState *irs);
+
+    // For operator overloading
+    Identifier *opId();
+};
+
+
+struct SliceExp : UnaExp
+{
+    Expression *upr;		// NULL if implicit 0
+    Expression *lwr;		// NULL if implicit [length - 1]
+    VarDeclaration *lengthVar;
+
+    SliceExp(Loc loc, Expression *e1, Expression *lwr, Expression *upr);
+    Expression *syntaxCopy();
+    Expression *semantic(Scope *sc);
+    void checkEscape();
+    Expression *toLvalue(Scope *sc, Expression *e);
+    Expression *modifiableLvalue(Scope *sc, Expression *e);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    Expression *optimize(int result);
+    Expression *interpret(InterState *istate);
+    void dump(int indent);
+    elem *toElem(IRState *irs);
+    void scanForNestedRef(Scope *sc);
+
+    int inlineCost(InlineCostState *ics);
+    Expression *doInline(InlineDoState *ids);
+    Expression *inlineScan(InlineScanState *iss);
+};
+
+struct ArrayLengthExp : UnaExp
+{
+    ArrayLengthExp(Loc loc, Expression *e1);
+    Expression *semantic(Scope *sc);
+    Expression *optimize(int result);
+    Expression *interpret(InterState *istate);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    elem *toElem(IRState *irs);
+};
+
+// e1[a0,a1,a2,a3,...]
+
+struct ArrayExp : UnaExp
+{
+    Expressions *arguments;		// Array of Expression's
+
+    ArrayExp(Loc loc, Expression *e1, Expressions *arguments);
+    Expression *syntaxCopy();
+    Expression *semantic(Scope *sc);
+    Expression *toLvalue(Scope *sc, Expression *e);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    void scanForNestedRef(Scope *sc);
+
+    // For operator overloading
+    Identifier *opId();
+
+    int inlineCost(InlineCostState *ics);
+    Expression *doInline(InlineDoState *ids);
+    Expression *inlineScan(InlineScanState *iss);
+};
+
+/****************************************************************/
+
+struct DotExp : BinExp
+{
+    DotExp(Loc loc, Expression *e1, Expression *e2);
+    Expression *semantic(Scope *sc);
+};
+
+struct CommaExp : BinExp
+{
+    CommaExp(Loc loc, Expression *e1, Expression *e2);
+    Expression *semantic(Scope *sc);
+    void checkEscape();
+    Expression *toLvalue(Scope *sc, Expression *e);
+    Expression *modifiableLvalue(Scope *sc, Expression *e);
+    int isBool(int result);
+    int checkSideEffect(int flag);
+    Expression *optimize(int result);
+    Expression *interpret(InterState *istate);
+    elem *toElem(IRState *irs);
+};
+
+struct IndexExp : BinExp
+{
+    VarDeclaration *lengthVar;
+    int modifiable;
+
+    IndexExp(Loc loc, Expression *e1, Expression *e2);
+    Expression *semantic(Scope *sc);
+    Expression *toLvalue(Scope *sc, Expression *e);
+    Expression *modifiableLvalue(Scope *sc, Expression *e);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    Expression *optimize(int result);
+    Expression *interpret(InterState *istate);
+    Expression *doInline(InlineDoState *ids);
+    void scanForNestedRef(Scope *sc);
+
+    elem *toElem(IRState *irs);
+};
+
+/* For both i++ and i--
+ */
+struct PostExp : BinExp
+{
+    PostExp(enum TOK op, Loc loc, Expression *e);
+    Expression *semantic(Scope *sc);
+    Expression *interpret(InterState *istate);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    Identifier *opId();    // For operator overloading
+    elem *toElem(IRState *irs);
+};
+
+struct AssignExp : BinExp
+{   int ismemset;	// !=0 if setting the contents of an array
+
+    AssignExp(Loc loc, Expression *e1, Expression *e2);
+    Expression *semantic(Scope *sc);
+    Expression *checkToBoolean();
+    Expression *interpret(InterState *istate);
+    Identifier *opId();    // For operator overloading
+    elem *toElem(IRState *irs);
+};
+
+#define ASSIGNEXP(op)	\
+struct op##AssignExp : BinExp					\
+{								\
+    op##AssignExp(Loc loc, Expression *e1, Expression *e2);	\
+    Expression *semantic(Scope *sc);				\
+    Expression *interpret(InterState *istate);			\
+								\
+    Identifier *opId();    /* For operator overloading */	\
+								\
+    elem *toElem(IRState *irs);					\
+};
+
+ASSIGNEXP(Add)
+ASSIGNEXP(Min)
+ASSIGNEXP(Cat)
+ASSIGNEXP(Mul)
+ASSIGNEXP(Div)
+ASSIGNEXP(Mod)
+ASSIGNEXP(Shl)
+ASSIGNEXP(Shr)
+ASSIGNEXP(Ushr)
+ASSIGNEXP(And)
+ASSIGNEXP(Or)
+ASSIGNEXP(Xor)
+
+#undef ASSIGNEXP
+
+struct AddExp : BinExp
+{
+    AddExp(Loc loc, Expression *e1, Expression *e2);
+    Expression *semantic(Scope *sc);
+    Expression *optimize(int result);
+    Expression *interpret(InterState *istate);
+
+    // For operator overloading
+    int isCommutative();
+    Identifier *opId();
+    Identifier *opId_r();
+
+    elem *toElem(IRState *irs);
+};
+
+struct MinExp : BinExp
+{
+    MinExp(Loc loc, Expression *e1, Expression *e2);
+    Expression *semantic(Scope *sc);
+    Expression *optimize(int result);
+    Expression *interpret(InterState *istate);
+
+    // For operator overloading
+    Identifier *opId();
+    Identifier *opId_r();
+
+    elem *toElem(IRState *irs);
+};
+
+struct CatExp : BinExp
+{
+    CatExp(Loc loc, Expression *e1, Expression *e2);
+    Expression *semantic(Scope *sc);
+    Expression *optimize(int result);
+    Expression *interpret(InterState *istate);
+
+    // For operator overloading
+    Identifier *opId();
+    Identifier *opId_r();
+
+    elem *toElem(IRState *irs);
+};
+
+struct MulExp : BinExp
+{
+    MulExp(Loc loc, Expression *e1, Expression *e2);
+    Expression *semantic(Scope *sc);
+    Expression *optimize(int result);
+    Expression *interpret(InterState *istate);
+
+    // For operator overloading
+    int isCommutative();
+    Identifier *opId();
+    Identifier *opId_r();
+
+    elem *toElem(IRState *irs);
+};
+
+struct DivExp : BinExp
+{
+    DivExp(Loc loc, Expression *e1, Expression *e2);
+    Expression *semantic(Scope *sc);
+    Expression *optimize(int result);
+    Expression *interpret(InterState *istate);
+
+    // For operator overloading
+    Identifier *opId();
+    Identifier *opId_r();
+
+    elem *toElem(IRState *irs);
+};
+
+struct ModExp : BinExp
+{
+    ModExp(Loc loc, Expression *e1, Expression *e2);
+    Expression *semantic(Scope *sc);
+    Expression *optimize(int result);
+    Expression *interpret(InterState *istate);
+
+    // For operator overloading
+    Identifier *opId();
+    Identifier *opId_r();
+
+    elem *toElem(IRState *irs);
+};
+
+struct ShlExp : BinExp
+{
+    ShlExp(Loc loc, Expression *e1, Expression *e2);
+    Expression *semantic(Scope *sc);
+    Expression *optimize(int result);
+    Expression *interpret(InterState *istate);
+
+    // For operator overloading
+    Identifier *opId();
+    Identifier *opId_r();
+
+    elem *toElem(IRState *irs);
+};
+
+struct ShrExp : BinExp
+{
+    ShrExp(Loc loc, Expression *e1, Expression *e2);
+    Expression *semantic(Scope *sc);
+    Expression *optimize(int result);
+    Expression *interpret(InterState *istate);
+
+    // For operator overloading
+    Identifier *opId();
+    Identifier *opId_r();
+
+    elem *toElem(IRState *irs);
+};
+
+struct UshrExp : BinExp
+{
+    UshrExp(Loc loc, Expression *e1, Expression *e2);
+    Expression *semantic(Scope *sc);
+    Expression *optimize(int result);
+    Expression *interpret(InterState *istate);
+
+    // For operator overloading
+    Identifier *opId();
+    Identifier *opId_r();
+
+    elem *toElem(IRState *irs);
+};
+
+struct AndExp : BinExp
+{
+    AndExp(Loc loc, Expression *e1, Expression *e2);
+    Expression *semantic(Scope *sc);
+    Expression *optimize(int result);
+    Expression *interpret(InterState *istate);
+
+    // For operator overloading
+    int isCommutative();
+    Identifier *opId();
+    Identifier *opId_r();
+
+    elem *toElem(IRState *irs);
+};
+
+struct OrExp : BinExp
+{
+    OrExp(Loc loc, Expression *e1, Expression *e2);
+    Expression *semantic(Scope *sc);
+    Expression *optimize(int result);
+    Expression *interpret(InterState *istate);
+
+    // For operator overloading
+    int isCommutative();
+    Identifier *opId();
+    Identifier *opId_r();
+
+    elem *toElem(IRState *irs);
+};
+
+struct XorExp : BinExp
+{
+    XorExp(Loc loc, Expression *e1, Expression *e2);
+    Expression *semantic(Scope *sc);
+    Expression *optimize(int result);
+    Expression *interpret(InterState *istate);
+
+    // For operator overloading
+    int isCommutative();
+    Identifier *opId();
+    Identifier *opId_r();
+
+    elem *toElem(IRState *irs);
+};
+
+struct OrOrExp : BinExp
+{
+    OrOrExp(Loc loc, Expression *e1, Expression *e2);
+    Expression *semantic(Scope *sc);
+    Expression *checkToBoolean();
+    int isBit();
+    Expression *optimize(int result);
+    Expression *interpret(InterState *istate);
+    int checkSideEffect(int flag);
+    elem *toElem(IRState *irs);
+};
+
+struct AndAndExp : BinExp
+{
+    AndAndExp(Loc loc, Expression *e1, Expression *e2);
+    Expression *semantic(Scope *sc);
+    Expression *checkToBoolean();
+    int isBit();
+    Expression *optimize(int result);
+    Expression *interpret(InterState *istate);
+    int checkSideEffect(int flag);
+    elem *toElem(IRState *irs);
+};
+
+struct CmpExp : BinExp
+{
+    CmpExp(enum TOK op, Loc loc, Expression *e1, Expression *e2);
+    Expression *semantic(Scope *sc);
+    Expression *optimize(int result);
+    Expression *interpret(InterState *istate);
+    int isBit();
+
+    // For operator overloading
+    int isCommutative();
+    Identifier *opId();
+
+    elem *toElem(IRState *irs);
+};
+
+struct InExp : BinExp
+{
+    InExp(Loc loc, Expression *e1, Expression *e2);
+    Expression *semantic(Scope *sc);
+    int isBit();
+
+    // For operator overloading
+    Identifier *opId();
+    Identifier *opId_r();
+
+    elem *toElem(IRState *irs);
+};
+
+struct RemoveExp : BinExp
+{
+    RemoveExp(Loc loc, Expression *e1, Expression *e2);
+    elem *toElem(IRState *irs);
+};
+
+// == and !=
+
+struct EqualExp : BinExp
+{
+    EqualExp(enum TOK op, Loc loc, Expression *e1, Expression *e2);
+    Expression *semantic(Scope *sc);
+    Expression *optimize(int result);
+    Expression *interpret(InterState *istate);
+    int isBit();
+
+    // For operator overloading
+    int isCommutative();
+    Identifier *opId();
+
+    elem *toElem(IRState *irs);
+};
+
+// === and !===
+
+struct IdentityExp : BinExp
+{
+    IdentityExp(enum TOK op, Loc loc, Expression *e1, Expression *e2);
+    Expression *semantic(Scope *sc);
+    int isBit();
+    Expression *optimize(int result);
+    Expression *interpret(InterState *istate);
+    elem *toElem(IRState *irs);
+};
+
+/****************************************************************/
+
+struct CondExp : BinExp
+{
+    Expression *econd;
+
+    CondExp(Loc loc, Expression *econd, Expression *e1, Expression *e2);
+    Expression *syntaxCopy();
+    Expression *semantic(Scope *sc);
+    Expression *optimize(int result);
+    Expression *interpret(InterState *istate);
+    void checkEscape();
+    Expression *toLvalue(Scope *sc, Expression *e);
+    Expression *modifiableLvalue(Scope *sc, Expression *e);
+    Expression *checkToBoolean();
+    int checkSideEffect(int flag);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    MATCH implicitConvTo(Type *t);
+    Expression *castTo(Scope *sc, Type *t);
+    void scanForNestedRef(Scope *sc);
+
+    int inlineCost(InlineCostState *ics);
+    Expression *doInline(InlineDoState *ids);
+    Expression *inlineScan(InlineScanState *iss);
+
+    elem *toElem(IRState *irs);
+};
+
+
+/****************************************************************/
+
+/* Special values used by the interpreter
+ */
+#define EXP_CANT_INTERPRET	((Expression *)1)
+#define EXP_CONTINUE_INTERPRET	((Expression *)2)
+#define EXP_BREAK_INTERPRET	((Expression *)3)
+#define EXP_GOTO_INTERPRET	((Expression *)4)
+#define EXP_VOID_INTERPRET	((Expression *)5)
+
+Expression *expType(Type *type, Expression *e);
+
+Expression *Neg(Type *type, Expression *e1);
+Expression *Com(Type *type, Expression *e1);
+Expression *Not(Type *type, Expression *e1);
+Expression *Bool(Type *type, Expression *e1);
+Expression *Cast(Type *type, Type *to, Expression *e1);
+Expression *ArrayLength(Type *type, Expression *e1);
+Expression *Ptr(Type *type, Expression *e1);
+
+Expression *Add(Type *type, Expression *e1, Expression *e2);
+Expression *Min(Type *type, Expression *e1, Expression *e2);
+Expression *Mul(Type *type, Expression *e1, Expression *e2);
+Expression *Div(Type *type, Expression *e1, Expression *e2);
+Expression *Mod(Type *type, Expression *e1, Expression *e2);
+Expression *Shl(Type *type, Expression *e1, Expression *e2);
+Expression *Shr(Type *type, Expression *e1, Expression *e2);
+Expression *Ushr(Type *type, Expression *e1, Expression *e2);
+Expression *And(Type *type, Expression *e1, Expression *e2);
+Expression *Or(Type *type, Expression *e1, Expression *e2);
+Expression *Xor(Type *type, Expression *e1, Expression *e2);
+Expression *Index(Type *type, Expression *e1, Expression *e2);
+Expression *Cat(Type *type, Expression *e1, Expression *e2);
+
+Expression *Equal(enum TOK op, Type *type, Expression *e1, Expression *e2);
+Expression *Cmp(enum TOK op, Type *type, Expression *e1, Expression *e2);
+Expression *Identity(enum TOK op, Type *type, Expression *e1, Expression *e2);
+
+Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr);
+
+#endif /* DMD_EXPRESSION_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/func.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,2659 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "mars.h"
+#include "init.h"
+#include "declaration.h"
+#include "attrib.h"
+#include "expression.h"
+#include "scope.h"
+#include "mtype.h"
+#include "aggregate.h"
+#include "identifier.h"
+#include "id.h"
+#include "module.h"
+#include "statement.h"
+#include "template.h"
+#include "hdrgen.h"
+
+#ifdef IN_GCC
+#include "d-dmd-gcc.h"
+#endif
+
+/********************************* FuncDeclaration ****************************/
+
+FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, enum STC storage_class, Type *type)
+    : Declaration(id)
+{
+    this->storage_class = storage_class;
+    this->type = type;
+    this->loc = loc;
+    this->endloc = endloc;
+    fthrows = NULL;
+    frequire = NULL;
+    outId = NULL;
+    vresult = NULL;
+    returnLabel = NULL;
+    fensure = NULL;
+    fbody = NULL;
+    localsymtab = NULL;
+    vthis = NULL;
+    v_arguments = NULL;
+#if IN_GCC
+    v_argptr = NULL;
+#endif
+    parameters = NULL;
+    labtab = NULL;
+    overnext = NULL;
+    vtblIndex = -1;
+    hasReturnExp = 0;
+    naked = 0;
+    inlineStatus = ILSuninitialized;
+    inlineNest = 0;
+    inlineAsm = 0;
+    cantInterpret = 0;
+    semanticRun = 0;
+    nestedFrameRef = 0;
+    fes = NULL;
+    introducing = 0;
+    tintro = NULL;
+    inferRetType = (type && type->nextOf() == NULL);
+    scope = NULL;
+    hasReturnExp = 0;
+    nrvo_can = 1;
+    nrvo_var = NULL;
+    shidden = NULL;
+}
+
+Dsymbol *FuncDeclaration::syntaxCopy(Dsymbol *s)
+{
+    FuncDeclaration *f;
+
+    //printf("FuncDeclaration::syntaxCopy('%s')\n", toChars());
+    if (s)
+	f = (FuncDeclaration *)s;
+    else
+	f = new FuncDeclaration(loc, endloc, ident, (enum STC) storage_class, type->syntaxCopy());
+    f->outId = outId;
+    f->frequire = frequire ? frequire->syntaxCopy() : NULL;
+    f->fensure  = fensure  ? fensure->syntaxCopy()  : NULL;
+    f->fbody    = fbody    ? fbody->syntaxCopy()    : NULL;
+    assert(!fthrows); // deprecated
+    return f;
+}
+
+
+// Do the semantic analysis on the external interface to the function.
+
+void FuncDeclaration::semantic(Scope *sc)
+{   TypeFunction *f;
+    StructDeclaration *sd;
+    ClassDeclaration *cd;
+    InterfaceDeclaration *id;
+
+#if 0
+    printf("FuncDeclaration::semantic(sc = %p, this = %p, '%s', linkage = %d)\n", sc, this, toPrettyChars(), sc->linkage);
+    if (isFuncLiteralDeclaration())
+	printf("\tFuncLiteralDeclaration()\n");
+    printf("sc->parent = %s\n", sc->parent->toChars());
+    printf("type: %s\n", type->toChars());
+#endif
+
+    if (type->nextOf())
+	type = type->semantic(loc, sc);
+    //type->print();
+    if (type->ty != Tfunction)
+    {
+	error("%s must be a function", toChars());
+	return;
+    }
+    f = (TypeFunction *)(type);
+    size_t nparams = Argument::dim(f->parameters);
+
+    linkage = sc->linkage;
+//    if (!parent)
+    {
+	//parent = sc->scopesym;
+	parent = sc->parent;
+    }
+    protection = sc->protection;
+    storage_class |= sc->stc;
+    //printf("function storage_class = x%x\n", storage_class);
+    Dsymbol *parent = toParent();
+
+    if (isConst() || isAuto() || isScope())
+	error("functions cannot be const or auto");
+
+    if (isAbstract() && !isVirtual())
+	error("non-virtual functions cannot be abstract");
+#if 0
+    if (isAbstract() && fbody)
+	error("abstract functions cannot have bodies");
+#endif
+
+#if 0
+    if (isStaticConstructor() || isStaticDestructor())
+    {
+	if (!isStatic() || type->nextOf()->ty != Tvoid)
+	    error("static constructors / destructors must be static void");
+	if (f->arguments && f->arguments->dim)
+	    error("static constructors / destructors must have empty parameter list");
+	// BUG: check for invalid storage classes
+    }
+#endif
+
+#ifdef IN_GCC
+    AggregateDeclaration *ad;
+
+    ad = parent->isAggregateDeclaration();
+    if (ad)
+	ad->methods.push(this);
+#endif
+    sd = parent->isStructDeclaration();
+    if (sd)
+    {
+	// Verify no constructors, destructors, etc.
+	if (isCtorDeclaration() ||
+	    isDtorDeclaration()
+	    //|| isInvariantDeclaration()
+	    //|| isUnitTestDeclaration()
+	   )
+	{
+	    error("special member functions not allowed for %ss", sd->kind());
+	}
+
+#if 0
+	if (!sd->inv)
+	    sd->inv = isInvariantDeclaration();
+
+	if (!sd->aggNew)
+	    sd->aggNew = isNewDeclaration();
+
+	if (isDelete())
+	{
+	    if (sd->aggDelete)
+		error("multiple delete's for struct %s", sd->toChars());
+	    sd->aggDelete = (DeleteDeclaration *)(this);
+	}
+#endif
+    }
+
+    id = parent->isInterfaceDeclaration();
+    if (id)
+    {
+	storage_class |= STCabstract;
+
+	if (isCtorDeclaration() ||
+	    isDtorDeclaration() ||
+	    isInvariantDeclaration() ||
+	    isUnitTestDeclaration() || isNewDeclaration() || isDelete())
+	    error("special function not allowed in interface %s", id->toChars());
+	if (fbody)
+	    error("function body is not abstract in interface %s", id->toChars());
+    }
+
+    cd = parent->isClassDeclaration();
+    if (cd)
+    {	int vi;
+	CtorDeclaration *ctor;
+	DtorDeclaration *dtor;
+	InvariantDeclaration *inv;
+
+	if (isCtorDeclaration())
+	{
+//	    ctor = (CtorDeclaration *)this;
+//	    if (!cd->ctor)
+//		cd->ctor = ctor;
+	    return;
+	}
+
+#if 0
+	dtor = isDtorDeclaration();
+	if (dtor)
+	{
+	    if (cd->dtor)
+		error("multiple destructors for class %s", cd->toChars());
+	    cd->dtor = dtor;
+	}
+
+	inv = isInvariantDeclaration();
+	if (inv)
+	{
+	    cd->inv = inv;
+	}
+
+	if (isNewDeclaration())
+	{
+	    if (!cd->aggNew)
+		cd->aggNew = (NewDeclaration *)(this);
+	}
+
+	if (isDelete())
+	{
+	    if (cd->aggDelete)
+		error("multiple delete's for class %s", cd->toChars());
+	    cd->aggDelete = (DeleteDeclaration *)(this);
+	}
+#endif
+
+	if (storage_class & STCabstract)
+	    cd->isabstract = 1;
+
+	// if static function, do not put in vtbl[]
+	if (!isVirtual())
+	{
+	    //printf("\tnot virtual\n");
+	    return;
+	}
+
+	// Find index of existing function in vtbl[] to override
+	if (cd->baseClass)
+	{
+	    for (vi = 0; vi < cd->baseClass->vtbl.dim; vi++)
+	    {
+		FuncDeclaration *fdv = ((Dsymbol *)cd->vtbl.data[vi])->isFuncDeclaration();
+
+		// BUG: should give error if argument types match,
+		// but return type does not?
+
+		//printf("\tvtbl[%d] = '%s'\n", vi, fdv ? fdv->ident->toChars() : "");
+		if (fdv && fdv->ident == ident)
+		{
+		    int cov = type->covariant(fdv->type);
+		    //printf("\tbaseclass cov = %d\n", cov);
+		    if (cov == 2)
+		    {
+			//type->print();
+			//fdv->type->print();
+			//printf("%s %s\n", type->deco, fdv->type->deco);
+			error("of type %s overrides but is not covariant with %s of type %s",
+			    type->toChars(), fdv->toPrettyChars(), fdv->type->toChars());
+		    }
+		    if (cov == 1)
+		    {
+			if (fdv->isFinal())
+			    error("cannot override final function %s", fdv->toPrettyChars());
+			if (fdv->toParent() == parent)
+			{
+			    // If both are mixins, then error.
+			    // If either is not, the one that is not overrides
+			    // the other.
+			    if (fdv->parent->isClassDeclaration())
+				goto L1;
+			    if (!this->parent->isClassDeclaration()
+#if !BREAKABI
+				&& !isDtorDeclaration()
+#endif
+				)
+				error("multiple overrides of same function");
+			}
+			cd->vtbl.data[vi] = (void *)this;
+			vtblIndex = vi;
+
+			/* This works by whenever this function is called,
+			 * it actually returns tintro, which gets dynamically
+			 * cast to type. But we know that tintro is a base
+			 * of type, so we could optimize it by not doing a
+			 * dynamic cast, but just subtracting the isBaseOf()
+			 * offset if the value is != null.
+			 */
+
+			if (fdv->tintro)
+			    tintro = fdv->tintro;
+			else if (!type->equals(fdv->type))
+			{
+			    /* Only need to have a tintro if the vptr
+			     * offsets differ
+			     */
+			    int offset;
+			    if (fdv->type->nextOf()->isBaseOf(type->nextOf(), &offset))
+			    {
+				tintro = fdv->type;
+			    }
+			}
+			goto L1;
+		    }
+		    if (cov == 3)
+		    {
+			cd->sizeok = 2;	// can't finish due to forward reference
+			return;
+		    }
+		}
+	    }
+	}
+
+	// This is an 'introducing' function.
+
+	// Verify this doesn't override previous final function
+	if (cd->baseClass)
+	{   Dsymbol *s = cd->baseClass->search(loc, ident, 0);
+	    if (s)
+	    {
+		FuncDeclaration *f = s->isFuncDeclaration();
+		f = f->overloadExactMatch(type);
+		if (f && f->isFinal() && f->prot() != PROTprivate)
+		    error("cannot override final function %s", f->toPrettyChars());
+	    }
+	}
+
+	if (isFinal())
+	{
+	    cd->vtblFinal.push(this);
+	}
+	else
+	{
+	    // Append to end of vtbl[]
+	    //printf("\tintroducing function\n");
+	    introducing = 1;
+	    vi = cd->vtbl.dim;
+	    cd->vtbl.push(this);
+	    vtblIndex = vi;
+	}
+
+    L1: ;
+
+	/* Go through all the interface bases.
+	 * If this function is covariant with any members of those interface
+	 * functions, set the tintro.
+	 */
+	for (int i = 0; i < cd->interfaces_dim; i++)
+	{
+	    BaseClass *b = cd->interfaces[i];
+	    for (vi = 0; vi < b->base->vtbl.dim; vi++)
+	    {
+		Dsymbol *s = (Dsymbol *)b->base->vtbl.data[vi];
+		//printf("interface %d vtbl[%d] %p %s\n", i, vi, s, s->toChars());
+		FuncDeclaration *fdv = s->isFuncDeclaration();
+		if (fdv && fdv->ident == ident)
+		{
+		    int cov = type->covariant(fdv->type);
+		    //printf("\tcov = %d\n", cov);
+		    if (cov == 2)
+		    {
+			//type->print();
+			//fdv->type->print();
+			//printf("%s %s\n", type->deco, fdv->type->deco);
+			error("of type %s overrides but is not covariant with %s of type %s",
+			    type->toChars(), fdv->toPrettyChars(), fdv->type->toChars());
+		    }
+		    if (cov == 1)
+		    {	Type *ti = NULL;
+
+			if (fdv->tintro)
+			    ti = fdv->tintro;
+			else if (!type->equals(fdv->type))
+			{
+			    /* Only need to have a tintro if the vptr
+			     * offsets differ
+			     */
+			    int offset;
+			    if (fdv->type->nextOf()->isBaseOf(type->nextOf(), &offset))
+			    {
+				ti = fdv->type;
+#if 0
+				if (offset)
+				    ti = fdv->type;
+				else if (type->next->ty == Tclass)
+				{   ClassDeclaration *cdn = ((TypeClass *)type->next)->sym;
+				    if (cdn && cdn->sizeok != 1)
+					ti = fdv->type;
+				}
+#endif
+			    }
+			}
+			if (ti)
+			{
+			    if (tintro && !tintro->equals(ti))
+			    {
+				error("incompatible covariant types %s and %s", tintro->toChars(), ti->toChars());
+			    }
+			    tintro = ti;
+			}
+			goto L2;
+		    }
+		    if (cov == 3)
+		    {
+			cd->sizeok = 2;	// can't finish due to forward reference
+			return;
+		    }
+		}
+	    }
+	}
+
+	if (introducing && isOverride())
+	{
+	    error("function %s does not override any", toChars());
+	}
+
+    L2: ;
+    }
+    else if (isOverride() && !parent->isTemplateInstance())
+	error("override only applies to class member functions");
+
+    /* Do not allow template instances to add virtual functions
+     * to a class.
+     */
+    if (isVirtual())
+    {
+	TemplateInstance *ti = parent->isTemplateInstance();
+	if (ti)
+	{
+	    // Take care of nested templates
+	    while (1)
+	    {
+		TemplateInstance *ti2 = ti->tempdecl->parent->isTemplateInstance();
+		if (!ti2)
+		    break;
+		ti = ti2;
+	    }
+
+	    // If it's a member template
+	    ClassDeclaration *cd = ti->tempdecl->isClassMember();
+	    if (cd)
+	    {
+		error("cannot use template to add virtual function to class '%s'", cd->toChars());
+	    }
+	}
+    }
+
+    if (isMain())
+    {
+	// Check parameters to see if they are either () or (char[][] args)
+	switch (nparams)
+	{
+	    case 0:
+		break;
+
+	    case 1:
+	    {
+		Argument *arg0 = Argument::getNth(f->parameters, 0);
+		if (arg0->type->ty != Tarray ||
+		    arg0->type->next->ty != Tarray ||
+		    arg0->type->next->next->ty != Tchar ||
+		    arg0->storageClass & (STCout | STCref | STClazy))
+		    goto Lmainerr;
+		break;
+	    }
+
+	    default:
+		goto Lmainerr;
+	}
+
+	if (f->nextOf()->ty != Tint32 && f->nextOf()->ty != Tvoid)
+	    error("must return int or void, not %s", f->nextOf()->toChars());
+	if (f->varargs)
+	{
+	Lmainerr:
+	    error("parameters must be main() or main(char[][] args)");
+	}
+    }
+
+    if (ident == Id::assign && (sd || cd))
+    {	// Disallow identity assignment operator.
+
+	// opAssign(...)
+	if (nparams == 0)
+	{   if (f->varargs == 1)
+		goto Lassignerr;
+	}
+	else
+	{
+	    Argument *arg0 = Argument::getNth(f->parameters, 0);
+	    Type *t0 = arg0->type->toBasetype();
+	    Type *tb = sd ? sd->type : cd->type;
+	    if (arg0->type->implicitConvTo(tb) ||
+		(sd && t0->ty == Tpointer && t0->nextOf()->implicitConvTo(tb))
+	       )
+	    {
+		if (nparams == 1)
+		    goto Lassignerr;
+		Argument *arg1 = Argument::getNth(f->parameters, 1);
+		if (arg1->defaultArg)
+		    goto Lassignerr;
+	    }
+	}
+    }
+
+    /* Save scope for possible later use (if we need the
+     * function internals)
+     */
+    scope = new Scope(*sc);
+    scope->setNoFree();
+    return;
+
+Lassignerr:
+    error("identity assignment operator overload is illegal");
+}
+
+void FuncDeclaration::semantic2(Scope *sc)
+{
+}
+
+// Do the semantic analysis on the internals of the function.
+
+void FuncDeclaration::semantic3(Scope *sc)
+{   TypeFunction *f;
+    AggregateDeclaration *ad;
+    VarDeclaration *argptr = NULL;
+    VarDeclaration *_arguments = NULL;
+
+    if (!parent)
+    {
+	printf("FuncDeclaration::semantic3(%s '%s', sc = %p)\n", kind(), toChars(), sc);
+	assert(0);
+    }
+    //printf("FuncDeclaration::semantic3('%s.%s', sc = %p)\n", parent->toChars(), toChars(), sc);
+    //fflush(stdout);
+    //{ static int x; if (++x == 2) *(char*)0=0; }
+    //printf("\tlinkage = %d\n", sc->linkage);
+
+    //printf(" sc->incontract = %d\n", sc->incontract);
+    if (semanticRun)
+	return;
+    semanticRun = 1;
+
+    if (!type || type->ty != Tfunction)
+	return;
+    f = (TypeFunction *)(type);
+    size_t nparams = Argument::dim(f->parameters);
+
+    // Check the 'throws' clause
+    if (fthrows)
+    {	int i;
+
+	for (i = 0; i < fthrows->dim; i++)
+	{
+	    Type *t = (Type *)fthrows->data[i];
+
+	    t = t->semantic(loc, sc);
+	    if (!t->isClassHandle())
+		error("can only throw classes, not %s", t->toChars());
+	}
+    }
+
+    if (fbody || frequire)
+    {
+	// Establish function scope
+	ScopeDsymbol *ss;
+	Scope *sc2;
+
+	localsymtab = new DsymbolTable();
+
+	ss = new ScopeDsymbol();
+	ss->parent = sc->scopesym;
+	sc2 = sc->push(ss);
+	sc2->func = this;
+	sc2->parent = this;
+	sc2->callSuper = 0;
+	sc2->sbreak = NULL;
+	sc2->scontinue = NULL;
+	sc2->sw = NULL;
+	sc2->fes = fes;
+	sc2->linkage = LINKd;
+	sc2->stc &= ~(STCauto | STCscope | STCstatic | STCabstract | STCdeprecated);
+	sc2->protection = PROTpublic;
+	sc2->explicitProtection = 0;
+	sc2->structalign = 8;
+	sc2->incontract = 0;
+	sc2->tf = NULL;
+	sc2->noctor = 0;
+
+	// Declare 'this'
+	ad = isThis();
+	if (ad)
+	{   VarDeclaration *v;
+
+	    if (isFuncLiteralDeclaration() && isNested())
+	    {
+		error("literals cannot be class members");
+		return;
+	    }
+	    else
+	    {
+		assert(!isNested());	// can't be both member and nested
+		assert(ad->handle);
+		v = new ThisDeclaration(ad->handle);
+		v->storage_class |= STCparameter | STCin;
+		v->semantic(sc2);
+		if (!sc2->insert(v))
+		    assert(0);
+		v->parent = this;
+		vthis = v;
+	    }
+	}
+	else if (isNested())
+	{
+	    VarDeclaration *v;
+
+	    v = new ThisDeclaration(Type::tvoid->pointerTo());
+	    v->storage_class |= STCparameter | STCin;
+	    v->semantic(sc2);
+	    if (!sc2->insert(v))
+		assert(0);
+	    v->parent = this;
+	    vthis = v;
+	}
+
+	// Declare hidden variable _arguments[] and _argptr
+	if (f->varargs == 1)
+	{   Type *t;
+
+	    if (f->linkage == LINKd)
+	    {	// Declare _arguments[]
+#if BREAKABI
+		v_arguments = new VarDeclaration(0, Type::typeinfotypelist->type, Id::_arguments_typeinfo, NULL);
+		v_arguments->storage_class = STCparameter | STCin;
+		v_arguments->semantic(sc2);
+		sc2->insert(v_arguments);
+		v_arguments->parent = this;
+
+		t = Type::typeinfo->type->arrayOf();
+		_arguments = new VarDeclaration(0, t, Id::_arguments, NULL);
+		_arguments->semantic(sc2);
+		sc2->insert(_arguments);
+		_arguments->parent = this;
+#else
+		t = Type::typeinfo->type->arrayOf();
+		v_arguments = new VarDeclaration(0, t, Id::_arguments, NULL);
+		v_arguments->storage_class = STCparameter | STCin;
+		v_arguments->semantic(sc2);
+		sc2->insert(v_arguments);
+		v_arguments->parent = this;
+#endif
+	    }
+	    if (f->linkage == LINKd || (parameters && parameters->dim))
+	    {	// Declare _argptr
+#if IN_GCC
+		t = d_gcc_builtin_va_list_d_type;
+#else
+		t = Type::tvoid->pointerTo();
+#endif
+		argptr = new VarDeclaration(0, t, Id::_argptr, NULL);
+		argptr->semantic(sc2);
+		sc2->insert(argptr);
+		argptr->parent = this;
+	    }
+	}
+
+	// Propagate storage class from tuple arguments to their sub-arguments.
+	if (f->parameters)
+	{
+	    for (size_t i = 0; i < f->parameters->dim; i++)
+	    {	Argument *arg = (Argument *)f->parameters->data[i];
+
+		if (arg->type->ty == Ttuple)
+		{   TypeTuple *t = (TypeTuple *)arg->type;
+		    size_t dim = Argument::dim(t->arguments);
+		    for (size_t j = 0; j < dim; j++)
+		    {	Argument *narg = Argument::getNth(t->arguments, j);
+			narg->storageClass = arg->storageClass;
+		    }
+		}
+	    }
+	}
+
+	// Declare all the function parameters as variables
+	if (nparams)
+	{   // parameters[] has all the tuples removed, as the back end
+	    // doesn't know about tuples
+	    parameters = new Dsymbols();
+	    parameters->reserve(nparams);
+	    for (size_t i = 0; i < nparams; i++)
+	    {
+		Argument *arg = Argument::getNth(f->parameters, i);
+		Identifier *id = arg->ident;
+		if (!id)
+		{
+		    //error("no identifier for parameter %d of %s", i + 1, toChars());
+		    OutBuffer buf;
+		    buf.printf("_param_%zu", i);
+		    char *name = (char *)buf.extractData();
+		    id = new Identifier(name, TOKidentifier);
+		    arg->ident = id;
+		}
+		VarDeclaration *v = new VarDeclaration(0, arg->type, id, NULL);
+		//printf("declaring parameter %s of type %s\n", v->toChars(), v->type->toChars());
+		v->storage_class |= STCparameter;
+		if (f->varargs == 2 && i + 1 == nparams)
+		    v->storage_class |= STCvariadic;
+		v->storage_class |= arg->storageClass & (STCin | STCout | STCref | STClazy);
+		if (v->storage_class & STClazy)
+		    v->storage_class |= STCin;
+		v->semantic(sc2);
+		if (!sc2->insert(v))
+		    error("parameter %s.%s is already defined", toChars(), v->toChars());
+		else
+		    parameters->push(v);
+		localsymtab->insert(v);
+		v->parent = this;
+        // for llvm d
+        arg->vardecl = v;
+	    }
+	}
+
+	// Declare the tuple symbols and put them in the symbol table,
+	// but not in parameters[].
+	if (f->parameters)
+	{
+	    for (size_t i = 0; i < f->parameters->dim; i++)
+	    {	Argument *arg = (Argument *)f->parameters->data[i];
+
+		if (!arg->ident)
+		    continue;			// never used, so ignore
+		if (arg->type->ty == Ttuple)
+		{   TypeTuple *t = (TypeTuple *)arg->type;
+		    size_t dim = Argument::dim(t->arguments);
+		    Objects *exps = new Objects();
+		    exps->setDim(dim);
+		    for (size_t j = 0; j < dim; j++)
+		    {	Argument *narg = Argument::getNth(t->arguments, j);
+			assert(narg->ident);
+			VarDeclaration *v = sc2->search(0, narg->ident, NULL)->isVarDeclaration();
+			assert(v);
+			Expression *e = new VarExp(0, v);
+			exps->data[j] = (void *)e;
+		    }
+		    assert(arg->ident);
+		    TupleDeclaration *v = new TupleDeclaration(0, arg->ident, exps);
+		    //printf("declaring tuple %s\n", v->toChars());
+		    v->isexp = 1;
+		    if (!sc2->insert(v))
+			error("parameter %s.%s is already defined", toChars(), v->toChars());
+		    localsymtab->insert(v);
+		    v->parent = this;
+		}
+	    }
+	}
+
+	sc2->incontract++;
+
+	if (frequire)
+	{
+	    // BUG: need to error if accessing out parameters
+	    // BUG: need to treat parameters as const
+	    // BUG: need to disallow returns and throws
+	    // BUG: verify that all in and ref parameters are read
+	    frequire = frequire->semantic(sc2);
+	    labtab = NULL;		// so body can't refer to labels
+	}
+
+	if (fensure || addPostInvariant())
+	{
+	    ScopeDsymbol *sym;
+
+	    sym = new ScopeDsymbol();
+	    sym->parent = sc2->scopesym;
+	    sc2 = sc2->push(sym);
+
+	    assert(type->nextOf());
+	    if (type->nextOf()->ty == Tvoid)
+	    {
+		if (outId)
+		    error("void functions have no result");
+	    }
+	    else
+	    {
+		if (!outId)
+		    outId = Id::result;		// provide a default
+	    }
+
+	    if (outId)
+	    {	// Declare result variable
+		VarDeclaration *v;
+		Loc loc = this->loc;
+
+		if (fensure)
+		    loc = fensure->loc;
+
+		v = new VarDeclaration(loc, type->nextOf(), outId, NULL);
+		v->noauto = 1;
+		sc2->incontract--;
+		v->semantic(sc2);
+		sc2->incontract++;
+		if (!sc2->insert(v))
+		    error("out result %s is already defined", v->toChars());
+		v->parent = this;
+		vresult = v;
+
+		// vresult gets initialized with the function return value
+		// in ReturnStatement::semantic()
+	    }
+
+	    // BUG: need to treat parameters as const
+	    // BUG: need to disallow returns and throws
+	    if (fensure)
+	    {	fensure = fensure->semantic(sc2);
+		labtab = NULL;		// so body can't refer to labels
+	    }
+
+	    if (!global.params.useOut)
+	    {	fensure = NULL;		// discard
+		vresult = NULL;
+	    }
+
+	    // Postcondition invariant
+	    if (addPostInvariant())
+	    {
+		Expression *e = NULL;
+		if (isCtorDeclaration())
+		{
+		    // Call invariant directly only if it exists
+		    InvariantDeclaration *inv = ad->inv;
+		    ClassDeclaration *cd = ad->isClassDeclaration();
+
+		    while (!inv && cd)
+		    {
+			cd = cd->baseClass;
+			if (!cd)
+			    break;
+			inv = cd->inv;
+		    }
+		    if (inv)
+		    {
+			e = new DsymbolExp(0, inv);
+			e = new CallExp(0, e);
+			e = e->semantic(sc2);
+		    }
+		}
+		else
+		{   // Call invariant virtually
+		    ThisExp *v = new ThisExp(0);
+		    v->type = vthis->type;
+		    e = new AssertExp(0, v);
+		}
+		if (e)
+		{
+		    ExpStatement *s = new ExpStatement(0, e);
+		    if (fensure)
+			fensure = new CompoundStatement(0, s, fensure);
+		    else
+			fensure = s;
+		}
+	    }
+
+	    if (fensure)
+	    {	returnLabel = new LabelDsymbol(Id::returnLabel);
+		LabelStatement *ls = new LabelStatement(0, Id::returnLabel, fensure);
+		ls->isReturnLabel = 1;
+		returnLabel->statement = ls;
+	    }
+	    sc2 = sc2->pop();
+	}
+
+	sc2->incontract--;
+
+	if (fbody)
+	{   ClassDeclaration *cd = isClassMember();
+
+	    if (isCtorDeclaration() && cd)
+	    {
+		for (int i = 0; i < cd->fields.dim; i++)
+		{   VarDeclaration *v = (VarDeclaration *)cd->fields.data[i];
+
+		    v->ctorinit = 0;
+		}
+	    }
+
+	    if (inferRetType || f->retStyle() != RETstack)
+		nrvo_can = 0;
+
+	    fbody = fbody->semantic(sc2);
+
+	    if (inferRetType)
+	    {	// If no return type inferred yet, then infer a void
+		if (!type->nextOf())
+		{
+		    type->next = Type::tvoid;
+		    type = type->semantic(loc, sc);
+		}
+		f = (TypeFunction *)type;
+	    }
+
+	    int offend = fbody ? fbody->fallOffEnd() : TRUE;
+
+	    if (isStaticCtorDeclaration())
+	    {	/* It's a static constructor. Ensure that all
+		 * ctor consts were initialized.
+		 */
+
+		ScopeDsymbol *ad = toParent()->isScopeDsymbol();
+		assert(ad);
+		for (int i = 0; i < ad->members->dim; i++)
+		{   Dsymbol *s = (Dsymbol *)ad->members->data[i];
+
+		    s->checkCtorConstInit();
+		}
+	    }
+
+	    if (isCtorDeclaration() && cd)
+	    {
+		//printf("callSuper = x%x\n", sc2->callSuper);
+
+		// Verify that all the ctorinit fields got initialized
+		if (!(sc2->callSuper & CSXthis_ctor))
+		{
+		    for (int i = 0; i < cd->fields.dim; i++)
+		    {   VarDeclaration *v = (VarDeclaration *)cd->fields.data[i];
+
+			if (v->ctorinit == 0 && v->isCtorinit())
+			    error("missing initializer for const field %s", v->toChars());
+		    }
+		}
+
+		if (!(sc2->callSuper & CSXany_ctor) &&
+		    cd->baseClass && cd->baseClass->ctor)
+		{
+		    sc2->callSuper = 0;
+
+		    // Insert implicit super() at start of fbody
+		    Expression *e1 = new SuperExp(0);
+		    Expression *e = new CallExp(0, e1);
+
+		    unsigned errors = global.errors;
+		    global.gag++;
+		    e = e->semantic(sc2);
+		    global.gag--;
+		    if (errors != global.errors)
+			error("no match for implicit super() call in constructor");
+
+		    Statement *s = new ExpStatement(0, e);
+		    fbody = new CompoundStatement(0, s, fbody);
+		}
+	    }
+	    else if (fes)
+	    {	// For foreach(){} body, append a return 0;
+		Expression *e = new IntegerExp(0);
+		Statement *s = new ReturnStatement(0, e);
+		fbody = new CompoundStatement(0, fbody, s);
+		assert(!returnLabel);
+	    }
+	    else if (!hasReturnExp && type->nextOf()->ty != Tvoid)
+		error("expected to return a value of type %s", type->nextOf()->toChars());
+	    else if (!inlineAsm)
+	    {
+		if (type->nextOf()->ty == Tvoid)
+		{
+		    if (offend && isMain())
+		    {	// Add a return 0; statement
+			Statement *s = new ReturnStatement(0, new IntegerExp(0));
+			fbody = new CompoundStatement(0, fbody, s);
+		    }
+		}
+		else
+		{
+		    if (offend)
+		    {   Expression *e;
+
+			if (global.params.warnings)
+			{   fprintf(stdmsg, "warning - ");
+			    error("no return at end of function");
+			}
+
+			if (global.params.useAssert &&
+			    !global.params.useInline)
+			{   /* Add an assert(0, msg); where the missing return
+			     * should be.
+			     */
+			    e = new AssertExp(
+				  endloc,
+				  new IntegerExp(0),
+				  new StringExp(loc, "missing return expression")
+				);
+			}
+			else
+			    e = new HaltExp(endloc);
+			e = new CommaExp(0, e, type->nextOf()->defaultInit());
+			e = e->semantic(sc2);
+			Statement *s = new ExpStatement(0, e);
+			fbody = new CompoundStatement(0, fbody, s);
+		    }
+		}
+	    }
+	}
+
+	{
+	    Statements *a = new Statements();
+
+	    // Merge in initialization of 'out' parameters
+	    if (parameters)
+	    {	for (size_t i = 0; i < parameters->dim; i++)
+		{   VarDeclaration *v;
+
+		    v = (VarDeclaration *)parameters->data[i];
+		    if (v->storage_class & STCout)
+		    {
+			assert(v->init);
+			ExpInitializer *ie = v->init->isExpInitializer();
+			assert(ie);
+			a->push(new ExpStatement(0, ie->exp));
+		    }
+		}
+	    }
+
+	    if (argptr)
+	    {	// Initialize _argptr to point past non-variadic arg
+#if IN_GCC
+		// Handled in FuncDeclaration::toObjFile
+		v_argptr = argptr;
+		v_argptr->init = new VoidInitializer(loc);
+#else
+		Expression *e1;
+		Expression *e;
+		Type *t = argptr->type;
+		VarDeclaration *p;
+		unsigned offset;
+
+		e1 = new VarExp(0, argptr);
+		if (parameters && parameters->dim)
+		    p = (VarDeclaration *)parameters->data[parameters->dim - 1];
+		else
+		    p = v_arguments;		// last parameter is _arguments[]
+		offset = p->type->size();
+		offset = (offset + 3) & ~3;	// assume stack aligns on 4
+		e = new SymOffExp(0, p, offset);
+		e = new AssignExp(0, e1, e);
+		e->type = t;
+		a->push(new ExpStatement(0, e));
+#endif
+	    }
+
+	    if (_arguments)
+	    {
+		/* Advance to elements[] member of TypeInfo_Tuple with:
+		 *  _arguments = v_arguments.elements;
+		 */
+		Expression *e = new VarExp(0, v_arguments);
+		e = new DotIdExp(0, e, Id::elements);
+		Expression *e1 = new VarExp(0, _arguments);
+		e = new AssignExp(0, e1, e);
+		e = e->semantic(sc);
+		a->push(new ExpStatement(0, e));
+	    }
+
+	    // Merge contracts together with body into one compound statement
+
+#ifdef _DH
+	    if (frequire && global.params.useIn)
+	    {	frequire->incontract = 1;
+		a->push(frequire);
+	    }
+#else
+	    if (frequire && global.params.useIn)
+		a->push(frequire);
+#endif
+
+	    // Precondition invariant
+	    if (addPreInvariant())
+	    {
+		Expression *e = NULL;
+		if (isDtorDeclaration())
+		{
+		    // Call invariant directly only if it exists
+		    InvariantDeclaration *inv = ad->inv;
+		    ClassDeclaration *cd = ad->isClassDeclaration();
+
+		    while (!inv && cd)
+		    {
+			cd = cd->baseClass;
+			if (!cd)
+			    break;
+			inv = cd->inv;
+		    }
+		    if (inv)
+		    {
+			e = new DsymbolExp(0, inv);
+			e = new CallExp(0, e);
+			e = e->semantic(sc2);
+		    }
+		}
+		else
+		{   // Call invariant virtually
+		    ThisExp *v = new ThisExp(0);
+		    v->type = vthis->type;
+		    Expression *se = new StringExp(0, "null this");
+		    se = se->semantic(sc);
+		    se->type = Type::tchar->arrayOf();
+		    e = new AssertExp(loc, v, se);
+		}
+		if (e)
+		{
+		    ExpStatement *s = new ExpStatement(0, e);
+		    a->push(s);
+		}
+	    }
+
+	    if (fbody)
+		a->push(fbody);
+
+	    if (fensure)
+	    {
+		a->push(returnLabel->statement);
+
+		if (type->nextOf()->ty != Tvoid)
+		{
+		    // Create: return vresult;
+		    assert(vresult);
+		    Expression *e = new VarExp(0, vresult);
+		    if (tintro)
+		    {	e = e->implicitCastTo(sc, tintro->nextOf());
+			e = e->semantic(sc);
+		    }
+		    ReturnStatement *s = new ReturnStatement(0, e);
+		    a->push(s);
+		}
+	    }
+
+	    fbody = new CompoundStatement(0, a);
+	}
+
+	sc2->callSuper = 0;
+	sc2->pop();
+    }
+    semanticRun = 2;
+}
+
+void FuncDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    //printf("FuncDeclaration::toCBuffer() '%s'\n", toChars());
+
+    type->toCBuffer(buf, ident, hgs);
+    bodyToCBuffer(buf, hgs);
+}
+
+
+void FuncDeclaration::bodyToCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    if (fbody &&
+	(!hgs->hdrgen || hgs->tpltMember || canInline(1,1))
+       )
+    {	buf->writenl();
+
+	// in{}
+	if (frequire)
+	{   buf->writestring("in");
+	    buf->writenl();
+	    frequire->toCBuffer(buf, hgs);
+	}
+
+	// out{}
+	if (fensure)
+	{   buf->writestring("out");
+	    if (outId)
+	    {   buf->writebyte('(');
+		buf->writestring(outId->toChars());
+		buf->writebyte(')');
+	    }
+	    buf->writenl();
+	    fensure->toCBuffer(buf, hgs);
+	}
+
+        if (frequire || fensure)
+	{   buf->writestring("body");
+	    buf->writenl();
+	}
+
+	buf->writebyte('{');
+	buf->writenl();
+	fbody->toCBuffer(buf, hgs);
+	buf->writebyte('}');
+	buf->writenl();
+    }
+    else
+    {	buf->writeByte(';');
+	buf->writenl();
+    }
+}
+
+/****************************************************
+ * Determine if 'this' overrides fd.
+ * Return !=0 if it does.
+ */
+
+int FuncDeclaration::overrides(FuncDeclaration *fd)
+{   int result = 0;
+
+    if (fd->ident == ident)
+    {
+	int cov = type->covariant(fd->type);
+	if (cov)
+	{   ClassDeclaration *cd1 = toParent()->isClassDeclaration();
+	    ClassDeclaration *cd2 = fd->toParent()->isClassDeclaration();
+
+	    if (cd1 && cd2 && cd2->isBaseOf(cd1, NULL))
+		result = 1;
+	}
+    }
+    return result;
+}
+
+/****************************************************
+ * Overload this FuncDeclaration with the new one f.
+ * Return !=0 if successful; i.e. no conflict.
+ */
+
+int FuncDeclaration::overloadInsert(Dsymbol *s)
+{
+    FuncDeclaration *f;
+    AliasDeclaration *a;
+
+    //printf("FuncDeclaration::overloadInsert(%s)\n", s->toChars());
+    a = s->isAliasDeclaration();
+    if (a)
+    {
+	if (overnext)
+	    return overnext->overloadInsert(a);
+	if (!a->aliassym && a->type->ty != Tident && a->type->ty != Tinstance)
+	{
+	    //printf("\ta = '%s'\n", a->type->toChars());
+	    return FALSE;
+	}
+	overnext = a;
+	//printf("\ttrue: no conflict\n");
+	return TRUE;
+    }
+    f = s->isFuncDeclaration();
+    if (!f)
+	return FALSE;
+
+    if (type && f->type &&	// can be NULL for overloaded constructors
+	f->type->covariant(type) &&
+	!isFuncAliasDeclaration())
+    {
+	//printf("\tfalse: conflict %s\n", kind());
+	return FALSE;
+    }
+
+    if (overnext)
+	return overnext->overloadInsert(f);
+    overnext = f;
+    //printf("\ttrue: no conflict\n");
+    return TRUE;
+}
+
+/********************************************
+ * Find function in overload list that exactly matches t.
+ */
+
+/***************************************************
+ * Visit each overloaded function in turn, and call
+ * (*fp)(param, f) on it.
+ * Exit when no more, or (*fp)(param, f) returns 1.
+ * Returns:
+ *	0	continue
+ *	1	done
+ */
+
+int overloadApply(FuncDeclaration *fstart,
+	int (*fp)(void *, FuncDeclaration *),
+	void *param)
+{
+    FuncDeclaration *f;
+    Declaration *d;
+    Declaration *next;
+
+    for (d = fstart; d; d = next)
+    {	FuncAliasDeclaration *fa = d->isFuncAliasDeclaration();
+
+	if (fa)
+	{
+	    if (overloadApply(fa->funcalias, fp, param))
+		return 1;
+	    next = fa->overnext;
+	}
+	else
+	{
+	    AliasDeclaration *a = d->isAliasDeclaration();
+
+	    if (a)
+	    {
+		Dsymbol *s = a->toAlias();
+		next = s->isDeclaration();
+		if (next == a)
+		    break;
+		if (next == fstart)
+		    break;
+	    }
+	    else
+	    {
+		f = d->isFuncDeclaration();
+		if (!f)
+		{   d->error("is aliased to a function");
+		    break;		// BUG: should print error message?
+		}
+		if ((*fp)(param, f))
+		    return 1;
+
+		next = f->overnext;
+	    }
+	}
+    }
+    return 0;
+}
+
+/********************************************
+ * Find function in overload list that exactly matches t.
+ */
+
+struct Param1
+{
+    Type *t;		// type to match
+    FuncDeclaration *f;	// return value
+};
+
+int fp1(void *param, FuncDeclaration *f)
+{   Param1 *p = (Param1 *)param;
+    Type *t = p->t;
+
+    if (t->equals(f->type))
+    {	p->f = f;
+	return 1;
+    }
+
+#if V2
+    /* Allow covariant matches, if it's just a const conversion
+     * of the return type
+     */
+    if (t->ty == Tfunction)
+    {   TypeFunction *tf = (TypeFunction *)f->type;
+	if (tf->covariant(t) == 1 &&
+	    tf->nextOf()->implicitConvTo(t->nextOf()) >= MATCHconst)
+	{
+	    p->f = f;
+	    return 1;
+	}
+    }
+#endif
+    return 0;
+}
+
+FuncDeclaration *FuncDeclaration::overloadExactMatch(Type *t)
+{
+    Param1 p;
+    p.t = t;
+    p.f = NULL;
+    overloadApply(this, &fp1, &p);
+    return p.f;
+}
+
+#if 0
+FuncDeclaration *FuncDeclaration::overloadExactMatch(Type *t)
+{
+    FuncDeclaration *f;
+    Declaration *d;
+    Declaration *next;
+
+    for (d = this; d; d = next)
+    {	FuncAliasDeclaration *fa = d->isFuncAliasDeclaration();
+
+	if (fa)
+	{
+	    FuncDeclaration *f2 = fa->funcalias->overloadExactMatch(t);
+	    if (f2)
+		return f2;
+	    next = fa->overnext;
+	}
+	else
+	{
+	    AliasDeclaration *a = d->isAliasDeclaration();
+
+	    if (a)
+	    {
+		Dsymbol *s = a->toAlias();
+		next = s->isDeclaration();
+		if (next == a)
+		    break;
+	    }
+	    else
+	    {
+		f = d->isFuncDeclaration();
+		if (!f)
+		    break;		// BUG: should print error message?
+		if (t->equals(d->type))
+		    return f;
+		next = f->overnext;
+	    }
+	}
+    }
+    return NULL;
+}
+#endif
+
+/********************************************
+ * Decide which function matches the arguments best.
+ */
+
+struct Param2
+{
+    Match *m;
+    Expressions *arguments;
+};
+
+int fp2(void *param, FuncDeclaration *f)
+{   Param2 *p = (Param2 *)param;
+    Match *m = p->m;
+    Expressions *arguments = p->arguments;
+    MATCH match;
+
+    if (f != m->lastf)		// skip duplicates
+    {
+	TypeFunction *tf;
+
+	m->anyf = f;
+	tf = (TypeFunction *)f->type;
+	match = (MATCH) tf->callMatch(arguments);
+	//printf("match = %d\n", match);
+	if (match != MATCHnomatch)
+	{
+	    if (match > m->last)
+		goto LfIsBetter;
+
+	    if (match < m->last)
+		goto LlastIsBetter;
+
+	    /* See if one of the matches overrides the other.
+	     */
+	    if (m->lastf->overrides(f))
+		goto LlastIsBetter;
+	    else if (f->overrides(m->lastf))
+		goto LfIsBetter;
+
+	Lambiguous:
+	    m->nextf = f;
+	    m->count++;
+	    return 0;
+
+	LfIsBetter:
+	    m->last = match;
+	    m->lastf = f;
+	    m->count = 1;
+	    return 0;
+
+	LlastIsBetter:
+	    return 0;
+	}
+    }
+    return 0;
+}
+
+
+void overloadResolveX(Match *m, FuncDeclaration *fstart, Expressions *arguments)
+{
+    Param2 p;
+    p.m = m;
+    p.arguments = arguments;
+    overloadApply(fstart, &fp2, &p);
+}
+
+#if 0
+// Recursive helper function
+
+void overloadResolveX(Match *m, FuncDeclaration *fstart, Expressions *arguments)
+{
+    MATCH match;
+    Declaration *d;
+    Declaration *next;
+
+    for (d = fstart; d; d = next)
+    {
+	FuncDeclaration *f;
+	FuncAliasDeclaration *fa;
+	AliasDeclaration *a;
+
+	fa = d->isFuncAliasDeclaration();
+	if (fa)
+	{
+	    overloadResolveX(m, fa->funcalias, arguments);
+	    next = fa->overnext;
+	}
+	else if ((f = d->isFuncDeclaration()) != NULL)
+	{
+	    next = f->overnext;
+	    if (f == m->lastf)
+		continue;			// skip duplicates
+	    else
+	    {
+		TypeFunction *tf;
+
+		m->anyf = f;
+		tf = (TypeFunction *)f->type;
+		match = (MATCH) tf->callMatch(arguments);
+		//printf("match = %d\n", match);
+		if (match != MATCHnomatch)
+		{
+		    if (match > m->last)
+			goto LfIsBetter;
+
+		    if (match < m->last)
+			goto LlastIsBetter;
+
+		    /* See if one of the matches overrides the other.
+		     */
+		    if (m->lastf->overrides(f))
+			goto LlastIsBetter;
+		    else if (f->overrides(m->lastf))
+			goto LfIsBetter;
+
+		Lambiguous:
+		    m->nextf = f;
+		    m->count++;
+		    continue;
+
+		LfIsBetter:
+		    m->last = match;
+		    m->lastf = f;
+		    m->count = 1;
+		    continue;
+
+		LlastIsBetter:
+		    continue;
+		}
+	    }
+	}
+	else if ((a = d->isAliasDeclaration()) != NULL)
+	{
+	    Dsymbol *s = a->toAlias();
+	    next = s->isDeclaration();
+	    if (next == a)
+		break;
+	    if (next == fstart)
+		break;
+	}
+	else
+	{   d->error("is aliased to a function");
+	    break;
+	}
+    }
+}
+#endif
+
+FuncDeclaration *FuncDeclaration::overloadResolve(Loc loc, Expressions *arguments)
+{
+    TypeFunction *tf;
+    Match m;
+
+#if 0
+printf("FuncDeclaration::overloadResolve('%s')\n", toChars());
+if (arguments)
+{   int i;
+
+    for (i = 0; i < arguments->dim; i++)
+    {   Expression *arg;
+
+	arg = (Expression *)arguments->data[i];
+	assert(arg->type);
+	printf("\t%s: ", arg->toChars());
+	arg->type->print();
+    }
+}
+#endif
+
+    memset(&m, 0, sizeof(m));
+    m.last = MATCHnomatch;
+    overloadResolveX(&m, this, arguments);
+
+    if (m.count == 1)		// exactly one match
+    {
+	return m.lastf;
+    }
+    else
+    {
+	OutBuffer buf;
+
+	if (arguments)
+	{
+	    HdrGenState hgs;
+
+	    argExpTypesToCBuffer(&buf, arguments, &hgs);
+	}
+
+	if (m.last == MATCHnomatch)
+	{
+	    tf = (TypeFunction *)type;
+
+	    //printf("tf = %s, args = %s\n", tf->deco, ((Expression *)arguments->data[0])->type->deco);
+	    error(loc, "%s does not match parameter types (%s)",
+		Argument::argsTypesToChars(tf->parameters, tf->varargs),
+		buf.toChars());
+	    return m.anyf;		// as long as it's not a FuncAliasDeclaration
+	}
+	else
+	{
+#if 1
+	    TypeFunction *t1 = (TypeFunction *)m.lastf->type;
+	    TypeFunction *t2 = (TypeFunction *)m.nextf->type;
+
+	    error(loc, "called with argument types:\n\t(%s)\nmatches both:\n\t%s%s\nand:\n\t%s%s",
+		    buf.toChars(),
+		    m.lastf->toPrettyChars(), Argument::argsTypesToChars(t1->parameters, t1->varargs),
+		    m.nextf->toPrettyChars(), Argument::argsTypesToChars(t2->parameters, t2->varargs));
+#else
+	    error(loc, "overloads %s and %s both match argument list for %s",
+		    m.lastf->type->toChars(),
+		    m.nextf->type->toChars(),
+		    m.lastf->toChars());
+#endif
+	    return m.lastf;
+	}
+    }
+}
+
+/********************************
+ * Labels are in a separate scope, one per function.
+ */
+
+LabelDsymbol *FuncDeclaration::searchLabel(Identifier *ident)
+{   Dsymbol *s;
+
+    if (!labtab)
+	labtab = new DsymbolTable();	// guess we need one
+
+    s = labtab->lookup(ident);
+    if (!s)
+    {
+	s = new LabelDsymbol(ident);
+	labtab->insert(s);
+    }
+    return (LabelDsymbol *)s;
+}
+
+AggregateDeclaration *FuncDeclaration::isThis()
+{   AggregateDeclaration *ad;
+
+    //printf("+FuncDeclaration::isThis() '%s'\n", toChars());
+    ad = NULL;
+    if ((storage_class & STCstatic) == 0)
+    {
+	ad = isMember2();
+    }
+    //printf("-FuncDeclaration::isThis() %p\n", ad);
+    return ad;
+}
+
+AggregateDeclaration *FuncDeclaration::isMember2()
+{   AggregateDeclaration *ad;
+
+    //printf("+FuncDeclaration::isMember2() '%s'\n", toChars());
+    ad = NULL;
+    for (Dsymbol *s = this; s; s = s->parent)
+    {
+//printf("\ts = '%s', parent = '%s', kind = %s\n", s->toChars(), s->parent->toChars(), s->parent->kind());
+	ad = s->isMember();
+	if (ad)
+{   //printf("test4\n");
+	    break;
+}
+	if (!s->parent ||
+	    (!s->parent->isTemplateInstance()))
+{   //printf("test5\n");
+	    break;
+}
+    }
+    //printf("-FuncDeclaration::isMember2() %p\n", ad);
+    return ad;
+}
+
+/*****************************************
+ * Determine lexical level difference from 'this' to nested function 'fd'.
+ * Error if this cannot call fd.
+ * Returns:
+ *	0	same level
+ *	-1	increase nesting by 1 (fd is nested within 'this')
+ *	>0	decrease nesting by number
+ */
+
+int FuncDeclaration::getLevel(Loc loc, FuncDeclaration *fd)
+{   int level;
+    Dsymbol *s;
+    Dsymbol *fdparent;
+
+    //printf("FuncDeclaration::getLevel(fd = '%s')\n", fd->toChars());
+    fdparent = fd->toParent2();
+    if (fdparent == this)
+	return -1;
+    s = this;
+    level = 0;
+    while (fd != s && fdparent != s->toParent2())
+    {
+	//printf("\ts = '%s'\n", s->toChars());
+	FuncDeclaration *thisfd = s->isFuncDeclaration();
+	if (thisfd)
+	{   if (!thisfd->isNested() && !thisfd->vthis)
+		goto Lerr;
+	}
+	else
+	{
+	    ClassDeclaration *thiscd = s->isClassDeclaration();
+	    if (thiscd)
+	    {	if (!thiscd->isNested())
+		    goto Lerr;
+	    }
+	    else
+		goto Lerr;
+	}
+
+	s = s->toParent2();
+	assert(s);
+	level++;
+    }
+    return level;
+
+Lerr:
+    error(loc, "cannot access frame of function %s", fd->toChars());
+    return 1;
+}
+
+void FuncDeclaration::appendExp(Expression *e)
+{   Statement *s;
+
+    s = new ExpStatement(0, e);
+    appendState(s);
+}
+
+void FuncDeclaration::appendState(Statement *s)
+{   CompoundStatement *cs;
+
+    if (!fbody)
+    {	Statements *a;
+
+	a = new Statements();
+	fbody = new CompoundStatement(0, a);
+    }
+    cs = fbody->isCompoundStatement();
+    cs->statements->push(s);
+}
+
+
+int FuncDeclaration::isMain()
+{
+    return ident == Id::main &&
+	linkage != LINKc && !isMember() && !isNested();
+}
+
+int FuncDeclaration::isWinMain()
+{
+    return ident == Id::WinMain &&
+	linkage != LINKc && !isMember();
+}
+
+int FuncDeclaration::isDllMain()
+{
+    return ident == Id::DllMain &&
+	linkage != LINKc && !isMember();
+}
+
+int FuncDeclaration::isExport()
+{
+    return protection == PROTexport;
+}
+
+int FuncDeclaration::isImportedSymbol()
+{
+    //printf("isImportedSymbol()\n");
+    //printf("protection = %d\n", protection);
+    return (protection == PROTexport) && !fbody;
+}
+
+// Determine if function goes into virtual function pointer table
+
+int FuncDeclaration::isVirtual()
+{
+#if 0
+    printf("FuncDeclaration::isVirtual(%s)\n", toChars());
+    printf("%p %d %d %d %d\n", isMember(), isStatic(), protection == PROTprivate, isCtorDeclaration(), linkage != LINKd);
+    printf("result is %d\n",
+	isMember() &&
+	!(isStatic() || protection == PROTprivate || protection == PROTpackage) &&
+	toParent()->isClassDeclaration());
+#endif
+    return isMember() &&
+	!(isStatic() || protection == PROTprivate || protection == PROTpackage) &&
+	toParent()->isClassDeclaration();
+}
+
+int FuncDeclaration::isAbstract()
+{
+    return storage_class & STCabstract;
+}
+
+int FuncDeclaration::isCodeseg()
+{
+    return TRUE;		// functions are always in the code segment
+}
+
+// Determine if function needs
+// a static frame pointer to its lexically enclosing function
+
+int FuncDeclaration::isNested()
+{
+    //if (!toParent())
+	//printf("FuncDeclaration::isNested('%s') parent=%p\n", toChars(), parent);
+    //printf("\ttoParent() = '%s'\n", toParent()->toChars());
+    return ((storage_class & STCstatic) == 0) &&
+	   (toParent2()->isFuncDeclaration() != NULL);
+}
+
+int FuncDeclaration::needThis()
+{
+    //printf("FuncDeclaration::needThis() '%s'\n", toChars());
+    int i = isThis() != NULL;
+    //printf("\t%d\n", i);
+    if (!i && isFuncAliasDeclaration())
+	i = ((FuncAliasDeclaration *)this)->funcalias->needThis();
+    return i;
+}
+
+int FuncDeclaration::addPreInvariant()
+{
+    AggregateDeclaration *ad = isThis();
+    return (ad &&
+	    //ad->isClassDeclaration() &&
+	    global.params.useInvariants &&
+	    (protection == PROTpublic || protection == PROTexport) &&
+	    !naked);
+}
+
+int FuncDeclaration::addPostInvariant()
+{
+    AggregateDeclaration *ad = isThis();
+    return (ad &&
+	    ad->inv &&
+	    //ad->isClassDeclaration() &&
+	    global.params.useInvariants &&
+	    (protection == PROTpublic || protection == PROTexport) &&
+	    !naked);
+}
+
+/**********************************
+ * Generate a FuncDeclaration for a runtime library function.
+ */
+
+FuncDeclaration *FuncDeclaration::genCfunc(Type *treturn, char *name)
+{
+    return genCfunc(treturn, Lexer::idPool(name));
+}
+
+FuncDeclaration *FuncDeclaration::genCfunc(Type *treturn, Identifier *id)
+{
+    FuncDeclaration *fd;
+    TypeFunction *tf;
+    Dsymbol *s;
+    static DsymbolTable *st = NULL;
+
+    //printf("genCfunc(name = '%s')\n", id->toChars());
+    //printf("treturn\n\t"); treturn->print();
+
+    // See if already in table
+    if (!st)
+	st = new DsymbolTable();
+    s = st->lookup(id);
+    if (s)
+    {
+	fd = s->isFuncDeclaration();
+	assert(fd);
+	assert(fd->type->nextOf()->equals(treturn));
+    }
+    else
+    {
+	tf = new TypeFunction(NULL, treturn, 0, LINKc);
+	fd = new FuncDeclaration(0, 0, id, STCstatic, tf);
+	fd->protection = PROTpublic;
+	fd->linkage = LINKc;
+
+	st->insert(fd);
+    }
+    return fd;
+}
+
+char *FuncDeclaration::kind()
+{
+    return "function";
+}
+
+/****************************** FuncAliasDeclaration ************************/
+
+// Used as a way to import a set of functions from another scope into this one.
+
+FuncAliasDeclaration::FuncAliasDeclaration(FuncDeclaration *funcalias)
+    : FuncDeclaration(funcalias->loc, funcalias->endloc, funcalias->ident,
+	(enum STC)funcalias->storage_class, funcalias->type)
+{
+    assert(funcalias != this);
+    this->funcalias = funcalias;
+}
+
+char *FuncAliasDeclaration::kind()
+{
+    return "function alias";
+}
+
+
+/****************************** FuncLiteralDeclaration ************************/
+
+FuncLiteralDeclaration::FuncLiteralDeclaration(Loc loc, Loc endloc, Type *type,
+	enum TOK tok, ForeachStatement *fes)
+    : FuncDeclaration(loc, endloc, NULL, STCundefined, type)
+{
+    char *id;
+
+    if (fes)
+	id = "__foreachbody";
+    else if (tok == TOKdelegate)
+	id = "__dgliteral";
+    else
+	id = "__funcliteral";
+    this->ident = Identifier::generateId(id);
+    this->tok = tok;
+    this->fes = fes;
+    //printf("FuncLiteralDeclaration() id = '%s', type = '%s'\n", this->ident->toChars(), type->toChars());
+}
+
+Dsymbol *FuncLiteralDeclaration::syntaxCopy(Dsymbol *s)
+{
+    FuncLiteralDeclaration *f;
+
+    //printf("FuncLiteralDeclaration::syntaxCopy('%s')\n", toChars());
+    if (s)
+	f = (FuncLiteralDeclaration *)s;
+    else
+	f = new FuncLiteralDeclaration(loc, endloc, type->syntaxCopy(), tok, fes);
+    FuncDeclaration::syntaxCopy(f);
+    return f;
+}
+
+int FuncLiteralDeclaration::isNested()
+{
+    //printf("FuncLiteralDeclaration::isNested() '%s'\n", toChars());
+    return (tok == TOKdelegate);
+}
+
+char *FuncLiteralDeclaration::kind()
+{
+    // GCC requires the (char*) casts
+    return (tok == TOKdelegate) ? (char*)"delegate" : (char*)"function";
+}
+
+void FuncLiteralDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    static Identifier *idfunc;
+    static Identifier *iddel;
+
+    if (!idfunc)
+	idfunc = new Identifier("function", 0);
+    if (!iddel)
+	iddel = new Identifier("delegate", 0);
+
+    type->toCBuffer(buf, ((tok == TOKdelegate) ? iddel : idfunc), hgs);
+    bodyToCBuffer(buf, hgs);
+}
+
+
+/********************************* CtorDeclaration ****************************/
+
+CtorDeclaration::CtorDeclaration(Loc loc, Loc endloc, Arguments *arguments, int varargs)
+    : FuncDeclaration(loc, endloc, Id::ctor, STCundefined, NULL)
+{
+    this->arguments = arguments;
+    this->varargs = varargs;
+    //printf("CtorDeclaration() %s\n", toChars());
+}
+
+Dsymbol *CtorDeclaration::syntaxCopy(Dsymbol *s)
+{
+    CtorDeclaration *f;
+
+    f = new CtorDeclaration(loc, endloc, NULL, varargs);
+
+    f->outId = outId;
+    f->frequire = frequire ? frequire->syntaxCopy() : NULL;
+    f->fensure  = fensure  ? fensure->syntaxCopy()  : NULL;
+    f->fbody    = fbody    ? fbody->syntaxCopy()    : NULL;
+    assert(!fthrows); // deprecated
+
+    f->arguments = Argument::arraySyntaxCopy(arguments);
+    return f;
+}
+
+
+void CtorDeclaration::semantic(Scope *sc)
+{
+    ClassDeclaration *cd;
+    Type *tret;
+
+    //printf("CtorDeclaration::semantic()\n");
+
+    sc = sc->push();
+    sc->stc &= ~STCstatic;		// not a static constructor
+
+    parent = sc->parent;
+    Dsymbol *parent = toParent();
+    cd = parent->isClassDeclaration();
+    if (!cd)
+    {
+	error("constructors only are for class definitions");
+	tret = Type::tvoid;
+    }
+    else
+	tret = cd->type; //->referenceTo();
+    type = new TypeFunction(arguments, tret, varargs, LINKd);
+
+    sc->flags |= SCOPEctor;
+    type = type->semantic(loc, sc);
+    sc->flags &= ~SCOPEctor;
+
+    // Append:
+    //	return this;
+    // to the function body
+    if (fbody)
+    {	Expression *e;
+	Statement *s;
+
+	e = new ThisExp(0);
+	s = new ReturnStatement(0, e);
+	fbody = new CompoundStatement(0, fbody, s);
+    }
+
+    FuncDeclaration::semantic(sc);
+
+    sc->pop();
+
+    // See if it's the default constructor
+    if (cd && varargs == 0 && Argument::dim(arguments) == 0)
+	cd->defaultCtor = this;
+}
+
+char *CtorDeclaration::kind()
+{
+    return "constructor";
+}
+
+char *CtorDeclaration::toChars()
+{
+    return "this";
+}
+
+int CtorDeclaration::isVirtual()
+{
+    return FALSE;
+}
+
+int CtorDeclaration::addPreInvariant()
+{
+    return FALSE;
+}
+
+int CtorDeclaration::addPostInvariant()
+{
+    return (vthis && global.params.useInvariants);
+}
+
+
+void CtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("this");
+    Argument::argsToCBuffer(buf, hgs, arguments, varargs);
+    bodyToCBuffer(buf, hgs);
+}
+
+/********************************* DtorDeclaration ****************************/
+
+DtorDeclaration::DtorDeclaration(Loc loc, Loc endloc)
+    : FuncDeclaration(loc, endloc, Id::dtor, STCundefined, NULL)
+{
+}
+
+Dsymbol *DtorDeclaration::syntaxCopy(Dsymbol *s)
+{
+    DtorDeclaration *dd;
+
+    assert(!s);
+    dd = new DtorDeclaration(loc, endloc);
+    return FuncDeclaration::syntaxCopy(dd);
+}
+
+
+void DtorDeclaration::semantic(Scope *sc)
+{
+    ClassDeclaration *cd;
+
+    parent = sc->parent;
+    Dsymbol *parent = toParent();
+    cd = parent->isClassDeclaration();
+    if (!cd)
+    {
+	error("destructors only are for class definitions");
+    }
+    else
+	cd->dtors.push(this);
+    type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd);
+
+    sc = sc->push();
+    sc->stc &= ~STCstatic;		// not a static destructor
+    sc->linkage = LINKd;
+
+    FuncDeclaration::semantic(sc);
+
+    sc->pop();
+}
+
+int DtorDeclaration::overloadInsert(Dsymbol *s)
+{
+    return FALSE;	// cannot overload destructors
+}
+
+int DtorDeclaration::addPreInvariant()
+{
+    return (vthis && global.params.useInvariants);
+}
+
+int DtorDeclaration::addPostInvariant()
+{
+    return FALSE;
+}
+
+int DtorDeclaration::isVirtual()
+{
+    /* This should be FALSE so that dtor's don't get put into the vtbl[],
+     * but doing so will require recompiling everything.
+     */
+#if BREAKABI
+    return FALSE;
+#else
+    return FuncDeclaration::isVirtual();
+#endif
+}
+
+void DtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    if (hgs->hdrgen)
+	return;
+    buf->writestring("~this()");
+    bodyToCBuffer(buf, hgs);
+}
+
+/********************************* StaticCtorDeclaration ****************************/
+
+StaticCtorDeclaration::StaticCtorDeclaration(Loc loc, Loc endloc)
+    : FuncDeclaration(loc, endloc, Id::staticCtor, STCstatic, NULL)
+{
+}
+
+Dsymbol *StaticCtorDeclaration::syntaxCopy(Dsymbol *s)
+{
+    StaticCtorDeclaration *scd;
+
+    assert(!s);
+    scd = new StaticCtorDeclaration(loc, endloc);
+    return FuncDeclaration::syntaxCopy(scd);
+}
+
+
+void StaticCtorDeclaration::semantic(Scope *sc)
+{
+    //printf("StaticCtorDeclaration::semantic()\n");
+
+    type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd);
+
+    FuncDeclaration::semantic(sc);
+
+    // We're going to need ModuleInfo
+    Module *m = getModule();
+    if (!m)
+	m = sc->module;
+    if (m)
+    {	m->needmoduleinfo = 1;
+#ifdef IN_GCC
+	m->strictlyneedmoduleinfo = 1;
+#endif
+    }
+}
+
+AggregateDeclaration *StaticCtorDeclaration::isThis()
+{
+    return NULL;
+}
+
+int StaticCtorDeclaration::isStaticConstructor()
+{
+    return TRUE;
+}
+
+int StaticCtorDeclaration::isVirtual()
+{
+    return FALSE;
+}
+
+int StaticCtorDeclaration::addPreInvariant()
+{
+    return FALSE;
+}
+
+int StaticCtorDeclaration::addPostInvariant()
+{
+    return FALSE;
+}
+
+void StaticCtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    if (hgs->hdrgen)
+    {	buf->writestring("static this(){}\n");
+	return;
+    }
+    buf->writestring("static this()");
+    bodyToCBuffer(buf, hgs);
+}
+
+/********************************* StaticDtorDeclaration ****************************/
+
+StaticDtorDeclaration::StaticDtorDeclaration(Loc loc, Loc endloc)
+    : FuncDeclaration(loc, endloc, Id::staticDtor, STCstatic, NULL)
+{
+}
+
+Dsymbol *StaticDtorDeclaration::syntaxCopy(Dsymbol *s)
+{
+    StaticDtorDeclaration *sdd;
+
+    assert(!s);
+    sdd = new StaticDtorDeclaration(loc, endloc);
+    return FuncDeclaration::syntaxCopy(sdd);
+}
+
+
+void StaticDtorDeclaration::semantic(Scope *sc)
+{
+    ClassDeclaration *cd;
+    Type *tret;
+
+    cd = sc->scopesym->isClassDeclaration();
+    if (!cd)
+    {
+    }
+    type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd);
+
+    FuncDeclaration::semantic(sc);
+
+    // We're going to need ModuleInfo
+    Module *m = getModule();
+    if (!m)
+	m = sc->module;
+    if (m)
+    {	m->needmoduleinfo = 1;
+#ifdef IN_GCC
+	m->strictlyneedmoduleinfo = 1;
+#endif
+    }
+}
+
+AggregateDeclaration *StaticDtorDeclaration::isThis()
+{
+    return NULL;
+}
+
+int StaticDtorDeclaration::isStaticDestructor()
+{
+    return TRUE;
+}
+
+int StaticDtorDeclaration::isVirtual()
+{
+    return FALSE;
+}
+
+int StaticDtorDeclaration::addPreInvariant()
+{
+    return FALSE;
+}
+
+int StaticDtorDeclaration::addPostInvariant()
+{
+    return FALSE;
+}
+
+void StaticDtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    if (hgs->hdrgen)
+	return;
+    buf->writestring("static ~this()");
+    bodyToCBuffer(buf, hgs);
+}
+
+/********************************* InvariantDeclaration ****************************/
+
+InvariantDeclaration::InvariantDeclaration(Loc loc, Loc endloc)
+    : FuncDeclaration(loc, endloc, Id::classInvariant, STCundefined, NULL)
+{
+}
+
+Dsymbol *InvariantDeclaration::syntaxCopy(Dsymbol *s)
+{
+    InvariantDeclaration *id;
+
+    assert(!s);
+    id = new InvariantDeclaration(loc, endloc);
+    FuncDeclaration::syntaxCopy(id);
+    return id;
+}
+
+
+void InvariantDeclaration::semantic(Scope *sc)
+{
+    AggregateDeclaration *ad;
+    Type *tret;
+
+    parent = sc->parent;
+    Dsymbol *parent = toParent();
+    ad = parent->isAggregateDeclaration();
+    if (!ad)
+    {
+	error("invariants only are for struct/union/class definitions");
+	return;
+    }
+    else if (ad->inv && ad->inv != this)
+    {
+	error("more than one invariant for %s", ad->toChars());
+    }
+    ad->inv = this;
+    type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd);
+
+    sc = sc->push();
+    sc->stc &= ~STCstatic;		// not a static invariant
+    sc->incontract++;
+    sc->linkage = LINKd;
+
+    FuncDeclaration::semantic(sc);
+
+    sc->pop();
+}
+
+int InvariantDeclaration::isVirtual()
+{
+    return FALSE;
+}
+
+int InvariantDeclaration::addPreInvariant()
+{
+    return FALSE;
+}
+
+int InvariantDeclaration::addPostInvariant()
+{
+    return FALSE;
+}
+
+void InvariantDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    if (hgs->hdrgen)
+	return;
+    buf->writestring("invariant");
+    bodyToCBuffer(buf, hgs);
+}
+
+
+/********************************* UnitTestDeclaration ****************************/
+
+/*******************************
+ * Generate unique unittest function Id so we can have multiple
+ * instances per module.
+ */
+
+static Identifier *unitTestId()
+{
+    static int n;
+    char buffer[10 + sizeof(n)*3 + 1];
+
+    sprintf(buffer,"__unittest%d", n);
+    n++;
+    return Lexer::idPool(buffer);
+}
+
+UnitTestDeclaration::UnitTestDeclaration(Loc loc, Loc endloc)
+    : FuncDeclaration(loc, endloc, unitTestId(), STCundefined, NULL)
+{
+}
+
+Dsymbol *UnitTestDeclaration::syntaxCopy(Dsymbol *s)
+{
+    UnitTestDeclaration *utd;
+
+    assert(!s);
+    utd = new UnitTestDeclaration(loc, endloc);
+    return FuncDeclaration::syntaxCopy(utd);
+}
+
+
+void UnitTestDeclaration::semantic(Scope *sc)
+{
+    if (global.params.useUnitTests)
+    {
+	Type *tret;
+
+	type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd);
+	FuncDeclaration::semantic(sc);
+    }
+
+    // We're going to need ModuleInfo even if the unit tests are not
+    // compiled in, because other modules may import this module and refer
+    // to this ModuleInfo.
+    Module *m = getModule();
+    if (!m)
+	m = sc->module;
+    if (m)
+	m->needmoduleinfo = 1;
+}
+
+AggregateDeclaration *UnitTestDeclaration::isThis()
+{
+    return NULL;
+}
+
+int UnitTestDeclaration::isVirtual()
+{
+    return FALSE;
+}
+
+int UnitTestDeclaration::addPreInvariant()
+{
+    return FALSE;
+}
+
+int UnitTestDeclaration::addPostInvariant()
+{
+    return FALSE;
+}
+
+void UnitTestDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    if (hgs->hdrgen)
+	return;
+    buf->writestring("unittest");
+    bodyToCBuffer(buf, hgs);
+}
+
+/********************************* NewDeclaration ****************************/
+
+NewDeclaration::NewDeclaration(Loc loc, Loc endloc, Arguments *arguments, int varargs)
+    : FuncDeclaration(loc, endloc, Id::classNew, STCstatic, NULL)
+{
+    this->arguments = arguments;
+    this->varargs = varargs;
+}
+
+Dsymbol *NewDeclaration::syntaxCopy(Dsymbol *s)
+{
+    NewDeclaration *f;
+
+    f = new NewDeclaration(loc, endloc, NULL, varargs);
+
+    FuncDeclaration::syntaxCopy(f);
+
+    f->arguments = Argument::arraySyntaxCopy(arguments);
+
+    return f;
+}
+
+
+void NewDeclaration::semantic(Scope *sc)
+{
+    ClassDeclaration *cd;
+    Type *tret;
+
+    //printf("NewDeclaration::semantic()\n");
+
+    parent = sc->parent;
+    Dsymbol *parent = toParent();
+    cd = parent->isClassDeclaration();
+    if (!cd && !parent->isStructDeclaration())
+    {
+	error("new allocators only are for class or struct definitions");
+    }
+    tret = Type::tvoid->pointerTo();
+    type = new TypeFunction(arguments, tret, varargs, LINKd);
+
+    type = type->semantic(loc, sc);
+    assert(type->ty == Tfunction);
+
+    // Check that there is at least one argument of type uint
+    TypeFunction *tf = (TypeFunction *)type;
+    if (Argument::dim(tf->parameters) < 1)
+    {
+	error("at least one argument of type uint expected");
+    }
+    else
+    {
+	Argument *a = Argument::getNth(tf->parameters, 0);
+	if (!a->type->equals(Type::tuns32))
+	    error("first argument must be type uint, not %s", a->type->toChars());
+    }
+
+    FuncDeclaration::semantic(sc);
+}
+
+char *NewDeclaration::kind()
+{
+    return "allocator";
+}
+
+int NewDeclaration::isVirtual()
+{
+    return FALSE;
+}
+
+int NewDeclaration::addPreInvariant()
+{
+    return FALSE;
+}
+
+int NewDeclaration::addPostInvariant()
+{
+    return FALSE;
+}
+
+void NewDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("new");
+    Argument::argsToCBuffer(buf, hgs, arguments, varargs);
+    bodyToCBuffer(buf, hgs);
+}
+
+
+/********************************* DeleteDeclaration ****************************/
+
+DeleteDeclaration::DeleteDeclaration(Loc loc, Loc endloc, Arguments *arguments)
+    : FuncDeclaration(loc, endloc, Id::classDelete, STCstatic, NULL)
+{
+    this->arguments = arguments;
+}
+
+Dsymbol *DeleteDeclaration::syntaxCopy(Dsymbol *s)
+{
+    DeleteDeclaration *f;
+
+    f = new DeleteDeclaration(loc, endloc, NULL);
+
+    FuncDeclaration::syntaxCopy(f);
+
+    f->arguments = Argument::arraySyntaxCopy(arguments);
+
+    return f;
+}
+
+
+void DeleteDeclaration::semantic(Scope *sc)
+{
+    ClassDeclaration *cd;
+
+    //printf("DeleteDeclaration::semantic()\n");
+
+    parent = sc->parent;
+    Dsymbol *parent = toParent();
+    cd = parent->isClassDeclaration();
+    if (!cd && !parent->isStructDeclaration())
+    {
+	error("new allocators only are for class or struct definitions");
+    }
+    type = new TypeFunction(arguments, Type::tvoid, 0, LINKd);
+
+    type = type->semantic(loc, sc);
+    assert(type->ty == Tfunction);
+
+    // Check that there is only one argument of type void*
+    TypeFunction *tf = (TypeFunction *)type;
+    if (Argument::dim(tf->parameters) != 1)
+    {
+	error("one argument of type void* expected");
+    }
+    else
+    {
+	Argument *a = Argument::getNth(tf->parameters, 0);
+	if (!a->type->equals(Type::tvoid->pointerTo()))
+	    error("one argument of type void* expected, not %s", a->type->toChars());
+    }
+
+    FuncDeclaration::semantic(sc);
+}
+
+char *DeleteDeclaration::kind()
+{
+    return "deallocator";
+}
+
+int DeleteDeclaration::isDelete()
+{
+    return TRUE;
+}
+
+int DeleteDeclaration::isVirtual()
+{
+    return FALSE;
+}
+
+int DeleteDeclaration::addPreInvariant()
+{
+    return FALSE;
+}
+
+int DeleteDeclaration::addPostInvariant()
+{
+    return FALSE;
+}
+
+void DeleteDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("delete");
+    Argument::argsToCBuffer(buf, hgs, arguments, 0);
+    bodyToCBuffer(buf, hgs);
+}
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/gnuc.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,55 @@
+
+// Put functions in here missing from gnu C
+
+#include "gnuc.h"
+
+int memicmp(const char *s1, const char *s2, int n)
+{
+    int result = 0;
+
+    for (int i = 0; i < n; i++)
+    {	char c1 = s1[i];
+	char c2 = s2[i];
+
+	result = c1 - c2;
+	if (result)
+	{
+	    if ('A' <= c1 && c1 <= 'Z')
+		c1 += 'a' - 'A';
+	    if ('A' <= c2 && c2 <= 'Z')
+		c2 += 'a' - 'A';
+	    result = c1 - c2;
+	    if (result)
+		break;
+	}
+    }
+    return result;
+}
+
+int stricmp(const char *s1, const char *s2)
+{
+    int result = 0;
+
+    for (;;)
+    {	char c1 = *s1;
+	char c2 = *s2;
+
+	result = c1 - c2;
+	if (result)
+	{
+	    if ('A' <= c1 && c1 <= 'Z')
+		c1 += 'a' - 'A';
+	    if ('A' <= c2 && c2 <= 'Z')
+		c2 += 'a' - 'A';
+	    result = c1 - c2;
+	    if (result)
+		break;
+	}
+	if (!c1)
+	    break;
+	s1++;
+	s2++;
+    }
+    return result;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/gnuc.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,8 @@
+
+#ifndef _GNUC_H
+#define _GNUC_H 1
+
+int memicmp(const char *s1, const char *s2, int n);
+int stricmp(const char *s1, const char *s2);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/gpl.txt	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,248 @@
+		    GNU GENERAL PUBLIC LICENSE
+		     Version 1, February 1989
+
+ Copyright (C) 1989 Free Software Foundation, Inc.
+                59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The license agreements of most software companies try to keep users
+at the mercy of those companies.  By contrast, our General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  The
+General Public License applies to the Free Software Foundation's
+software and to any other program whose authors commit to using it.
+You can use it for your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Specifically, the General Public License is designed to make
+sure that you have the freedom to give away or sell copies of free
+software, that you receive source code or can get it if you want it,
+that you can change the software or use pieces of it in new free
+programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of a such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must tell them their rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any program or other work which
+contains a notice placed by the copyright holder saying it may be
+distributed under the terms of this General Public License.  The
+"Program", below, refers to any such program or work, and a "work based
+on the Program" means either the Program or any work containing the
+Program or a portion of it, either verbatim or with modifications.  Each
+licensee is addressed as "you".
+
+  1. You may copy and distribute verbatim copies of the Program's source
+code as you receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice and
+disclaimer of warranty; keep intact all the notices that refer to this
+General Public License and to the absence of any warranty; and give any
+other recipients of the Program a copy of this General Public License
+along with the Program.  You may charge a fee for the physical act of
+transferring a copy.
+
+  2. You may modify your copy or copies of the Program or any portion of
+it, and copy and distribute such modifications under the terms of Paragraph
+1 above, provided that you also do the following:
+
+    a) cause the modified files to carry prominent notices stating that
+    you changed the files and the date of any change; and
+
+    b) cause the whole of any work that you distribute or publish, that
+    in whole or in part contains the Program or any part thereof, either
+    with or without modifications, to be licensed at no charge to all
+    third parties under the terms of this General Public License (except
+    that you may choose to grant warranty protection to some or all
+    third parties, at your option).
+
+    c) If the modified program normally reads commands interactively when
+    run, you must cause it, when started running for such interactive use
+    in the simplest and most usual way, to print or display an
+    announcement including an appropriate copyright notice and a notice
+    that there is no warranty (or else, saying that you provide a
+    warranty) and that users may redistribute the program under these
+    conditions, and telling the user how to view a copy of this General
+    Public License.
+
+    d) You may charge a fee for the physical act of transferring a
+    copy, and you may at your option offer warranty protection in
+    exchange for a fee.
+
+Mere aggregation of another independent work with the Program (or its
+derivative) on a volume of a storage or distribution medium does not bring
+the other work under the scope of these terms.
+
+  3. You may copy and distribute the Program (or a portion or derivative of
+it, under Paragraph 2) in object code or executable form under the terms of
+Paragraphs 1 and 2 above provided that you also do one of the following:
+
+    a) accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of
+    Paragraphs 1 and 2 above; or,
+
+    b) accompany it with a written offer, valid for at least three
+    years, to give any third party free (except for a nominal charge
+    for the cost of distribution) a complete machine-readable copy of the
+    corresponding source code, to be distributed under the terms of
+    Paragraphs 1 and 2 above; or,
+
+    c) accompany it with the information you received as to where the
+    corresponding source code may be obtained.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form alone.)
+
+Source code for a work means the preferred form of the work for making
+modifications to it.  For an executable file, complete source code means
+all the source code for all modules it contains; but, as a special
+exception, it need not include source code for modules which are standard
+libraries that accompany the operating system on which the executable
+file runs, or for standard header files or definitions files that
+accompany that operating system.
+
+  4. You may not copy, modify, sublicense, distribute or transfer the
+Program except as expressly provided under this General Public License.
+Any attempt otherwise to copy, modify, sublicense, distribute or transfer
+the Program is void, and will automatically terminate your rights to use
+the Program under this License.  However, parties who have received
+copies, or rights to use copies, from you under this General Public
+License will not have their licenses terminated so long as such parties
+remain in full compliance.
+
+  5. By copying, distributing or modifying the Program (or any work based
+on the Program) you indicate your acceptance of this license to do so,
+and all its terms and conditions.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the original
+licensor to copy, distribute or modify the Program subject to these
+terms and conditions.  You may not impose any further restrictions on the
+recipients' exercise of the rights granted herein.
+
+  7. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of the license which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+the license, you may choose any version ever published by the Free Software
+Foundation.
+
+  8. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	Appendix: How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to humanity, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these
+terms.
+
+  To do so, attach the following notices to the program.  It is safest to
+attach them to the start of each source file to most effectively convey
+the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 1, or (at your option)
+    any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software Foundation,
+    Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19xx name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the
+appropriate parts of the General Public License.  Of course, the
+commands you use may be called something other than `show w' and `show
+c'; they could even be mouse-clicks or menu items--whatever suits your
+program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  program `Gnomovision' (a program to direct compilers to make passes
+  at assemblers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+That's all there is to it!
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/hdrgen.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,114 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// Initial header generation implementation by Dave Fladebo
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+// Routines to emit header files
+
+#ifdef _DH
+
+#define PRETTY_PRINT
+#define TEST_EMIT_ALL  0	// For Testing
+
+#define LOG 0
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#if __DMC__
+#include <complex.h>
+#endif
+
+#if IN_GCC || IN_LLVM
+#include "mem.h"
+#else
+#if _WIN32
+#include "..\root\mem.h"
+#elif linux
+#include "../root/mem.h"
+#else
+#error "fix this"
+#endif
+#endif
+
+#include "id.h"
+#include "init.h"
+
+#include "attrib.h"
+#include "cond.h"
+#include "enum.h"
+#include "import.h"
+#include "module.h"
+#include "mtype.h"
+#include "scope.h"
+#include "staticassert.h"
+#include "template.h"
+#include "utf.h"
+#include "version.h"
+
+#include "declaration.h"
+#include "aggregate.h"
+#include "expression.h"
+#include "statement.h"
+#include "mtype.h"
+#include "hdrgen.h"
+
+void argsToCBuffer(OutBuffer *buf, Array *arguments, HdrGenState *hgs);
+
+void Module::genhdrfile()
+{
+    OutBuffer hdrbufr;
+
+    hdrbufr.printf("// D import file generated from '%s'", srcfile->toChars());
+    hdrbufr.writenl();
+
+    HdrGenState hgs;
+    memset(&hgs, 0, sizeof(hgs));
+    hgs.hdrgen = 1;
+
+    toCBuffer(&hdrbufr, &hgs);
+
+    // Transfer image to file
+    hdrfile->setbuffer(hdrbufr.data, hdrbufr.offset);
+    hdrbufr.data = NULL;
+
+    char *pt = FileName::path(hdrfile->toChars());
+    if (*pt)
+	FileName::ensurePathExists(pt);
+    mem.free(pt);
+    hdrfile->writev();
+}
+
+
+void Module::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    if (md)
+    {
+        buf->writestring("module ");
+	buf->writestring(md->toChars());
+        buf->writebyte(';');
+        buf->writenl();
+    }
+
+    for (int i = 0; i < members->dim; i++)
+    {   Dsymbol *s = (Dsymbol *)members->data[i];
+
+        s->toHBuffer(buf, hgs);
+    }
+}
+
+
+void Dsymbol::toHBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    toCBuffer(buf, hgs);
+}
+
+
+/*************************************/
+
+#endif // #ifdef _DH
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/hdrgen.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,34 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// initial header generation implementation by Dave Fladebo
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+
+struct HdrGenState
+{
+    int hdrgen;		// 1 if generating header file
+    int ddoc;		// 1 if generating Ddoc file
+    int console;	// 1 if writing to console
+    int tpltMember;
+    int inCallExp;
+    int inPtrExp;
+    int inSlcExp;
+    int inDotExp;
+    int inBinExp;
+    int inArrExp;
+    int emitInst;
+    struct
+    {
+        int init;
+        int decl;
+    } FLinit;
+
+    HdrGenState() { memset(this, 0, sizeof(HdrGenState)); }
+};
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/html.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,718 @@
+
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+
+/* HTML parser
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <wchar.h>
+
+#include "mars.h"
+#include "html.h"
+
+#include <assert.h>
+#include "root.h"
+
+extern int HtmlNamedEntity(unsigned char *p, int length);
+
+static int isLineSeparator(const unsigned char* p);
+
+/**********************************
+ * Determine if beginning of tag identifier
+ * or a continuation of a tag identifier.
+ */
+
+inline int istagstart(int c)
+{
+    return (isalpha(c) || c == '_');
+}
+
+inline int istag(int c)
+{
+    return (isalnum(c) || c == '_');
+}
+
+/**********************************************
+ */
+
+Html::Html(const char *sourcename, unsigned char *base, unsigned length)
+{
+    //printf("Html::Html()\n");
+    this->sourcename = sourcename;
+    this->base = base;
+    p = base;
+    end = base + length;
+    linnum = 1;
+    dbuf = NULL;
+    inCode = 0;
+}
+
+/**********************************************
+ * Print error & quit.
+ */
+
+void Html::error(const char *format, ...)
+{
+    if (!global.gag)
+    {
+	printf("%s(%d) : HTML Error: ", sourcename, linnum);
+
+	va_list ap;
+	va_start(ap, format);
+	vprintf(format, ap);
+	va_end(ap);
+
+	printf("\n");
+	fflush(stdout);
+    }
+
+    global.errors++;
+}
+
+/**********************************************
+ * Extract all the code from an HTML file,
+ * concatenate it all together, and store in buf.
+ */
+
+void Html::extractCode(OutBuffer *buf)
+{
+    //printf("Html::extractCode()\n");
+    dbuf = buf;			// save for other routines
+    buf->reserve(end - p);
+    inCode = 0;
+    while (1)
+    {
+	//printf("p = %p, *p = x%x\n", p, *p);
+	switch (*p)
+	{
+#if 0 // strings are not recognized outside of tags
+	    case '"':
+	    case '\'':
+		skipString();
+		continue;
+#endif
+	    case '<':
+		if (p[1] == '!' && isCommentStart())
+		{   // Comments start with <!--
+		    scanComment();
+		}
+  		else if(p[1] == '!' && isCDATAStart())
+  		{
+  		    scanCDATA();
+  		}
+		else if (p[1] == '/' && istagstart(*skipWhite(p + 2)))
+		    skipTag();
+		else if (istagstart(*skipWhite(p + 1)))
+		    skipTag();
+		else
+		    goto Ldefault;
+		continue;
+
+	    case 0:
+	    case 0x1a:
+		break;		// end of file
+
+	    case '&':
+		if (inCode)
+		{   // Translate character entity into ascii for D parser
+		    int c;
+
+		    c = charEntity();
+		    buf->writeUTF8(c);
+		}
+		else
+		    p++;
+		continue;
+
+	    case '\r':
+		if (p[1] == '\n')
+		    goto Ldefault;
+	    case '\n':
+		linnum++;
+		// Always extract new lines, so that D lexer counts the
+		// lines right.
+		buf->writeByte(*p);
+		p++;
+		continue;
+
+	    default:
+	    Ldefault:
+		if (inCode)
+		    buf->writeByte(*p);
+		p++;
+		continue;
+	}
+	break;
+    }
+    buf->writeByte(0);				// ending sentinel
+    //printf("D code is: '%s'\n", (char *)buf->data);
+}
+
+/***********************************************
+ * Scan to end of <> tag.
+ * Look for <code> and </code> tags to start/stop D processing.
+ * Input:
+ *	p is on opening '<' of tag; it's already verified that
+ *	it's a tag by lookahead
+ * Output:
+ *	p is past closing '>' of tag
+ */
+
+void Html::skipTag()
+{
+    enum TagState	// what parsing state we're in
+    {
+	TStagstart,	// start of tag name
+	TStag,		// in a tag name
+	TSrest,		// following tag name
+    };
+    enum TagState state = TStagstart;
+    int inot;
+    unsigned char *tagstart = NULL;
+    int taglen = 0;
+
+    p++;
+    inot = 0;
+    if (*p == '/')
+    {	inot = 1;
+	p++;
+    }
+    while (1)
+    {
+	switch (*p)
+	{
+	    case '>':		// found end of tag
+		p++;
+		break;
+
+	    case '"':
+	    case '\'':
+		state = TSrest;
+		skipString();
+		continue;
+
+	    case '<':
+		if (p[1] == '!' && isCommentStart())
+		{   // Comments start with <!--
+		    scanComment();
+		}
+		else if (p[1] == '/' && istagstart(*skipWhite(p + 2)))
+		{   error("nested tag");
+		    skipTag();
+		}
+		else if (istagstart(*skipWhite(p + 1)))
+		{   error("nested tag");
+		    skipTag();
+		}
+		// Treat comments as if they were whitespace
+		state = TSrest;
+		continue;
+
+	    case 0:
+	    case 0x1a:
+		error("end of file before end of tag");
+		break;		// end of file
+
+	    case '\r':
+		if (p[1] == '\n')
+		    goto Ldefault;
+	    case '\n':
+		linnum++;
+		// Always extract new lines, so that code lexer counts the
+		// lines right.
+		dbuf->writeByte(*p);
+		state = TSrest;			// end of tag
+		p++;
+		continue;
+
+	    case ' ':
+	    case '\t':
+	    case '\f':
+	    case '\v':
+		if (state == TStagstart)
+		{   p++;
+		    continue;
+		}
+	    default:
+	    Ldefault:
+		switch (state)
+		{
+		    case TStagstart:		// start of tag name
+			assert(istagstart(*p));
+			state = TStag;
+			tagstart = p;
+			taglen = 0;
+			break;
+
+		    case TStag:
+			if (istag(*p))
+			{   // Continuing tag name
+			    taglen++;
+			}
+			else
+			{   // End of tag name
+			    state = TSrest;
+			}
+			break;
+
+		    case TSrest:
+			break;
+		}
+		p++;
+		continue;
+	}
+	break;
+    }
+
+    // See if we parsed a <code> or </code> tag
+    if (taglen && memicmp((char *) tagstart, (char *) "CODE", taglen) == 0
+	&& *(p - 2) != '/') // ignore "<code />" (XHTML)
+    {
+	if (inot)
+	{   inCode--;
+	    if (inCode < 0)
+		inCode = 0;		// ignore extra </code>'s
+	}
+	else
+	    inCode++;
+    }
+}
+
+/***********************************************
+ * Scan to end of attribute string.
+ */
+
+void Html::skipString()
+{
+    int tc = *p;
+
+    while (1)
+    {
+	p++;
+	switch (*p)
+	{
+	    case '"':
+	    case '\'':
+		if (*p == tc)
+		{   p++;
+		    break;
+		}
+		continue;
+
+	    case '\r':
+		if (p[1] == '\n')
+		    goto Ldefault;
+	    case '\n':
+		linnum++;
+		// Always extract new lines, so that D lexer counts the
+		// lines right.
+		dbuf->writeByte(*p);
+		continue;
+
+	    case 0:
+	    case 0x1a:
+	    Leof:
+		error("end of file before closing %c of string", tc);
+		break;
+
+	    default:
+	    Ldefault:
+		continue;
+	}
+	break;
+    }
+}
+
+/*********************************
+ * If p points to any white space, skip it
+ * and return pointer just past it.
+ */
+
+unsigned char *Html::skipWhite(unsigned char *q)
+{
+    for (; 1; q++)
+    {
+	switch (*q)
+	{
+	    case ' ':
+	    case '\t':
+	    case '\f':
+	    case '\v':
+	    case '\r':
+	    case '\n':
+		continue;
+
+	    default:
+		break;
+	}
+	break;
+    }
+    return q;
+}
+
+/***************************************************
+ * Scan to end of comment.
+ * Comments are defined any of a number of ways.
+ * IE 5.0: <!-- followed by >
+ * "HTML The Definitive Guide": <!-- text with at least one space in it -->
+ * Netscape: <!-- --> comments nest
+ * w3c: whitespace can appear between -- and > of comment close
+ */
+
+void Html::scanComment()
+{
+    // Most of the complexity is dealing with the case that
+    // an arbitrary amount of whitespace can appear between
+    // the -- and the > of a comment close.
+    int scangt = 0;
+
+    //printf("scanComment()\n");
+    if (*p == '\n')
+    {	linnum++;
+	// Always extract new lines, so that D lexer counts the
+	// lines right.
+	dbuf->writeByte(*p);
+    }
+    while (1)
+    {
+	//scangt = 1;			// IE 5.0 compatibility
+	p++;
+	switch (*p)
+	{
+	    case '-':
+		if (p[1] == '-')
+		{
+		    if (p[2] == '>')	// optimize for most common case
+		    {
+			p += 3;
+			break;
+		    }
+		    p++;
+		    scangt = 1;
+		}
+		else
+		    scangt = 0;
+		continue;
+
+	    case '>':
+		if (scangt)
+		{   // found -->
+		    p++;
+		    break;
+		}
+		continue;
+
+	    case ' ':
+	    case '\t':
+	    case '\f':
+	    case '\v':
+		// skip white space
+		continue;
+
+	    case '\r':
+		if (p[1] == '\n')
+		    goto Ldefault;
+	    case '\n':
+		linnum++;		// remember to count lines
+		// Always extract new lines, so that D lexer counts the
+		// lines right.
+		dbuf->writeByte(*p);
+		continue;
+
+	    case 0:
+	    case 0x1a:
+		error("end of file before closing --> of comment");
+		break;
+
+	    default:
+	    Ldefault:
+		scangt = 0;		// it's not -->
+		continue;
+	}
+	break;
+    }
+    //printf("*p = '%c'\n", *p);
+}
+
+/********************************************
+ * Determine if we are at the start of a comment.
+ * Input:
+ *	p is on the opening '<'
+ * Returns:
+ *	0 if not start of a comment
+ * 	1 if start of a comment, p is adjusted to point past --
+ */
+
+int Html::isCommentStart()
+#ifdef __DMC__
+    __out(result)
+    {
+	if (result == 0)
+	    ;
+	else if (result == 1)
+	{
+	    assert(p[-2] == '-' && p[-1] == '-');
+	}
+	else
+	    assert(0);
+    }
+    __body
+#endif /* __DMC__ */
+    {	unsigned char *s;
+
+	if (p[0] == '<' && p[1] == '!')
+	{
+	    for (s = p + 2; 1; s++)
+	    {
+		switch (*s)
+		{
+		    case ' ':
+		    case '\t':
+		    case '\r':
+		    case '\f':
+		    case '\v':
+			// skip white space, even though spec says no
+			// white space is allowed
+			continue;
+
+		    case '-':
+			if (s[1] == '-')
+			{
+			    p = s + 2;
+			    return 1;
+			}
+			goto No;
+
+		    default:
+			goto No;
+		}
+	    }
+	}
+    No:
+	return 0;
+    }
+
+int Html::isCDATAStart()
+{
+    const char * CDATA_START_MARKER = "<![CDATA[";
+    size_t len = strlen(CDATA_START_MARKER);
+
+    if (strncmp((char*)p, CDATA_START_MARKER, len) == 0)
+    {
+	p += len;
+	return 1;
+    }
+    else
+    {
+	return 0;
+    }
+}
+
+void Html::scanCDATA()
+{
+    while(*p && *p != 0x1A)
+    {
+	int lineSepLength = isLineSeparator(p);
+	if (lineSepLength>0)
+	{
+	    /* Always extract new lines, so that D lexer counts the lines
+	     * right.
+	     */
+	    linnum++;
+	    dbuf->writeUTF8('\n');
+	    p += lineSepLength;
+	    continue;
+        }
+	else if (p[0] == ']' && p[1] == ']' && p[2] == '>')
+	{
+	    /* end of CDATA section */
+	    p += 3;
+	    return;
+	}
+	else if (inCode)
+	{
+	    /* this CDATA section contains D code */
+	    dbuf->writeByte(*p);
+	}
+
+	p++;
+    }
+}
+
+/********************************************
+ * Convert an HTML character entity into a character.
+ * Forms are:
+ *	&name;		named entity
+ *	&#ddd;		decimal
+ *	&#xhhhh;	hex
+ * Input:
+ *	p is on the &
+ */
+
+int Html::charEntity()
+{   int c = 0;
+    int v;
+    int hex;
+    unsigned char *pstart = p;
+
+    //printf("Html::charEntity('%c')\n", *p);
+    if (p[1] == '#')
+    {
+	p++;
+	if (p[1] == 'x' || p[1] == 'X')
+	{   p++;
+	    hex = 1;
+	}
+	else
+	    hex = 0;
+	if (p[1] == ';')
+	    goto Linvalid;
+	while (1)
+	{
+	    p++;
+	    switch (*p)
+	    {
+		case 0:
+		case 0x1a:
+		    error("end of file before end of character entity");
+		    goto Lignore;
+
+		case '\n':
+		case '\r':
+		case '<':	// tag start
+		    // Termination is assumed
+		    break;
+
+		case ';':
+		    // Termination is explicit
+		    p++;
+		    break;
+
+		case '0': case '1': case '2': case '3': case '4':
+		case '5': case '6': case '7': case '8': case '9':
+		    v = *p - '0';
+		    goto Lvalue;
+
+		case 'a': case 'b': case 'c':
+		case 'd': case 'e': case 'f':
+		    if (!hex)
+			goto Linvalid;
+		    v = (*p - 'a') + 10;
+		    goto Lvalue;
+
+		case 'A': case 'B': case 'C':
+		case 'D': case 'E': case 'F':
+		    if (!hex)
+			goto Linvalid;
+		    v = (*p - 'A') + 10;
+		    goto Lvalue;
+
+		Lvalue:
+		    if (hex)
+			c = (c << 4) + v;
+		    else
+			c = (c * 10) + v;
+		    if (c > 0x10FFFF)
+		    {
+			error("character entity out of range");
+			goto Lignore;
+		    }
+		    continue;
+
+		default:
+		Linvalid:
+		    error("invalid numeric character reference");
+		    goto Lignore;
+	    }
+	    break;
+	}
+    }
+    else
+    {
+	// It's a named entity; gather all characters until ;
+	unsigned char *idstart = p + 1;
+
+	while (1)
+	{
+	    p++;
+	    switch (*p)
+	    {
+		case 0:
+		case 0x1a:
+		    error("end of file before end of character entity");
+		    break;
+
+		case '\n':
+		case '\r':
+		case '<':	// tag start
+		    // Termination is assumed
+		    c = HtmlNamedEntity(idstart, p - idstart);
+		    if (c == -1)
+			goto Lignore;
+		    break;
+
+		case ';':
+		    // Termination is explicit
+		    c = HtmlNamedEntity(idstart, p - idstart);
+		    if (c == -1)
+			goto Lignore;
+		    p++;
+		    break;
+
+		default:
+		    continue;
+	    }
+	    break;
+	}
+    }
+
+    // Kludge to convert non-breaking space to ascii space
+    if (c == 160)
+	c = ' ';
+
+    return c;
+
+Lignore:
+    //printf("Lignore\n");
+    p = pstart + 1;
+    return '&';
+}
+
+/**
+ * identify DOS, Linux, Mac, Next and Unicode line endings
+ * 0 if this is no line separator
+ * >0 the length of the separator
+ * Note: input has to be UTF-8
+ */
+static int isLineSeparator(const unsigned char* p)
+{
+    // Linux
+    if( p[0]=='\n')
+	return 1;
+
+    // Mac & Dos
+    if( p[0]=='\r')
+	return (p[1]=='\n') ? 2 : 1;
+
+    // Unicode (line || paragraph sep.)
+    if( p[0]==0xE2 && p[1]==0x80 && (p[2]==0xA8 || p[2]==0xA9))
+	return 3;
+
+    // Next
+    if( p[0]==0xC2 && p[1]==0x85)
+	return 2;
+
+    return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/html.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,43 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#ifndef DMD_HTML_H
+#define DMD_HTML_H 1
+
+struct OutBuffer;
+
+struct Html
+{
+    const char *sourcename;
+
+    unsigned char *base;	// pointer to start of buffer
+    unsigned char *end;		// past end of buffer
+    unsigned char *p;		// current character
+    unsigned linnum;		// current line number
+    OutBuffer *dbuf;		// code source buffer
+    int inCode;			// !=0 if in code
+
+
+    Html(const char *sourcename, unsigned char *base, unsigned length);
+
+    void error(const char *format, ...);
+    void extractCode(OutBuffer *buf);
+    void skipTag();
+    void skipString();
+    unsigned char *skipWhite(unsigned char *q);
+    void scanComment();
+    int isCommentStart();
+    void scanCDATA();
+    int isCDATAStart();
+    int charEntity();
+    static int namedEntity(unsigned char *p, int length);
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/id.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,353 @@
+// File generated by idgen.c
+#include "id.h"
+#include "identifier.h"
+#include "lexer.h"
+Identifier *Id::IUnknown;
+Identifier *Id::Object;
+Identifier *Id::object;
+Identifier *Id::max;
+Identifier *Id::min;
+Identifier *Id::This;
+Identifier *Id::ctor;
+Identifier *Id::dtor;
+Identifier *Id::classInvariant;
+Identifier *Id::unitTest;
+Identifier *Id::staticCtor;
+Identifier *Id::staticDtor;
+Identifier *Id::init;
+Identifier *Id::size;
+Identifier *Id::__sizeof;
+Identifier *Id::alignof;
+Identifier *Id::mangleof;
+Identifier *Id::stringof;
+Identifier *Id::tupleof;
+Identifier *Id::length;
+Identifier *Id::remove;
+Identifier *Id::ptr;
+Identifier *Id::funcptr;
+Identifier *Id::dollar;
+Identifier *Id::offset;
+Identifier *Id::offsetof;
+Identifier *Id::ModuleInfo;
+Identifier *Id::ClassInfo;
+Identifier *Id::classinfo;
+Identifier *Id::typeinfo;
+Identifier *Id::outer;
+Identifier *Id::Exception;
+Identifier *Id::withSym;
+Identifier *Id::result;
+Identifier *Id::returnLabel;
+Identifier *Id::delegate;
+Identifier *Id::line;
+Identifier *Id::empty;
+Identifier *Id::p;
+Identifier *Id::coverage;
+Identifier *Id::TypeInfo;
+Identifier *Id::TypeInfo_Class;
+Identifier *Id::TypeInfo_Interface;
+Identifier *Id::TypeInfo_Struct;
+Identifier *Id::TypeInfo_Enum;
+Identifier *Id::TypeInfo_Typedef;
+Identifier *Id::TypeInfo_Pointer;
+Identifier *Id::TypeInfo_Array;
+Identifier *Id::TypeInfo_StaticArray;
+Identifier *Id::TypeInfo_AssociativeArray;
+Identifier *Id::TypeInfo_Function;
+Identifier *Id::TypeInfo_Delegate;
+Identifier *Id::TypeInfo_Tuple;
+Identifier *Id::TypeInfo_Const;
+Identifier *Id::TypeInfo_Invariant;
+Identifier *Id::elements;
+Identifier *Id::_arguments_typeinfo;
+Identifier *Id::_arguments;
+Identifier *Id::_argptr;
+Identifier *Id::_match;
+Identifier *Id::LINE;
+Identifier *Id::FILE;
+Identifier *Id::DATE;
+Identifier *Id::TIME;
+Identifier *Id::TIMESTAMP;
+Identifier *Id::VENDOR;
+Identifier *Id::VERSIONX;
+Identifier *Id::nan;
+Identifier *Id::infinity;
+Identifier *Id::dig;
+Identifier *Id::epsilon;
+Identifier *Id::mant_dig;
+Identifier *Id::max_10_exp;
+Identifier *Id::max_exp;
+Identifier *Id::min_10_exp;
+Identifier *Id::min_exp;
+Identifier *Id::re;
+Identifier *Id::im;
+Identifier *Id::C;
+Identifier *Id::D;
+Identifier *Id::Windows;
+Identifier *Id::Pascal;
+Identifier *Id::System;
+Identifier *Id::exit;
+Identifier *Id::success;
+Identifier *Id::failure;
+Identifier *Id::keys;
+Identifier *Id::values;
+Identifier *Id::rehash;
+Identifier *Id::sort;
+Identifier *Id::reverse;
+Identifier *Id::dup;
+Identifier *Id::idup;
+Identifier *Id::___out;
+Identifier *Id::___in;
+Identifier *Id::__int;
+Identifier *Id::__dollar;
+Identifier *Id::__LOCAL_SIZE;
+Identifier *Id::uadd;
+Identifier *Id::neg;
+Identifier *Id::com;
+Identifier *Id::add;
+Identifier *Id::add_r;
+Identifier *Id::sub;
+Identifier *Id::sub_r;
+Identifier *Id::mul;
+Identifier *Id::mul_r;
+Identifier *Id::div;
+Identifier *Id::div_r;
+Identifier *Id::mod;
+Identifier *Id::mod_r;
+Identifier *Id::eq;
+Identifier *Id::cmp;
+Identifier *Id::iand;
+Identifier *Id::iand_r;
+Identifier *Id::ior;
+Identifier *Id::ior_r;
+Identifier *Id::ixor;
+Identifier *Id::ixor_r;
+Identifier *Id::shl;
+Identifier *Id::shl_r;
+Identifier *Id::shr;
+Identifier *Id::shr_r;
+Identifier *Id::ushr;
+Identifier *Id::ushr_r;
+Identifier *Id::cat;
+Identifier *Id::cat_r;
+Identifier *Id::assign;
+Identifier *Id::addass;
+Identifier *Id::subass;
+Identifier *Id::mulass;
+Identifier *Id::divass;
+Identifier *Id::modass;
+Identifier *Id::andass;
+Identifier *Id::orass;
+Identifier *Id::xorass;
+Identifier *Id::shlass;
+Identifier *Id::shrass;
+Identifier *Id::ushrass;
+Identifier *Id::catass;
+Identifier *Id::postinc;
+Identifier *Id::postdec;
+Identifier *Id::index;
+Identifier *Id::indexass;
+Identifier *Id::slice;
+Identifier *Id::sliceass;
+Identifier *Id::call;
+Identifier *Id::cast;
+Identifier *Id::match;
+Identifier *Id::next;
+Identifier *Id::opIn;
+Identifier *Id::opIn_r;
+Identifier *Id::classNew;
+Identifier *Id::classDelete;
+Identifier *Id::apply;
+Identifier *Id::applyReverse;
+Identifier *Id::adDup;
+Identifier *Id::adReverse;
+Identifier *Id::aaLen;
+Identifier *Id::aaKeys;
+Identifier *Id::aaValues;
+Identifier *Id::aaRehash;
+Identifier *Id::lib;
+Identifier *Id::msg;
+Identifier *Id::GNU_asm;
+Identifier *Id::LLVM_intrinsic;
+Identifier *Id::LLVM_internal;
+Identifier *Id::tohash;
+Identifier *Id::tostring;
+Identifier *Id::alloca;
+Identifier *Id::main;
+Identifier *Id::WinMain;
+Identifier *Id::DllMain;
+void Id::initialize()
+{
+    IUnknown = Lexer::idPool("IUnknown");
+    Object = Lexer::idPool("Object");
+    object = Lexer::idPool("object");
+    max = Lexer::idPool("max");
+    min = Lexer::idPool("min");
+    This = Lexer::idPool("this");
+    ctor = Lexer::idPool("_ctor");
+    dtor = Lexer::idPool("_dtor");
+    classInvariant = Lexer::idPool("__invariant");
+    unitTest = Lexer::idPool("_unitTest");
+    staticCtor = Lexer::idPool("_staticCtor");
+    staticDtor = Lexer::idPool("_staticDtor");
+    init = Lexer::idPool("init");
+    size = Lexer::idPool("size");
+    __sizeof = Lexer::idPool("sizeof");
+    alignof = Lexer::idPool("alignof");
+    mangleof = Lexer::idPool("mangleof");
+    stringof = Lexer::idPool("stringof");
+    tupleof = Lexer::idPool("tupleof");
+    length = Lexer::idPool("length");
+    remove = Lexer::idPool("remove");
+    ptr = Lexer::idPool("ptr");
+    funcptr = Lexer::idPool("funcptr");
+    dollar = Lexer::idPool("__dollar");
+    offset = Lexer::idPool("offset");
+    offsetof = Lexer::idPool("offsetof");
+    ModuleInfo = Lexer::idPool("ModuleInfo");
+    ClassInfo = Lexer::idPool("ClassInfo");
+    classinfo = Lexer::idPool("classinfo");
+    typeinfo = Lexer::idPool("typeinfo");
+    outer = Lexer::idPool("outer");
+    Exception = Lexer::idPool("Exception");
+    withSym = Lexer::idPool("__withSym");
+    result = Lexer::idPool("__result");
+    returnLabel = Lexer::idPool("__returnLabel");
+    delegate = Lexer::idPool("delegate");
+    line = Lexer::idPool("line");
+    empty = Lexer::idPool("");
+    p = Lexer::idPool("p");
+    coverage = Lexer::idPool("__coverage");
+    TypeInfo = Lexer::idPool("TypeInfo");
+    TypeInfo_Class = Lexer::idPool("TypeInfo_Class");
+    TypeInfo_Interface = Lexer::idPool("TypeInfo_Interface");
+    TypeInfo_Struct = Lexer::idPool("TypeInfo_Struct");
+    TypeInfo_Enum = Lexer::idPool("TypeInfo_Enum");
+    TypeInfo_Typedef = Lexer::idPool("TypeInfo_Typedef");
+    TypeInfo_Pointer = Lexer::idPool("TypeInfo_Pointer");
+    TypeInfo_Array = Lexer::idPool("TypeInfo_Array");
+    TypeInfo_StaticArray = Lexer::idPool("TypeInfo_StaticArray");
+    TypeInfo_AssociativeArray = Lexer::idPool("TypeInfo_AssociativeArray");
+    TypeInfo_Function = Lexer::idPool("TypeInfo_Function");
+    TypeInfo_Delegate = Lexer::idPool("TypeInfo_Delegate");
+    TypeInfo_Tuple = Lexer::idPool("TypeInfo_Tuple");
+    TypeInfo_Const = Lexer::idPool("TypeInfo_Const");
+    TypeInfo_Invariant = Lexer::idPool("TypeInfo_Invariant");
+    elements = Lexer::idPool("elements");
+    _arguments_typeinfo = Lexer::idPool("_arguments_typeinfo");
+    _arguments = Lexer::idPool("_arguments");
+    _argptr = Lexer::idPool("_argptr");
+    _match = Lexer::idPool("_match");
+    LINE = Lexer::idPool("__LINE__");
+    FILE = Lexer::idPool("__FILE__");
+    DATE = Lexer::idPool("__DATE__");
+    TIME = Lexer::idPool("__TIME__");
+    TIMESTAMP = Lexer::idPool("__TIMESTAMP__");
+    VENDOR = Lexer::idPool("__VENDOR__");
+    VERSIONX = Lexer::idPool("__VERSION__");
+    nan = Lexer::idPool("nan");
+    infinity = Lexer::idPool("infinity");
+    dig = Lexer::idPool("dig");
+    epsilon = Lexer::idPool("epsilon");
+    mant_dig = Lexer::idPool("mant_dig");
+    max_10_exp = Lexer::idPool("max_10_exp");
+    max_exp = Lexer::idPool("max_exp");
+    min_10_exp = Lexer::idPool("min_10_exp");
+    min_exp = Lexer::idPool("min_exp");
+    re = Lexer::idPool("re");
+    im = Lexer::idPool("im");
+    C = Lexer::idPool("C");
+    D = Lexer::idPool("D");
+    Windows = Lexer::idPool("Windows");
+    Pascal = Lexer::idPool("Pascal");
+    System = Lexer::idPool("System");
+    exit = Lexer::idPool("exit");
+    success = Lexer::idPool("success");
+    failure = Lexer::idPool("failure");
+    keys = Lexer::idPool("keys");
+    values = Lexer::idPool("values");
+    rehash = Lexer::idPool("rehash");
+    sort = Lexer::idPool("sort");
+    reverse = Lexer::idPool("reverse");
+    dup = Lexer::idPool("dup");
+    idup = Lexer::idPool("idup");
+    ___out = Lexer::idPool("out");
+    ___in = Lexer::idPool("in");
+    __int = Lexer::idPool("int");
+    __dollar = Lexer::idPool("$");
+    __LOCAL_SIZE = Lexer::idPool("__LOCAL_SIZE");
+    uadd = Lexer::idPool("opPos");
+    neg = Lexer::idPool("opNeg");
+    com = Lexer::idPool("opCom");
+    add = Lexer::idPool("opAdd");
+    add_r = Lexer::idPool("opAdd_r");
+    sub = Lexer::idPool("opSub");
+    sub_r = Lexer::idPool("opSub_r");
+    mul = Lexer::idPool("opMul");
+    mul_r = Lexer::idPool("opMul_r");
+    div = Lexer::idPool("opDiv");
+    div_r = Lexer::idPool("opDiv_r");
+    mod = Lexer::idPool("opMod");
+    mod_r = Lexer::idPool("opMod_r");
+    eq = Lexer::idPool("opEquals");
+    cmp = Lexer::idPool("opCmp");
+    iand = Lexer::idPool("opAnd");
+    iand_r = Lexer::idPool("opAnd_r");
+    ior = Lexer::idPool("opOr");
+    ior_r = Lexer::idPool("opOr_r");
+    ixor = Lexer::idPool("opXor");
+    ixor_r = Lexer::idPool("opXor_r");
+    shl = Lexer::idPool("opShl");
+    shl_r = Lexer::idPool("opShl_r");
+    shr = Lexer::idPool("opShr");
+    shr_r = Lexer::idPool("opShr_r");
+    ushr = Lexer::idPool("opUShr");
+    ushr_r = Lexer::idPool("opUShr_r");
+    cat = Lexer::idPool("opCat");
+    cat_r = Lexer::idPool("opCat_r");
+    assign = Lexer::idPool("opAssign");
+    addass = Lexer::idPool("opAddAssign");
+    subass = Lexer::idPool("opSubAssign");
+    mulass = Lexer::idPool("opMulAssign");
+    divass = Lexer::idPool("opDivAssign");
+    modass = Lexer::idPool("opModAssign");
+    andass = Lexer::idPool("opAndAssign");
+    orass = Lexer::idPool("opOrAssign");
+    xorass = Lexer::idPool("opXorAssign");
+    shlass = Lexer::idPool("opShlAssign");
+    shrass = Lexer::idPool("opShrAssign");
+    ushrass = Lexer::idPool("opUShrAssign");
+    catass = Lexer::idPool("opCatAssign");
+    postinc = Lexer::idPool("opPostInc");
+    postdec = Lexer::idPool("opPostDec");
+    index = Lexer::idPool("opIndex");
+    indexass = Lexer::idPool("opIndexAssign");
+    slice = Lexer::idPool("opSlice");
+    sliceass = Lexer::idPool("opSliceAssign");
+    call = Lexer::idPool("opCall");
+    cast = Lexer::idPool("opCast");
+    match = Lexer::idPool("opMatch");
+    next = Lexer::idPool("opNext");
+    opIn = Lexer::idPool("opIn");
+    opIn_r = Lexer::idPool("opIn_r");
+    classNew = Lexer::idPool("new");
+    classDelete = Lexer::idPool("delete");
+    apply = Lexer::idPool("opApply");
+    applyReverse = Lexer::idPool("opApplyReverse");
+    adDup = Lexer::idPool("_adDupT");
+    adReverse = Lexer::idPool("_adReverse");
+    aaLen = Lexer::idPool("_aaLen");
+    aaKeys = Lexer::idPool("_aaKeys");
+    aaValues = Lexer::idPool("_aaValues");
+    aaRehash = Lexer::idPool("_aaRehash");
+    lib = Lexer::idPool("lib");
+    msg = Lexer::idPool("msg");
+    GNU_asm = Lexer::idPool("GNU_asm");
+    LLVM_intrinsic = Lexer::idPool("LLVM_intrinsic");
+    LLVM_internal = Lexer::idPool("LLVM_internal");
+    tohash = Lexer::idPool("toHash");
+    tostring = Lexer::idPool("toString");
+    alloca = Lexer::idPool("alloca");
+    main = Lexer::idPool("main");
+    WinMain = Lexer::idPool("WinMain");
+    DllMain = Lexer::idPool("DllMain");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/id.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,182 @@
+// File generated by idgen.c
+#ifndef DMD_ID_H
+#define DMD_ID_H 1
+struct Identifier;
+struct Id
+{
+    static Identifier *IUnknown;
+    static Identifier *Object;
+    static Identifier *object;
+    static Identifier *max;
+    static Identifier *min;
+    static Identifier *This;
+    static Identifier *ctor;
+    static Identifier *dtor;
+    static Identifier *classInvariant;
+    static Identifier *unitTest;
+    static Identifier *staticCtor;
+    static Identifier *staticDtor;
+    static Identifier *init;
+    static Identifier *size;
+    static Identifier *__sizeof;
+    static Identifier *alignof;
+    static Identifier *mangleof;
+    static Identifier *stringof;
+    static Identifier *tupleof;
+    static Identifier *length;
+    static Identifier *remove;
+    static Identifier *ptr;
+    static Identifier *funcptr;
+    static Identifier *dollar;
+    static Identifier *offset;
+    static Identifier *offsetof;
+    static Identifier *ModuleInfo;
+    static Identifier *ClassInfo;
+    static Identifier *classinfo;
+    static Identifier *typeinfo;
+    static Identifier *outer;
+    static Identifier *Exception;
+    static Identifier *withSym;
+    static Identifier *result;
+    static Identifier *returnLabel;
+    static Identifier *delegate;
+    static Identifier *line;
+    static Identifier *empty;
+    static Identifier *p;
+    static Identifier *coverage;
+    static Identifier *TypeInfo;
+    static Identifier *TypeInfo_Class;
+    static Identifier *TypeInfo_Interface;
+    static Identifier *TypeInfo_Struct;
+    static Identifier *TypeInfo_Enum;
+    static Identifier *TypeInfo_Typedef;
+    static Identifier *TypeInfo_Pointer;
+    static Identifier *TypeInfo_Array;
+    static Identifier *TypeInfo_StaticArray;
+    static Identifier *TypeInfo_AssociativeArray;
+    static Identifier *TypeInfo_Function;
+    static Identifier *TypeInfo_Delegate;
+    static Identifier *TypeInfo_Tuple;
+    static Identifier *TypeInfo_Const;
+    static Identifier *TypeInfo_Invariant;
+    static Identifier *elements;
+    static Identifier *_arguments_typeinfo;
+    static Identifier *_arguments;
+    static Identifier *_argptr;
+    static Identifier *_match;
+    static Identifier *LINE;
+    static Identifier *FILE;
+    static Identifier *DATE;
+    static Identifier *TIME;
+    static Identifier *TIMESTAMP;
+    static Identifier *VENDOR;
+    static Identifier *VERSIONX;
+    static Identifier *nan;
+    static Identifier *infinity;
+    static Identifier *dig;
+    static Identifier *epsilon;
+    static Identifier *mant_dig;
+    static Identifier *max_10_exp;
+    static Identifier *max_exp;
+    static Identifier *min_10_exp;
+    static Identifier *min_exp;
+    static Identifier *re;
+    static Identifier *im;
+    static Identifier *C;
+    static Identifier *D;
+    static Identifier *Windows;
+    static Identifier *Pascal;
+    static Identifier *System;
+    static Identifier *exit;
+    static Identifier *success;
+    static Identifier *failure;
+    static Identifier *keys;
+    static Identifier *values;
+    static Identifier *rehash;
+    static Identifier *sort;
+    static Identifier *reverse;
+    static Identifier *dup;
+    static Identifier *idup;
+    static Identifier *___out;
+    static Identifier *___in;
+    static Identifier *__int;
+    static Identifier *__dollar;
+    static Identifier *__LOCAL_SIZE;
+    static Identifier *uadd;
+    static Identifier *neg;
+    static Identifier *com;
+    static Identifier *add;
+    static Identifier *add_r;
+    static Identifier *sub;
+    static Identifier *sub_r;
+    static Identifier *mul;
+    static Identifier *mul_r;
+    static Identifier *div;
+    static Identifier *div_r;
+    static Identifier *mod;
+    static Identifier *mod_r;
+    static Identifier *eq;
+    static Identifier *cmp;
+    static Identifier *iand;
+    static Identifier *iand_r;
+    static Identifier *ior;
+    static Identifier *ior_r;
+    static Identifier *ixor;
+    static Identifier *ixor_r;
+    static Identifier *shl;
+    static Identifier *shl_r;
+    static Identifier *shr;
+    static Identifier *shr_r;
+    static Identifier *ushr;
+    static Identifier *ushr_r;
+    static Identifier *cat;
+    static Identifier *cat_r;
+    static Identifier *assign;
+    static Identifier *addass;
+    static Identifier *subass;
+    static Identifier *mulass;
+    static Identifier *divass;
+    static Identifier *modass;
+    static Identifier *andass;
+    static Identifier *orass;
+    static Identifier *xorass;
+    static Identifier *shlass;
+    static Identifier *shrass;
+    static Identifier *ushrass;
+    static Identifier *catass;
+    static Identifier *postinc;
+    static Identifier *postdec;
+    static Identifier *index;
+    static Identifier *indexass;
+    static Identifier *slice;
+    static Identifier *sliceass;
+    static Identifier *call;
+    static Identifier *cast;
+    static Identifier *match;
+    static Identifier *next;
+    static Identifier *opIn;
+    static Identifier *opIn_r;
+    static Identifier *classNew;
+    static Identifier *classDelete;
+    static Identifier *apply;
+    static Identifier *applyReverse;
+    static Identifier *adDup;
+    static Identifier *adReverse;
+    static Identifier *aaLen;
+    static Identifier *aaKeys;
+    static Identifier *aaValues;
+    static Identifier *aaRehash;
+    static Identifier *lib;
+    static Identifier *msg;
+    static Identifier *GNU_asm;
+    static Identifier *LLVM_intrinsic;
+    static Identifier *LLVM_internal;
+    static Identifier *tohash;
+    static Identifier *tostring;
+    static Identifier *alloca;
+    static Identifier *main;
+    static Identifier *WinMain;
+    static Identifier *DllMain;
+    static void initialize();
+};
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/identifier.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,89 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <string.h>
+
+#include "root.h"
+#include "identifier.h"
+#include "mars.h"
+#include "lexer.h"
+#include "id.h"
+
+Identifier::Identifier(const char *string, int value)
+{
+    //printf("Identifier('%s', %d)\n", string, value);
+    this->string = string;
+    this->value = value;
+    this->len = strlen(string);
+}
+
+hash_t Identifier::hashCode()
+{
+    return String::calcHash(string);
+}
+
+int Identifier::equals(Object *o)
+{
+    return this == o || memcmp(string,o->toChars(),len+1) == 0;
+}
+
+int Identifier::compare(Object *o)
+{
+    return memcmp(string, o->toChars(), len + 1);
+}
+
+char *Identifier::toChars()
+{
+    return (char *)string;
+}
+
+char *Identifier::toHChars2()
+{
+    char *p = NULL;
+
+    if (this == Id::ctor) p = "this";
+    else if (this == Id::dtor) p = "~this";
+    else if (this == Id::classInvariant) p = "invariant";
+    else if (this == Id::unitTest) p = "unittest";
+    else if (this == Id::staticCtor) p = "static this";
+    else if (this == Id::staticDtor) p = "static ~this";
+    else if (this == Id::dollar) p = "$";
+    else if (this == Id::withSym) p = "with";
+    else if (this == Id::result) p = "result";
+    else if (this == Id::returnLabel) p = "return";
+    else
+	p = toChars();
+
+    return p;
+}
+
+void Identifier::print()
+{
+    fprintf(stdmsg, "%s",string);
+}
+
+int Identifier::dyncast()
+{
+    return DYNCAST_IDENTIFIER;
+}
+
+Identifier *Identifier::generateId(char *prefix)
+{   OutBuffer buf;
+    char *id;
+    static unsigned i;
+
+    buf.writestring(prefix);
+    buf.printf("%u", ++i);
+
+    id = buf.toChars();
+    buf.data = NULL;
+    return new Identifier(id, TOKidentifier);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/identifier.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,46 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#ifndef DMD_IDENTIFIER_H
+#define DMD_IDENTIFIER_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include "root.h"
+
+namespace llvm
+{
+    class Value;
+}
+
+struct Identifier : Object
+{
+    int value;
+    const char *string;
+    unsigned len;
+
+    Identifier(const char *string, int value);
+    int equals(Object *o);
+    hash_t hashCode();
+    int compare(Object *o);
+    void print();
+    char *toChars();
+#ifdef _DH
+    char *toHChars();
+#endif
+    char *toHChars2();
+    int dyncast();
+
+    static Identifier *generateId(char *prefix);
+};
+
+#endif /* DMD_IDENTIFIER_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/idgen.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,304 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+// Program to generate string files in d data structures.
+// Saves much tedious typing, and eliminates typo problems.
+// Generates:
+//	id.h
+//	id.c
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <assert.h>
+
+struct Msgtable
+{
+	char *ident;	// name to use in DMD source
+	char *name;	// name in D executable
+};
+
+Msgtable msgtable[] =
+{
+    { "IUnknown" },
+    { "Object" },
+    { "object" },
+    { "max" },
+    { "min" },
+    { "This", "this" },
+    { "ctor", "_ctor" },
+    { "dtor", "_dtor" },
+    { "classInvariant", "__invariant" },
+    { "unitTest", "_unitTest" },
+    { "staticCtor", "_staticCtor" },
+    { "staticDtor", "_staticDtor" },
+    { "init" },
+    { "size" },
+    { "__sizeof", "sizeof" },
+    { "alignof" },
+    { "mangleof" },
+    { "stringof" },
+    { "tupleof" },
+    { "length" },
+    { "remove" },
+    { "ptr" },
+    { "funcptr" },
+    { "dollar", "__dollar" },
+    { "offset" },
+    { "offsetof" },
+    { "ModuleInfo" },
+    { "ClassInfo" },
+    { "classinfo" },
+    { "typeinfo" },
+    { "outer" },
+    { "Exception" },
+    { "withSym", "__withSym" },
+    { "result", "__result" },
+    { "returnLabel", "__returnLabel" },
+    { "delegate" },
+    { "line" },
+    { "empty", "" },
+    { "p" },
+    { "coverage", "__coverage" },
+
+    { "TypeInfo" },
+    { "TypeInfo_Class" },
+    { "TypeInfo_Interface" },
+    { "TypeInfo_Struct" },
+    { "TypeInfo_Enum" },
+    { "TypeInfo_Typedef" },
+    { "TypeInfo_Pointer" },
+    { "TypeInfo_Array" },
+    { "TypeInfo_StaticArray" },
+    { "TypeInfo_AssociativeArray" },
+    { "TypeInfo_Function" },
+    { "TypeInfo_Delegate" },
+    { "TypeInfo_Tuple" },
+    { "TypeInfo_Const" },
+    { "TypeInfo_Invariant" },
+    { "elements" },
+    { "_arguments_typeinfo" },
+    { "_arguments" },
+    { "_argptr" },
+    { "_match" },
+
+    { "LINE", "__LINE__" },
+    { "FILE", "__FILE__" },
+    { "DATE", "__DATE__" },
+    { "TIME", "__TIME__" },
+    { "TIMESTAMP", "__TIMESTAMP__" },
+    { "VENDOR", "__VENDOR__" },
+    { "VERSIONX", "__VERSION__" },
+
+    { "nan" },
+    { "infinity" },
+    { "dig" },
+    { "epsilon" },
+    { "mant_dig" },
+    { "max_10_exp" },
+    { "max_exp" },
+    { "min_10_exp" },
+    { "min_exp" },
+    { "re" },
+    { "im" },
+
+    { "C" },
+    { "D" },
+    { "Windows" },
+    { "Pascal" },
+    { "System" },
+
+    { "exit" },
+    { "success" },
+    { "failure" },
+
+    { "keys" },
+    { "values" },
+    { "rehash" },
+
+    { "sort" },
+    { "reverse" },
+    { "dup" },
+    { "idup" },
+
+    // For inline assembler
+    { "___out", "out" },
+    { "___in", "in" },
+    { "__int", "int" },
+    { "__dollar", "$" },
+    { "__LOCAL_SIZE" },
+
+    // For operator overloads
+    { "uadd",	 "opPos" },
+    { "neg",     "opNeg" },
+    { "com",     "opCom" },
+    { "add",     "opAdd" },
+    { "add_r",   "opAdd_r" },
+    { "sub",     "opSub" },
+    { "sub_r",   "opSub_r" },
+    { "mul",     "opMul" },
+    { "mul_r",   "opMul_r" },
+    { "div",     "opDiv" },
+    { "div_r",   "opDiv_r" },
+    { "mod",     "opMod" },
+    { "mod_r",   "opMod_r" },
+    { "eq",      "opEquals" },
+    { "cmp",     "opCmp" },
+    { "iand",    "opAnd" },
+    { "iand_r",  "opAnd_r" },
+    { "ior",     "opOr" },
+    { "ior_r",   "opOr_r" },
+    { "ixor",    "opXor" },
+    { "ixor_r",  "opXor_r" },
+    { "shl",     "opShl" },
+    { "shl_r",   "opShl_r" },
+    { "shr",     "opShr" },
+    { "shr_r",   "opShr_r" },
+    { "ushr",    "opUShr" },
+    { "ushr_r",  "opUShr_r" },
+    { "cat",     "opCat" },
+    { "cat_r",   "opCat_r" },
+    { "assign",  "opAssign" },
+    { "addass",  "opAddAssign" },
+    { "subass",  "opSubAssign" },
+    { "mulass",  "opMulAssign" },
+    { "divass",  "opDivAssign" },
+    { "modass",  "opModAssign" },
+    { "andass",  "opAndAssign" },
+    { "orass",   "opOrAssign" },
+    { "xorass",  "opXorAssign" },
+    { "shlass",  "opShlAssign" },
+    { "shrass",  "opShrAssign" },
+    { "ushrass", "opUShrAssign" },
+    { "catass",  "opCatAssign" },
+    { "postinc", "opPostInc" },
+    { "postdec", "opPostDec" },
+    { "index",	 "opIndex" },
+    { "indexass", "opIndexAssign" },
+    { "slice",	 "opSlice" },
+    { "sliceass", "opSliceAssign" },
+    { "call",	 "opCall" },
+    { "cast",	 "opCast" },
+    { "match",	 "opMatch" },
+    { "next",	 "opNext" },
+    { "opIn" },
+    { "opIn_r" },
+
+    { "classNew", "new" },
+    { "classDelete", "delete" },
+
+    // For foreach
+    { "apply", "opApply" },
+    { "applyReverse", "opApplyReverse" },
+
+    { "adDup", "_adDupT" },
+    { "adReverse", "_adReverse" },
+
+    // For internal functions
+    { "aaLen", "_aaLen" },
+    { "aaKeys", "_aaKeys" },
+    { "aaValues", "_aaValues" },
+    { "aaRehash", "_aaRehash" },
+
+    // For pragma's
+    { "lib" },
+    { "msg" },
+    { "GNU_asm" },
+    { "LLVM_intrinsic" },
+    { "LLVM_internal" },
+
+    // For toHash/toString
+    { "tohash", "toHash" },
+    { "tostring", "toString" },
+
+    // Special functions
+    { "alloca" },
+    { "main" },
+    { "WinMain" },
+    { "DllMain" },
+};
+
+
+int main()
+{
+    FILE *fp;
+    unsigned i;
+
+    {
+	fp = fopen("id.h","w");
+	if (!fp)
+	{   printf("can't open id.h\n");
+	    exit(EXIT_FAILURE);
+	}
+
+	fprintf(fp, "// File generated by idgen.c\n");
+#if __DMC__
+	fprintf(fp, "#pragma once\n");
+#endif
+	fprintf(fp, "#ifndef DMD_ID_H\n");
+	fprintf(fp, "#define DMD_ID_H 1\n");
+	fprintf(fp, "struct Identifier;\n");
+	fprintf(fp, "struct Id\n");
+	fprintf(fp, "{\n");
+
+	for (i = 0; i < sizeof(msgtable) / sizeof(msgtable[0]); i++)
+	{   char *id = msgtable[i].ident;
+
+	    fprintf(fp,"    static Identifier *%s;\n", id);
+	}
+
+	fprintf(fp, "    static void initialize();\n");
+	fprintf(fp, "};\n");
+	fprintf(fp, "#endif\n");
+
+	fclose(fp);
+    }
+
+    {
+	fp = fopen("id.c","w");
+	if (!fp)
+	{   printf("can't open id.c\n");
+	    exit(EXIT_FAILURE);
+	}
+
+	fprintf(fp, "// File generated by idgen.c\n");
+	fprintf(fp, "#include \"id.h\"\n");
+	fprintf(fp, "#include \"identifier.h\"\n");
+	fprintf(fp, "#include \"lexer.h\"\n");
+
+	for (i = 0; i < sizeof(msgtable) / sizeof(msgtable[0]); i++)
+	{   char *id = msgtable[i].ident;
+	    char *p = msgtable[i].name;
+
+	    if (!p)
+		p = id;
+	    fprintf(fp,"Identifier *Id::%s;\n", id);
+	}
+
+	fprintf(fp, "void Id::initialize()\n");
+	fprintf(fp, "{\n");
+
+	for (i = 0; i < sizeof(msgtable) / sizeof(msgtable[0]); i++)
+	{   char *id = msgtable[i].ident;
+	    char *p = msgtable[i].name;
+
+	    if (!p)
+		p = id;
+	    fprintf(fp,"    %s = Lexer::idPool(\"%s\");\n", id, p);
+	}
+
+	fprintf(fp, "}\n");
+
+	fclose(fp);
+    }
+
+    return EXIT_SUCCESS;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/impcnvgen.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,440 @@
+
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "mtype.h"
+
+enum TY impcnvResult[TMAX][TMAX];
+enum TY impcnvType1[TMAX][TMAX];
+enum TY impcnvType2[TMAX][TMAX];
+int impcnvWarn[TMAX][TMAX];
+
+int integral_promotion(int t)
+{
+    switch (t)
+    {
+	case Tchar:
+	case Twchar:
+	case Tbit:
+	case Tbool:
+	case Tint8:
+	case Tuns8:
+	case Tint16:
+	case Tuns16:	return Tint32;
+	case Tdchar:	return Tuns32;
+	default:	return t;
+    }
+}
+
+void init()
+{   int i, j;
+
+    // Set conversion tables
+    for (i = 0; i < TMAX; i++)
+	for (j = 0; j < TMAX; j++)
+	{   impcnvResult[i][j] = Terror;
+	    impcnvType1[i][j] = Terror;
+	    impcnvType2[i][j] = Terror;
+	    impcnvWarn[i][j] = 0;
+	}
+
+#define X(t1,t2, nt1,nt2, rt)		\
+	impcnvResult[t1][t2] = rt;	\
+	impcnvType1[t1][t2] = nt1;	\
+	impcnvType2[t1][t2] = nt2;
+
+    /* ======================= */
+
+    X(Tbit,Tbit,    Tint32,Tint32,  Tint32)
+    X(Tbit,Tint8,   Tint32,Tint32,  Tint32)
+    X(Tbit,Tuns8,   Tint32,Tint32,  Tint32)
+    X(Tbit,Tint16,  Tint32,Tint32,  Tint32)
+    X(Tbit,Tuns16,  Tint32,Tint32,  Tint32)
+    X(Tbit,Tint32,  Tint32,Tint32,  Tint32)
+    X(Tbit,Tuns32,  Tuns32,Tuns32,  Tuns32)
+    X(Tbit,Tint64,  Tint64,Tint64,  Tint64)
+    X(Tbit,Tuns64,  Tuns64,Tuns64,  Tuns64)
+
+    X(Tbit,Tfloat32,     Tfloat32,Tfloat32,     Tfloat32)
+    X(Tbit,Tfloat64,     Tfloat64,Tfloat64,     Tfloat64)
+    X(Tbit,Tfloat80,     Tfloat80,Tfloat80,     Tfloat80)
+    X(Tbit,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
+    X(Tbit,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
+    X(Tbit,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
+    X(Tbit,Tcomplex32,   Tfloat32,Tcomplex32,   Tcomplex32)
+    X(Tbit,Tcomplex64,   Tfloat64,Tcomplex64,   Tcomplex64)
+    X(Tbit,Tcomplex80,   Tfloat80,Tcomplex80,   Tcomplex80)
+
+    /* ======================= */
+
+    X(Tbool,Tbool,   Tbool,Tbool,    Tbool)
+    X(Tbool,Tint8,   Tint32,Tint32,  Tint32)
+    X(Tbool,Tuns8,   Tint32,Tint32,  Tint32)
+    X(Tbool,Tint16,  Tint32,Tint32,  Tint32)
+    X(Tbool,Tuns16,  Tint32,Tint32,  Tint32)
+    X(Tbool,Tint32,  Tint32,Tint32,  Tint32)
+    X(Tbool,Tuns32,  Tuns32,Tuns32,  Tuns32)
+    X(Tbool,Tint64,  Tint64,Tint64,  Tint64)
+    X(Tbool,Tuns64,  Tuns64,Tuns64,  Tuns64)
+
+    X(Tbool,Tfloat32,     Tfloat32,Tfloat32,     Tfloat32)
+    X(Tbool,Tfloat64,     Tfloat64,Tfloat64,     Tfloat64)
+    X(Tbool,Tfloat80,     Tfloat80,Tfloat80,     Tfloat80)
+    X(Tbool,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
+    X(Tbool,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
+    X(Tbool,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
+    X(Tbool,Tcomplex32,   Tfloat32,Tcomplex32,   Tcomplex32)
+    X(Tbool,Tcomplex64,   Tfloat64,Tcomplex64,   Tcomplex64)
+    X(Tbool,Tcomplex80,   Tfloat80,Tcomplex80,   Tcomplex80)
+
+    /* ======================= */
+
+    X(Tint8,Tint8,   Tint32,Tint32,  Tint32)
+    X(Tint8,Tuns8,   Tint32,Tint32,  Tint32)
+    X(Tint8,Tint16,  Tint32,Tint32,  Tint32)
+    X(Tint8,Tuns16,  Tint32,Tint32,  Tint32)
+    X(Tint8,Tint32,  Tint32,Tint32,  Tint32)
+    X(Tint8,Tuns32,  Tuns32,Tuns32,  Tuns32)
+    X(Tint8,Tint64,  Tint64,Tint64,  Tint64)
+    X(Tint8,Tuns64,  Tuns64,Tuns64,  Tuns64)
+
+    X(Tint8,Tfloat32,     Tfloat32,Tfloat32,     Tfloat32)
+    X(Tint8,Tfloat64,     Tfloat64,Tfloat64,     Tfloat64)
+    X(Tint8,Tfloat80,     Tfloat80,Tfloat80,     Tfloat80)
+    X(Tint8,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
+    X(Tint8,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
+    X(Tint8,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
+    X(Tint8,Tcomplex32,   Tfloat32,Tcomplex32,   Tcomplex32)
+    X(Tint8,Tcomplex64,   Tfloat64,Tcomplex64,   Tcomplex64)
+    X(Tint8,Tcomplex80,   Tfloat80,Tcomplex80,   Tcomplex80)
+
+    /* ======================= */
+
+    X(Tuns8,Tuns8,   Tint32,Tint32,  Tint32)
+    X(Tuns8,Tint16,  Tint32,Tint32,  Tint32)
+    X(Tuns8,Tuns16,  Tint32,Tint32,  Tint32)
+    X(Tuns8,Tint32,  Tint32,Tint32,  Tint32)
+    X(Tuns8,Tuns32,  Tuns32,Tuns32,  Tuns32)
+    X(Tuns8,Tint64,  Tint64,Tint64,  Tint64)
+    X(Tuns8,Tuns64,  Tuns64,Tuns64,  Tuns64)
+
+    X(Tuns8,Tfloat32,     Tfloat32,Tfloat32,     Tfloat32)
+    X(Tuns8,Tfloat64,     Tfloat64,Tfloat64,     Tfloat64)
+    X(Tuns8,Tfloat80,     Tfloat80,Tfloat80,     Tfloat80)
+    X(Tuns8,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
+    X(Tuns8,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
+    X(Tuns8,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
+    X(Tuns8,Tcomplex32,   Tfloat32,Tcomplex32,   Tcomplex32)
+    X(Tuns8,Tcomplex64,   Tfloat64,Tcomplex64,   Tcomplex64)
+    X(Tuns8,Tcomplex80,   Tfloat80,Tcomplex80,   Tcomplex80)
+
+    /* ======================= */
+
+    X(Tint16,Tint16,  Tint32,Tint32,  Tint32)
+    X(Tint16,Tuns16,  Tint32,Tint32,  Tint32)
+    X(Tint16,Tint32,  Tint32,Tint32,  Tint32)
+    X(Tint16,Tuns32,  Tuns32,Tuns32,  Tuns32)
+    X(Tint16,Tint64,  Tint64,Tint64,  Tint64)
+    X(Tint16,Tuns64,  Tuns64,Tuns64,  Tuns64)
+
+    X(Tint16,Tfloat32,     Tfloat32,Tfloat32,     Tfloat32)
+    X(Tint16,Tfloat64,     Tfloat64,Tfloat64,     Tfloat64)
+    X(Tint16,Tfloat80,     Tfloat80,Tfloat80,     Tfloat80)
+    X(Tint16,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
+    X(Tint16,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
+    X(Tint16,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
+    X(Tint16,Tcomplex32,   Tfloat32,Tcomplex32,   Tcomplex32)
+    X(Tint16,Tcomplex64,   Tfloat64,Tcomplex64,   Tcomplex64)
+    X(Tint16,Tcomplex80,   Tfloat80,Tcomplex80,   Tcomplex80)
+
+    /* ======================= */
+
+    X(Tuns16,Tuns16,  Tint32,Tint32,  Tint32)
+    X(Tuns16,Tint32,  Tint32,Tint32,  Tint32)
+    X(Tuns16,Tuns32,  Tuns32,Tuns32,  Tuns32)
+    X(Tuns16,Tint64,  Tint64,Tint64,  Tint64)
+    X(Tuns16,Tuns64,  Tuns64,Tuns64,  Tuns64)
+
+    X(Tuns16,Tfloat32,     Tfloat32,Tfloat32,     Tfloat32)
+    X(Tuns16,Tfloat64,     Tfloat64,Tfloat64,     Tfloat64)
+    X(Tuns16,Tfloat80,     Tfloat80,Tfloat80,     Tfloat80)
+    X(Tuns16,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
+    X(Tuns16,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
+    X(Tuns16,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
+    X(Tuns16,Tcomplex32,   Tfloat32,Tcomplex32,   Tcomplex32)
+    X(Tuns16,Tcomplex64,   Tfloat64,Tcomplex64,   Tcomplex64)
+    X(Tuns16,Tcomplex80,   Tfloat80,Tcomplex80,   Tcomplex80)
+
+    /* ======================= */
+
+    X(Tint32,Tint32,  Tint32,Tint32,  Tint32)
+    X(Tint32,Tuns32,  Tuns32,Tuns32,  Tuns32)
+    X(Tint32,Tint64,  Tint64,Tint64,  Tint64)
+    X(Tint32,Tuns64,  Tuns64,Tuns64,  Tuns64)
+
+    X(Tint32,Tfloat32,     Tfloat32,Tfloat32,     Tfloat32)
+    X(Tint32,Tfloat64,     Tfloat64,Tfloat64,     Tfloat64)
+    X(Tint32,Tfloat80,     Tfloat80,Tfloat80,     Tfloat80)
+    X(Tint32,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
+    X(Tint32,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
+    X(Tint32,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
+    X(Tint32,Tcomplex32,   Tfloat32,Tcomplex32,   Tcomplex32)
+    X(Tint32,Tcomplex64,   Tfloat64,Tcomplex64,   Tcomplex64)
+    X(Tint32,Tcomplex80,   Tfloat80,Tcomplex80,   Tcomplex80)
+
+    /* ======================= */
+
+    X(Tuns32,Tuns32,  Tuns32,Tuns32,  Tuns32)
+    X(Tuns32,Tint64,  Tint64,Tint64,  Tint64)
+    X(Tuns32,Tuns64,  Tuns64,Tuns64,  Tuns64)
+
+    X(Tuns32,Tfloat32,     Tfloat32,Tfloat32,     Tfloat32)
+    X(Tuns32,Tfloat64,     Tfloat64,Tfloat64,     Tfloat64)
+    X(Tuns32,Tfloat80,     Tfloat80,Tfloat80,     Tfloat80)
+    X(Tuns32,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
+    X(Tuns32,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
+    X(Tuns32,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
+    X(Tuns32,Tcomplex32,   Tfloat32,Tcomplex32,   Tcomplex32)
+    X(Tuns32,Tcomplex64,   Tfloat64,Tcomplex64,   Tcomplex64)
+    X(Tuns32,Tcomplex80,   Tfloat80,Tcomplex80,   Tcomplex80)
+
+    /* ======================= */
+
+    X(Tint64,Tint64,  Tint64,Tint64,  Tint64)
+    X(Tint64,Tuns64,  Tuns64,Tuns64,  Tuns64)
+
+    X(Tint64,Tfloat32,     Tfloat32,Tfloat32,     Tfloat32)
+    X(Tint64,Tfloat64,     Tfloat64,Tfloat64,     Tfloat64)
+    X(Tint64,Tfloat80,     Tfloat80,Tfloat80,     Tfloat80)
+    X(Tint64,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
+    X(Tint64,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
+    X(Tint64,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
+    X(Tint64,Tcomplex32,   Tfloat32,Tcomplex32,   Tcomplex32)
+    X(Tint64,Tcomplex64,   Tfloat64,Tcomplex64,   Tcomplex64)
+    X(Tint64,Tcomplex80,   Tfloat80,Tcomplex80,   Tcomplex80)
+
+    /* ======================= */
+
+    X(Tuns64,Tuns64,  Tuns64,Tuns64,  Tuns64)
+
+    X(Tuns64,Tfloat32,     Tfloat32,Tfloat32,     Tfloat32)
+    X(Tuns64,Tfloat64,     Tfloat64,Tfloat64,     Tfloat64)
+    X(Tuns64,Tfloat80,     Tfloat80,Tfloat80,     Tfloat80)
+    X(Tuns64,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
+    X(Tuns64,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
+    X(Tuns64,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
+    X(Tuns64,Tcomplex32,   Tfloat32,Tcomplex32,   Tcomplex32)
+    X(Tuns64,Tcomplex64,   Tfloat64,Tcomplex64,   Tcomplex64)
+    X(Tuns64,Tcomplex80,   Tfloat80,Tcomplex80,   Tcomplex80)
+
+    /* ======================= */
+
+    X(Tfloat32,Tfloat32,  Tfloat32,Tfloat32, Tfloat32)
+    X(Tfloat32,Tfloat64,  Tfloat64,Tfloat64, Tfloat64)
+    X(Tfloat32,Tfloat80,  Tfloat80,Tfloat80, Tfloat80)
+
+    X(Tfloat32,Timaginary32,  Tfloat32,Timaginary32, Tfloat32)
+    X(Tfloat32,Timaginary64,  Tfloat64,Timaginary64, Tfloat64)
+    X(Tfloat32,Timaginary80,  Tfloat80,Timaginary80, Tfloat80)
+
+    X(Tfloat32,Tcomplex32,  Tfloat32,Tcomplex32, Tcomplex32)
+    X(Tfloat32,Tcomplex64,  Tfloat64,Tcomplex64, Tcomplex64)
+    X(Tfloat32,Tcomplex80,  Tfloat80,Tcomplex80, Tcomplex80)
+
+    /* ======================= */
+
+    X(Tfloat64,Tfloat64,  Tfloat64,Tfloat64, Tfloat64)
+    X(Tfloat64,Tfloat80,  Tfloat80,Tfloat80, Tfloat80)
+
+    X(Tfloat64,Timaginary32,  Tfloat64,Timaginary64, Tfloat64)
+    X(Tfloat64,Timaginary64,  Tfloat64,Timaginary64, Tfloat64)
+    X(Tfloat64,Timaginary80,  Tfloat80,Timaginary80, Tfloat80)
+
+    X(Tfloat64,Tcomplex32,  Tfloat64,Tcomplex64, Tcomplex64)
+    X(Tfloat64,Tcomplex64,  Tfloat64,Tcomplex64, Tcomplex64)
+    X(Tfloat64,Tcomplex80,  Tfloat80,Tcomplex80, Tcomplex80)
+
+    /* ======================= */
+
+    X(Tfloat80,Tfloat80,  Tfloat80,Tfloat80, Tfloat80)
+
+    X(Tfloat80,Timaginary32,  Tfloat80,Timaginary80, Tfloat80)
+    X(Tfloat80,Timaginary64,  Tfloat80,Timaginary80, Tfloat80)
+    X(Tfloat80,Timaginary80,  Tfloat80,Timaginary80, Tfloat80)
+
+    X(Tfloat80,Tcomplex32,  Tfloat80,Tcomplex80, Tcomplex80)
+    X(Tfloat80,Tcomplex64,  Tfloat80,Tcomplex80, Tcomplex80)
+    X(Tfloat80,Tcomplex80,  Tfloat80,Tcomplex80, Tcomplex80)
+
+    /* ======================= */
+
+    X(Timaginary32,Timaginary32,  Timaginary32,Timaginary32, Timaginary32)
+    X(Timaginary32,Timaginary64,  Timaginary64,Timaginary64, Timaginary64)
+    X(Timaginary32,Timaginary80,  Timaginary80,Timaginary80, Timaginary80)
+
+    X(Timaginary32,Tcomplex32,  Timaginary32,Tcomplex32, Tcomplex32)
+    X(Timaginary32,Tcomplex64,  Timaginary64,Tcomplex64, Tcomplex64)
+    X(Timaginary32,Tcomplex80,  Timaginary80,Tcomplex80, Tcomplex80)
+
+    /* ======================= */
+
+    X(Timaginary64,Timaginary64,  Timaginary64,Timaginary64, Timaginary64)
+    X(Timaginary64,Timaginary80,  Timaginary80,Timaginary80, Timaginary80)
+
+    X(Timaginary64,Tcomplex32,  Timaginary64,Tcomplex64, Tcomplex64)
+    X(Timaginary64,Tcomplex64,  Timaginary64,Tcomplex64, Tcomplex64)
+    X(Timaginary64,Tcomplex80,  Timaginary80,Tcomplex80, Tcomplex80)
+
+    /* ======================= */
+
+    X(Timaginary80,Timaginary80,  Timaginary80,Timaginary80, Timaginary80)
+
+    X(Timaginary80,Tcomplex32,  Timaginary80,Tcomplex80, Tcomplex80)
+    X(Timaginary80,Tcomplex64,  Timaginary80,Tcomplex80, Tcomplex80)
+    X(Timaginary80,Tcomplex80,  Timaginary80,Tcomplex80, Tcomplex80)
+
+    /* ======================= */
+
+    X(Tcomplex32,Tcomplex32,  Tcomplex32,Tcomplex32, Tcomplex32)
+    X(Tcomplex32,Tcomplex64,  Tcomplex64,Tcomplex64, Tcomplex64)
+    X(Tcomplex32,Tcomplex80,  Tcomplex80,Tcomplex80, Tcomplex80)
+
+    /* ======================= */
+
+    X(Tcomplex64,Tcomplex64,  Tcomplex64,Tcomplex64, Tcomplex64)
+    X(Tcomplex64,Tcomplex80,  Tcomplex80,Tcomplex80, Tcomplex80)
+
+    /* ======================= */
+
+    X(Tcomplex80,Tcomplex80,  Tcomplex80,Tcomplex80, Tcomplex80)
+
+#undef X
+
+#define Y(t1,t2)	impcnvWarn[t1][t2] = 1;
+    Y(Tint8, Tbit)
+    Y(Tuns8, Tbit)
+    Y(Tint16, Tbit)
+    Y(Tuns16, Tbit)
+    Y(Tint32, Tbit)
+    Y(Tuns32, Tbit)
+    Y(Tint64, Tbit)
+    Y(Tuns64, Tbit)
+
+    Y(Tuns8, Tint8)
+    Y(Tint16, Tint8)
+    Y(Tuns16, Tint8)
+    Y(Tint32, Tint8)
+    Y(Tuns32, Tint8)
+    Y(Tint64, Tint8)
+    Y(Tuns64, Tint8)
+
+    Y(Tint8, Tuns8)
+    Y(Tint16, Tuns8)
+    Y(Tuns16, Tuns8)
+    Y(Tint32, Tuns8)
+    Y(Tuns32, Tuns8)
+    Y(Tint64, Tuns8)
+    Y(Tuns64, Tuns8)
+
+    Y(Tuns16, Tint16)
+    Y(Tint32, Tint16)
+    Y(Tuns32, Tint16)
+    Y(Tint64, Tint16)
+    Y(Tuns64, Tint16)
+
+    Y(Tint16, Tuns16)
+    Y(Tint32, Tuns16)
+    Y(Tuns32, Tuns16)
+    Y(Tint64, Tuns16)
+    Y(Tuns64, Tuns16)
+
+//    Y(Tuns32, Tint32)
+    Y(Tint64, Tint32)
+    Y(Tuns64, Tint32)
+
+//    Y(Tint32, Tuns32)
+    Y(Tint64, Tuns32)
+    Y(Tuns64, Tuns32)
+
+    Y(Tint64, Tuns64)
+    Y(Tuns64, Tint64)
+
+    for (i = 0; i < TMAX; i++)
+	for (j = 0; j < TMAX; j++)
+	{
+	    if (impcnvResult[i][j] == Terror)
+	    {
+		impcnvResult[i][j] = impcnvResult[j][i];
+		impcnvType1[i][j] = impcnvType2[j][i];
+		impcnvType2[i][j] = impcnvType1[j][i];
+	    }
+	}
+}
+
+int main()
+{   FILE *fp;
+    int i;
+    int j;
+
+    init();
+
+    fp = fopen("impcnvtab.c","w");
+
+    fprintf(fp,"// This file is generated by impcnvgen.c\n");
+    fprintf(fp,"#include \"mtype.h\"\n");
+
+    fprintf(fp,"unsigned char Type::impcnvResult[TMAX][TMAX] =\n{\n");
+    for (i = 0; i < TMAX; i++)
+    {
+	for (j = 0; j < TMAX; j++)
+	{
+	    fprintf(fp, "%d,",impcnvResult[i][j]);
+	}
+	fprintf(fp, "\n");
+    }
+    fprintf(fp,"};\n");
+
+    fprintf(fp,"unsigned char Type::impcnvType1[TMAX][TMAX] =\n{\n");
+    for (i = 0; i < TMAX; i++)
+    {
+	for (j = 0; j < TMAX; j++)
+	{
+	    fprintf(fp, "%d,",impcnvType1[i][j]);
+	}
+	fprintf(fp, "\n");
+    }
+    fprintf(fp,"};\n");
+
+    fprintf(fp,"unsigned char Type::impcnvType2[TMAX][TMAX] =\n{\n");
+    for (i = 0; i < TMAX; i++)
+    {
+	for (j = 0; j < TMAX; j++)
+	{
+	    fprintf(fp, "%d,",impcnvType2[i][j]);
+	}
+	fprintf(fp, "\n");
+    }
+    fprintf(fp,"};\n");
+
+    fprintf(fp,"unsigned char Type::impcnvWarn[TMAX][TMAX] =\n{\n");
+    for (i = 0; i < TMAX; i++)
+    {
+	for (j = 0; j < TMAX; j++)
+	{
+	    fprintf(fp, "%d,",impcnvWarn[i][j]);
+	}
+	fprintf(fp, "\n");
+    }
+    fprintf(fp,"};\n");
+
+    fclose(fp);
+    return EXIT_SUCCESS;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/impcnvtab.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,178 @@
+// This file is generated by impcnvgen.c
+#include "mtype.h"
+unsigned char Type::impcnvResult[TMAX][TMAX] =
+{
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,18,18,18,18,18,19,20,21,22,23,24,22,23,24,28,29,30,18,18,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,18,18,18,18,18,19,20,21,22,23,24,22,23,24,28,29,30,18,18,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,18,18,18,18,18,19,20,21,22,23,24,22,23,24,28,29,30,18,18,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,18,18,18,18,18,19,20,21,22,23,24,22,23,24,28,29,30,18,18,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,18,18,18,18,18,19,20,21,22,23,24,22,23,24,28,29,30,18,18,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,19,19,19,19,19,19,20,21,22,23,24,22,23,24,28,29,30,19,19,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,20,20,20,20,20,20,20,21,22,23,24,22,23,24,28,29,30,20,20,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,21,21,21,21,21,21,21,21,22,23,24,22,23,24,28,29,30,21,21,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,22,22,22,22,22,22,22,22,22,23,24,22,23,24,28,29,30,22,22,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,23,23,23,23,23,23,23,23,23,23,24,23,23,24,29,29,30,23,23,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,24,24,24,24,24,24,24,24,24,24,24,24,24,24,30,30,30,24,24,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,22,22,22,22,22,22,22,22,22,23,24,25,26,27,28,29,30,22,22,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,23,23,23,23,23,23,23,23,23,23,24,26,26,27,29,29,30,23,23,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,24,24,24,24,24,24,24,24,24,24,24,27,27,27,30,30,30,24,24,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,28,28,28,28,28,28,28,28,28,29,30,28,29,30,28,29,30,28,28,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,29,29,29,29,29,29,29,29,29,29,30,29,29,30,29,29,30,29,29,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,18,18,18,18,18,19,20,21,22,23,24,22,23,24,28,29,30,18,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,18,18,18,18,18,19,20,21,22,23,24,22,23,24,28,29,30,36,32,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+};
+unsigned char Type::impcnvType1[TMAX][TMAX] =
+{
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,18,18,18,18,18,19,20,21,22,23,24,22,23,24,22,23,24,18,18,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,18,18,18,18,18,19,20,21,22,23,24,22,23,24,22,23,24,18,18,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,18,18,18,18,18,19,20,21,22,23,24,22,23,24,22,23,24,18,18,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,18,18,18,18,18,19,20,21,22,23,24,22,23,24,22,23,24,18,18,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,18,18,18,18,18,19,20,21,22,23,24,22,23,24,22,23,24,18,18,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,19,19,19,19,19,19,20,21,22,23,24,22,23,24,22,23,24,19,19,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,20,20,20,20,20,20,20,21,22,23,24,22,23,24,22,23,24,20,20,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,21,21,21,21,21,21,21,21,22,23,24,22,23,24,22,23,24,21,21,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,22,22,22,22,22,22,22,22,22,23,24,22,23,24,22,23,24,22,22,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,23,23,23,23,23,23,23,23,23,23,24,23,23,24,23,23,24,23,23,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,25,25,25,25,25,25,25,25,25,26,27,25,26,27,25,26,27,25,25,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,26,26,26,26,26,26,26,26,26,26,27,26,26,27,26,26,27,26,26,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,28,28,28,28,28,28,28,28,28,29,30,28,29,30,28,29,30,28,28,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,29,29,29,29,29,29,29,29,29,29,30,29,29,30,29,29,30,29,29,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,18,18,18,18,18,19,20,21,22,23,24,22,23,24,22,23,24,18,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,18,18,18,18,18,19,20,21,22,23,24,22,23,24,22,23,24,36,32,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+};
+unsigned char Type::impcnvType2[TMAX][TMAX] =
+{
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,18,18,18,18,18,19,20,21,22,23,24,25,26,27,28,29,30,18,18,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,18,18,18,18,18,19,20,21,22,23,24,25,26,27,28,29,30,18,18,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,18,18,18,18,18,19,20,21,22,23,24,25,26,27,28,29,30,18,18,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,18,18,18,18,18,19,20,21,22,23,24,25,26,27,28,29,30,18,18,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,18,18,18,18,18,19,20,21,22,23,24,25,26,27,28,29,30,18,18,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,19,19,19,19,19,19,20,21,22,23,24,25,26,27,28,29,30,19,19,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,20,20,20,20,20,20,20,21,22,23,24,25,26,27,28,29,30,20,20,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,21,21,21,21,21,21,21,21,22,23,24,25,26,27,28,29,30,21,21,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,22,22,22,22,22,22,22,22,22,23,24,25,26,27,28,29,30,22,22,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,23,23,23,23,23,23,23,23,23,23,24,26,26,27,29,29,30,23,23,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,24,24,24,24,24,24,24,24,24,24,24,27,27,27,30,30,30,24,24,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,22,22,22,22,22,22,22,22,22,23,24,25,26,27,28,29,30,22,22,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,23,23,23,23,23,23,23,23,23,23,24,26,26,27,29,29,30,23,23,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,24,24,24,24,24,24,24,24,24,24,24,27,27,27,30,30,30,24,24,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,22,22,22,22,22,22,22,22,22,23,24,25,26,27,28,29,30,22,22,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,23,23,23,23,23,23,23,23,23,23,24,26,26,27,29,29,30,23,23,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,24,24,24,24,24,24,24,24,24,24,24,27,27,27,30,30,30,24,24,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,18,18,18,18,18,19,20,21,22,23,24,25,26,27,28,29,30,18,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,18,18,18,18,18,19,20,21,22,23,24,25,26,27,28,29,30,36,32,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+};
+unsigned char Type::impcnvWarn[TMAX][TMAX] =
+{
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/import.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,268 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "root.h"
+#include "dsymbol.h"
+#include "import.h"
+#include "identifier.h"
+#include "module.h"
+#include "scope.h"
+#include "hdrgen.h"
+#include "mtype.h"
+#include "declaration.h"
+#include "id.h"
+
+/********************************* Import ****************************/
+
+Import::Import(Loc loc, Array *packages, Identifier *id, Identifier *aliasId,
+	int isstatic)
+    : Dsymbol(id)
+{
+    this->loc = loc;
+    this->packages = packages;
+    this->id = id;
+    this->aliasId = aliasId;
+    this->isstatic = isstatic;
+    pkg = NULL;
+    mod = NULL;
+
+    if (aliasId)
+	this->ident = aliasId;
+    // Kludge to change Import identifier to first package
+    else if (packages && packages->dim)
+	this->ident = (Identifier *)packages->data[0];
+}
+
+void Import::addAlias(Identifier *name, Identifier *alias)
+{
+    if (isstatic)
+	error("cannot have an import bind list");
+
+    if (!aliasId)
+	this->ident = NULL;	// make it an anonymous import
+
+    names.push(name);
+    aliases.push(alias);
+}
+
+char *Import::kind()
+{
+    return isstatic ? (char *)"static import" : (char *)"import";
+}
+
+
+Dsymbol *Import::syntaxCopy(Dsymbol *s)
+{
+    assert(!s);
+
+    Import *si;
+
+    si = new Import(loc, packages, id, aliasId, isstatic);
+
+    for (size_t i = 0; i < names.dim; i++)
+    {
+	si->addAlias((Identifier *)names.data[i], (Identifier *)aliases.data[i]);
+    }
+
+    return si;
+}
+
+void Import::load(Scope *sc)
+{
+    DsymbolTable *dst;
+    Dsymbol *s;
+
+    //printf("Import::load('%s')\n", toChars());
+
+    // See if existing module
+    dst = Package::resolve(packages, NULL, &pkg);
+
+    s = dst->lookup(id);
+    if (s)
+    {
+	if (s->isModule())
+	    mod = (Module *)s;
+	else
+	    error("package and module have the same name");
+    }
+
+    if (!mod)
+    {
+	// Load module
+	mod = Module::load(loc, packages, id);
+	dst->insert(id, mod);		// id may be different from mod->ident,
+					// if so then insert alias
+	if (!mod->importedFrom)
+	    mod->importedFrom = sc ? sc->module->importedFrom : Module::rootModule;
+    }
+    if (!pkg)
+	pkg = mod;
+    mod->semantic();
+
+    //printf("-Import::load('%s'), pkg = %p\n", toChars(), pkg);
+}
+
+
+void Import::semantic(Scope *sc)
+{
+    //printf("Import::semantic('%s')\n", toChars());
+
+    load(sc);
+
+    if (mod)
+    {
+#if 0
+	if (mod->loc.linnum != 0)
+	{   /* If the line number is not 0, then this is not
+	     * a 'root' module, i.e. it was not specified on the command line.
+	     */
+	    mod->importedFrom = sc->module->importedFrom;
+	    assert(mod->importedFrom);
+	}
+#endif
+
+	if (!isstatic && !aliasId && !names.dim)
+	{
+	    /* Default to private importing
+	     */
+	    enum PROT prot = sc->protection;
+	    if (!sc->explicitProtection)
+		prot = PROTprivate;
+	    sc->scopesym->importScope(mod, prot);
+	}
+
+	// Modules need a list of each imported module
+	sc->module->aimports.push(mod);
+
+	if (mod->needmoduleinfo)
+	    sc->module->needmoduleinfo = 1;
+
+	sc = sc->push(mod);
+	for (size_t i = 0; i < aliasdecls.dim; i++)
+	{   Dsymbol *s = (Dsymbol *)aliasdecls.data[i];
+
+	    //printf("\tImport alias semantic('%s')\n", s->toChars());
+	    if (!mod->search(loc, (Identifier *)names.data[i], 0))
+		error("%s not found", ((Identifier *)names.data[i])->toChars());
+
+	    s->semantic(sc);
+	}
+	sc = sc->pop();
+    }
+    //printf("-Import::semantic('%s'), pkg = %p\n", toChars(), pkg);
+}
+
+void Import::semantic2(Scope *sc)
+{
+    //printf("Import::semantic2('%s')\n", toChars());
+    mod->semantic2();
+    if (mod->needmoduleinfo)
+	sc->module->needmoduleinfo = 1;
+}
+
+Dsymbol *Import::toAlias()
+{
+    if (aliasId)
+	return mod;
+    return this;
+}
+
+int Import::addMember(Scope *sc, ScopeDsymbol *sd, int memnum)
+{
+    int result = 0;
+
+    if (names.dim == 0)
+	return Dsymbol::addMember(sc, sd, memnum);
+
+    if (aliasId)
+	result = Dsymbol::addMember(sc, sd, memnum);
+
+    for (size_t i = 0; i < names.dim; i++)
+    {
+	Identifier *name = (Identifier *)names.data[i];
+	Identifier *alias = (Identifier *)aliases.data[i];
+
+	if (!alias)
+	    alias = name;
+
+#if 1
+	TypeIdentifier *tname = new TypeIdentifier(loc, name);
+#else
+	TypeIdentifier *tname = new TypeIdentifier(loc, NULL);
+	if (packages)
+	{
+	    for (size_t j = 0; j < packages->dim; j++)
+	    {   Identifier *pid = (Identifier *)packages->data[j];
+
+		if (!tname->ident)
+		    tname->ident = pid;
+		else
+		    tname->addIdent(pid);
+	    }
+	}
+	if (!tname->ident)
+	    tname->ident = id;
+	else
+	    tname->addIdent(id);
+	tname->addIdent(name);
+#endif
+	AliasDeclaration *ad = new AliasDeclaration(loc, alias, tname);
+	result |= ad->addMember(sc, sd, memnum);
+
+	aliasdecls.push(ad);
+    }
+
+    return result;
+}
+
+Dsymbol *Import::search(Loc loc, Identifier *ident, int flags)
+{
+    //printf("%s.Import::search(ident = '%s', flags = x%x)\n", toChars(), ident->toChars(), flags);
+
+    if (!pkg)
+	load(NULL);
+
+    // Forward it to the package/module
+    return pkg->search(loc, ident, flags);
+}
+
+int Import::overloadInsert(Dsymbol *s)
+{
+    // Allow multiple imports of the same name
+    return s->isImport() != NULL;
+}
+
+void Import::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    if (hgs->hdrgen && id == Id::object)
+	return;		// object is imported by default
+
+    if (isstatic)
+	buf->writestring("static ");
+    buf->writestring("import ");
+    if (aliasId)
+    {
+	buf->printf("%s = ", aliasId->toChars());
+    }
+    if (packages && packages->dim)
+    {
+	for (size_t i = 0; i < packages->dim; i++)
+	{   Identifier *pid = (Identifier *)packages->data[i];
+
+	    buf->printf("%s.", pid->toChars());
+	}
+    }
+    buf->printf("%s;", id->toChars());
+    buf->writenl();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/import.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,65 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#ifndef DMD_IMPORT_H
+#define DMD_IMPORT_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include "dsymbol.h"
+
+
+struct Identifier;
+struct Scope;
+struct OutBuffer;
+struct Module;
+struct Package;
+struct AliasDeclaration;
+#ifdef _DH
+struct HdrGenState;
+#endif
+
+struct Import : Dsymbol
+{
+    Array *packages;		// array of Identifier's representing packages
+    Identifier *id;		// module Identifier
+    Identifier *aliasId;
+    int isstatic;		// !=0 if static import
+
+    // Pairs of alias=name to bind into current namespace
+    Array names;
+    Array aliases;
+
+    Array aliasdecls;		// AliasDeclarations for names/aliases
+
+    Module *mod;
+    Package *pkg;		// leftmost package/module
+
+    Import(Loc loc, Array *packages, Identifier *id, Identifier *aliasId,
+	int isstatic);
+    void addAlias(Identifier *name, Identifier *alias);
+
+    char *kind();
+    Dsymbol *syntaxCopy(Dsymbol *s);	// copy only syntax trees
+    void load(Scope *sc);
+    void semantic(Scope *sc);
+    void semantic2(Scope *sc);
+    Dsymbol *toAlias();
+    int addMember(Scope *sc, ScopeDsymbol *s, int memnum);
+    Dsymbol *search(Loc loc, Identifier *ident, int flags);
+    int overloadInsert(Dsymbol *s);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    Import *isImport() { return this; }
+};
+
+#endif /* DMD_IMPORT_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/inifile.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,272 @@
+
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+
+
+#include	<stdio.h>
+#include	<string.h>
+#include	<stdlib.h>
+#include	<ctype.h>
+
+#include	"root.h"
+#include	"mem.h"
+
+#define LOG	0
+
+char *skipspace(const char *p);
+
+#if __GNUC__
+char *strupr(char *s)
+{
+    char *t = s;
+    
+    while (*s)
+    {
+	*s = toupper(*s);
+	s++;
+    }
+
+    return t;
+}
+#endif /* unix */
+
+/*****************************
+ * Read and analyze .ini file.
+ * Input:
+ *	argv0	program name (argv[0])
+ *	inifile	.ini file name
+ */
+
+void inifile(char *argv0, char *inifile)
+{
+    char *path;		// need path for @P macro
+    char *filename;
+    OutBuffer buf;
+    int i;
+    int k;
+    int envsection = 0;
+
+#if LOG
+    printf("inifile(argv0 = '%s', inifile = '%s')\n", argv0, inifile);
+#endif
+    if (FileName::absolute(inifile))
+    {
+	filename = inifile;
+    }
+    else
+    {
+	/* Look for inifile in the following sequence of places:
+	 *	o current directory
+	 *	o home directory
+	 *	o directory off of argv0
+	 *	o /etc/
+	 */
+	if (FileName::exists(inifile))
+	{
+	    filename = inifile;
+	}
+	else
+	{
+	    filename = FileName::combine(getenv("HOME"), inifile);
+	    if (!FileName::exists(filename))
+	    {
+		filename = FileName::replaceName(argv0, inifile);
+		if (!FileName::exists(filename))
+		{
+#if linux
+		    // Search PATH for argv0
+		    const char *p = getenv("PATH");
+		    Array *paths = FileName::splitPath(p);
+		    filename = FileName::searchPath(paths, argv0, 0);
+		    if (!filename)
+			goto Letc;		// argv0 not found on path
+		    filename = FileName::replaceName(filename, inifile);
+		    if (FileName::exists(filename))
+			goto Ldone;
+#endif
+
+		    // Search /etc/ for inifile
+		Letc:
+		    filename = FileName::combine("/etc/", inifile);
+
+		Ldone:
+		    ;
+		}
+	    }
+	}
+    }
+    path = FileName::path(filename);
+#if LOG
+    printf("\tpath = '%s', filename = '%s'\n", path, filename);
+#endif
+
+    File file(filename);
+
+    if (file.read())
+	return;			// error reading file
+
+    // Parse into lines
+    int eof = 0;
+    for (i = 0; i < file.len && !eof; i++)
+    {
+	int linestart = i;
+
+	for (; i < file.len; i++)
+	{
+	    switch (file.buffer[i])
+	    {
+		case '\r':
+		    break;
+
+		case '\n':
+		    // Skip if it was preceded by '\r'
+		    if (i && file.buffer[i - 1] == '\r')
+			goto Lskip;
+		    break;
+
+		case 0:
+		case 0x1A:
+		    eof = 1;
+		    break;
+
+		default:
+		    continue;
+	    }
+	    break;
+	}
+
+	// The line is file.buffer[linestart..i]
+	char *line;
+	int len;
+	char *p;
+	char *pn;
+
+	line = (char *)&file.buffer[linestart];
+	len = i - linestart;
+
+	buf.reset();
+
+	// First, expand the macros.
+	// Macros are bracketed by % characters.
+
+	for (k = 0; k < len; k++)
+	{
+	    if (line[k] == '%')
+	    {
+		int j;
+
+		for (j = k + 1; j < len; j++)
+		{
+		    if (line[j] == '%')
+		    {
+			if (j - k == 3 && memicmp(&line[k + 1], "@P", 2) == 0)
+			{
+			    // %@P% is special meaning the path to the .ini file
+			    p = path;
+			    if (!*p)
+				p = ".";
+			}
+			else
+			{   int len = j - k;
+			    char tmp[10];	// big enough most of the time
+
+			    if (len <= sizeof(tmp))
+				p = tmp;
+			    else
+				p = (char *)alloca(len);
+			    len--;
+			    memcpy(p, &line[k + 1], len);
+			    p[len] = 0;
+			    strupr(p);
+			    p = getenv(p);
+			    if (!p)
+				p = "";
+			}
+			buf.writestring(p);
+			k = j;
+			goto L1;
+		    }
+		}
+	    }
+	    buf.writeByte(line[k]);
+	 L1:
+	    ;
+	}
+
+	// Remove trailing spaces
+	while (buf.offset && isspace(buf.data[buf.offset - 1]))
+	    buf.offset--;
+
+	p = buf.toChars();
+
+	// The expanded line is in p.
+	// Now parse it for meaning.
+
+	p = skipspace(p);
+	switch (*p)
+	{
+	    case ';':		// comment
+	    case 0:		// blank
+		break;
+
+	    case '[':		// look for [Environment]
+		p = skipspace(p + 1);
+		for (pn = p; isalnum(*pn); pn++)
+		    ;
+		if (pn - p == 11 &&
+		    memicmp(p, "Environment", 11) == 0 &&
+		    *skipspace(pn) == ']'
+		   )
+		    envsection = 1;
+		else
+		    envsection = 0;
+		break;
+
+	    default:
+		if (envsection)
+		{
+		    pn = p;
+
+		    // Convert name to upper case;
+		    // remove spaces bracketing =
+		    for (p = pn; *p; p++)
+		    {   if (islower(*p))
+			    *p &= ~0x20;
+			else if (isspace(*p))
+			    memmove(p, p + 1, strlen(p));
+			else if (*p == '=')
+			{
+			    p++;
+			    while (isspace(*p))
+				memmove(p, p + 1, strlen(p));
+			    break;
+			}
+		    }
+
+		    putenv(strdup(pn));
+#if LOG
+		    printf("\tputenv('%s')\n", pn);
+		    //printf("getenv(\"TEST\") = '%s'\n",getenv("TEST"));
+#endif
+		}
+		break;
+	}
+
+     Lskip:
+	;
+    }
+}
+
+/********************
+ * Skip spaces.
+ */
+
+char *skipspace(const char *p)
+{
+    while (isspace(*p))
+	p++;
+    return (char *)p;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/init.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,550 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "mars.h"
+#include "init.h"
+#include "expression.h"
+#include "statement.h"
+#include "identifier.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "scope.h"
+#include "mtype.h"
+#include "hdrgen.h"
+
+/********************************** Initializer *******************************/
+
+Initializer::Initializer(Loc loc)
+{
+    this->loc = loc;
+}
+
+Initializer *Initializer::syntaxCopy()
+{
+    return this;
+}
+
+Initializer *Initializer::semantic(Scope *sc, Type *t)
+{
+    return this;
+}
+
+Type *Initializer::inferType(Scope *sc)
+{
+    error(loc, "cannot infer type from initializer");
+    return Type::terror;
+}
+
+Initializers *Initializer::arraySyntaxCopy(Initializers *ai)
+{   Initializers *a = NULL;
+
+    if (ai)
+    {
+	a = new Initializers();
+	a->setDim(ai->dim);
+	for (int i = 0; i < a->dim; i++)
+	{   Initializer *e = (Initializer *)ai->data[i];
+
+	    e = e->syntaxCopy();
+	    a->data[i] = e;
+	}
+    }
+    return a;
+}
+
+char *Initializer::toChars()
+{   OutBuffer *buf;
+    HdrGenState hgs;
+
+    memset(&hgs, 0, sizeof(hgs));
+    buf = new OutBuffer();
+    toCBuffer(buf, &hgs);
+    return buf->toChars();
+}
+
+/********************************** VoidInitializer ***************************/
+
+VoidInitializer::VoidInitializer(Loc loc)
+    : Initializer(loc)
+{
+    type = NULL;
+}
+
+
+Initializer *VoidInitializer::syntaxCopy()
+{
+    return new VoidInitializer(loc);
+}
+
+
+Initializer *VoidInitializer::semantic(Scope *sc, Type *t)
+{
+    //printf("VoidInitializer::semantic(t = %p)\n", t);
+    type = t;
+    return this;
+}
+
+
+Expression *VoidInitializer::toExpression()
+{
+    error(loc, "void initializer has no value");
+    return new IntegerExp(0);
+}
+
+
+void VoidInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("void");
+}
+
+
+/********************************** StructInitializer *************************/
+
+StructInitializer::StructInitializer(Loc loc)
+    : Initializer(loc)
+{
+    ad = NULL;
+}
+
+Initializer *StructInitializer::syntaxCopy()
+{
+    StructInitializer *ai = new StructInitializer(loc);
+
+    assert(field.dim == value.dim);
+    ai->field.setDim(field.dim);
+    ai->value.setDim(value.dim);
+    for (int i = 0; i < field.dim; i++)
+    {    
+	ai->field.data[i] = field.data[i];
+
+	Initializer *init = (Initializer *)value.data[i];
+	init = init->syntaxCopy();
+	ai->value.data[i] = init;
+    }
+    return ai;
+}
+
+void StructInitializer::addInit(Identifier *field, Initializer *value)
+{
+    //printf("StructInitializer::addInit(field = %p, value = %p)\n", field, value);
+    this->field.push(field);
+    this->value.push(value);
+}
+
+Initializer *StructInitializer::semantic(Scope *sc, Type *t)
+{
+    TypeStruct *ts;
+    int errors = 0;
+
+    //printf("StructInitializer::semantic(t = %s) %s\n", t->toChars(), toChars());
+    vars.setDim(field.dim);
+    t = t->toBasetype();
+    if (t->ty == Tstruct)
+    {	unsigned i;
+	unsigned fieldi = 0;
+
+	ts = (TypeStruct *)t;
+	ad = ts->sym;
+	for (i = 0; i < field.dim; i++)
+	{
+	    Identifier *id = (Identifier *)field.data[i];
+	    Initializer *val = (Initializer *)value.data[i];
+	    Dsymbol *s;
+	    VarDeclaration *v;
+
+	    if (id == NULL)
+	    {
+		if (fieldi >= ad->fields.dim)
+		{   error(loc, "too many initializers for %s", ad->toChars());
+		    continue;
+		}
+		else
+		{
+		    s = (Dsymbol *)ad->fields.data[fieldi];
+		}
+	    }
+	    else
+	    {
+		//s = ad->symtab->lookup(id);
+		s = ad->search(loc, id, 0);
+		if (!s)
+		{
+		    error("'%s' is not a member of '%s'", id->toChars(), t->toChars());
+		    continue;
+		}
+
+		// Find out which field index it is
+		for (fieldi = 0; 1; fieldi++)
+		{
+		    if (fieldi >= ad->fields.dim)
+		    {
+			s->error("is not a per-instance initializable field");
+			break;
+		    }
+		    if (s == (Dsymbol *)ad->fields.data[fieldi])
+			break;
+		}
+	    }
+	    if (s && (v = s->isVarDeclaration()) != NULL)
+	    {
+		val = val->semantic(sc, v->type);
+		value.data[i] = (void *)val;
+		vars.data[i] = (void *)v;
+	    }
+	    else
+	    {	error(loc, "%s is not a field of %s", id ? id->toChars() : s->toChars(), ad->toChars());
+		errors = 1;
+	    }
+	    fieldi++;
+	}
+    }
+    else if (t->ty == Tdelegate && value.dim == 0)
+    {	/* Rewrite as empty delegate literal { }
+	 */
+	Arguments *arguments = new Arguments;
+	Type *tf = new TypeFunction(arguments, NULL, 0, LINKd);
+	FuncLiteralDeclaration *fd = new FuncLiteralDeclaration(loc, 0, tf, TOKdelegate, NULL);
+	fd->fbody = new CompoundStatement(loc, new Statements());
+	fd->endloc = loc;
+	Expression *e = new FuncExp(loc, fd);
+	ExpInitializer *ie = new ExpInitializer(loc, e);
+	return ie->semantic(sc, t);
+    }
+    else
+    {
+	error(loc, "a struct is not a valid initializer for a %s", t->toChars());
+	errors = 1;
+    }
+    if (errors)
+    {
+	field.setDim(0);
+	value.setDim(0);
+	vars.setDim(0);
+    }
+    return this;
+}
+
+
+Expression *StructInitializer::toExpression()
+{
+    return NULL;		// cannot do it
+}
+
+
+void StructInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    //printf("StructInitializer::toCBuffer()\n");
+    buf->writebyte('{');
+    for (int i = 0; i < field.dim; i++)
+    {
+        if (i > 0)
+	    buf->writebyte(',');
+        Identifier *id = (Identifier *)field.data[i];
+        if (id)
+        {
+            buf->writestring(id->toChars());
+            buf->writebyte(':');
+        }
+        Initializer *iz = (Initializer *)value.data[i];
+        if (iz)
+            iz->toCBuffer(buf, hgs);
+    }
+    buf->writebyte('}');
+}
+
+/********************************** ArrayInitializer ************************************/
+
+ArrayInitializer::ArrayInitializer(Loc loc)
+    : Initializer(loc)
+{
+    dim = 0;
+    type = NULL;
+    sem = 0;
+}
+
+Initializer *ArrayInitializer::syntaxCopy()
+{
+    //printf("ArrayInitializer::syntaxCopy()\n");
+
+    ArrayInitializer *ai = new ArrayInitializer(loc);
+
+    assert(index.dim == value.dim);
+    ai->index.setDim(index.dim);
+    ai->value.setDim(value.dim);
+    for (int i = 0; i < ai->value.dim; i++)
+    {	Expression *e = (Expression *)index.data[i];
+	if (e)
+	    e = e->syntaxCopy();
+	ai->index.data[i] = e;
+
+	Initializer *init = (Initializer *)value.data[i];
+	init = init->syntaxCopy();
+	ai->value.data[i] = init;
+    }
+    return ai;
+}
+
+void ArrayInitializer::addInit(Expression *index, Initializer *value)
+{
+    this->index.push(index);
+    this->value.push(value);
+    dim = 0;
+    type = NULL;
+}
+
+Initializer *ArrayInitializer::semantic(Scope *sc, Type *t)
+{   unsigned i;
+    unsigned length;
+
+    //printf("ArrayInitializer::semantic(%s)\n", t->toChars());
+    if (sem)				// if semantic() already run
+	return this;
+    sem = 1;
+    type = t;
+    t = t->toBasetype();
+    switch (t->ty)
+    {
+	case Tpointer:
+	case Tsarray:
+	case Tarray:
+	    break;
+
+	default:
+	    error(loc, "cannot use array to initialize %s", type->toChars());
+	    return this;
+    }
+
+    length = 0;
+    for (i = 0; i < index.dim; i++)
+    {	Expression *idx;
+	Initializer *val;
+
+	idx = (Expression *)index.data[i];
+	if (idx)
+	{   idx = idx->semantic(sc);
+	    idx = idx->optimize(WANTvalue | WANTinterpret);
+	    index.data[i] = (void *)idx;
+	    length = idx->toInteger();
+	}
+
+	val = (Initializer *)value.data[i];
+	val = val->semantic(sc, t->next);
+	value.data[i] = (void *)val;
+	length++;
+	if (length == 0)
+	    error("array dimension overflow");
+	if (length > dim)
+	    dim = length;
+    }
+    unsigned long amax = 0x80000000;
+    if ((unsigned long) dim * t->next->size() >= amax)
+	error(loc, "array dimension %u exceeds max of %ju", dim, amax / t->next->size());
+    return this;
+}
+
+/********************************
+ * If possible, convert array initializer to array literal.
+ */
+
+Expression *ArrayInitializer::toExpression()
+{   Expressions *elements;
+    Expression *e;
+
+    //printf("ArrayInitializer::toExpression()\n");
+    //static int i; if (++i == 2) halt();
+    elements = new Expressions();
+    for (size_t i = 0; i < value.dim; i++)
+    {
+	if (index.data[i])
+	    goto Lno;
+	Initializer *iz = (Initializer *)value.data[i];
+	if (!iz)
+	    goto Lno;
+	Expression *ex = iz->toExpression();
+	if (!ex)
+	    goto Lno;
+	elements->push(ex);
+    }
+    e = new ArrayLiteralExp(loc, elements);
+    e->type = type;
+    return e;
+
+Lno:
+    delete elements;
+    error(loc, "array initializers as expressions are not allowed");
+    return NULL;
+}
+
+
+/********************************
+ * If possible, convert array initializer to associative array initializer.
+ */
+
+Initializer *ArrayInitializer::toAssocArrayInitializer()
+{   Expressions *keys;
+    Expressions *values;
+    Expression *e;
+
+    //printf("ArrayInitializer::toAssocArrayInitializer()\n");
+    //static int i; if (++i == 2) halt();
+    keys = new Expressions();
+    keys->setDim(value.dim);
+    values = new Expressions();
+    values->setDim(value.dim);
+
+    for (size_t i = 0; i < value.dim; i++)
+    {
+	e = (Expression *)index.data[i];
+	if (!e)
+	    goto Lno;
+	keys->data[i] = (void *)e;
+
+	Initializer *iz = (Initializer *)value.data[i];
+	if (!iz)
+	    goto Lno;
+	e = iz->toExpression();
+	if (!e)
+	    goto Lno;
+	values->data[i] = (void *)e;
+    }
+    e = new AssocArrayLiteralExp(loc, keys, values);
+    return new ExpInitializer(loc, e);
+
+Lno:
+    delete keys;
+    delete values;
+    error(loc, "not an associative array initializer");
+    return this;
+}
+
+
+Type *ArrayInitializer::inferType(Scope *sc)
+{
+    for (size_t i = 0; i < value.dim; i++)
+    {
+	if (index.data[i])
+	    goto Lno;
+    }
+    if (value.dim)
+    {
+	Initializer *iz = (Initializer *)value.data[0];
+	if (iz)
+	{   Type *t = iz->inferType(sc);
+	    t = new TypeSArray(t, new IntegerExp(value.dim));
+	    t = t->semantic(loc, sc);
+	    return t;
+	}
+    }
+
+Lno:
+    error(loc, "cannot infer type from this array initializer");
+    return Type::terror;
+}
+
+
+void ArrayInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writebyte('[');
+    for (int i = 0; i < index.dim; i++)
+    {
+        if (i > 0)
+	    buf->writebyte(',');
+        Expression *ex = (Expression *)index.data[i];
+        if (ex)
+        {
+            ex->toCBuffer(buf, hgs);
+            buf->writebyte(':');
+        }
+        Initializer *iz = (Initializer *)value.data[i];
+        if (iz)
+            iz->toCBuffer(buf, hgs);
+    }
+    buf->writebyte(']');
+}
+
+
+/********************************** ExpInitializer ************************************/
+
+ExpInitializer::ExpInitializer(Loc loc, Expression *exp)
+    : Initializer(loc)
+{
+    this->exp = exp;
+}
+
+Initializer *ExpInitializer::syntaxCopy()
+{
+    return new ExpInitializer(loc, exp->syntaxCopy());
+}
+
+Initializer *ExpInitializer::semantic(Scope *sc, Type *t)
+{
+    //printf("ExpInitializer::semantic(%s), type = %s\n", exp->toChars(), t->toChars());
+    exp = exp->semantic(sc);
+    Type *tb = t->toBasetype();
+
+    /* Look for case of initializing a static array with a too-short
+     * string literal, such as:
+     *	char[5] foo = "abc";
+     * Allow this by doing an explicit cast, which will lengthen the string
+     * literal.
+     */
+    if (exp->op == TOKstring && tb->ty == Tsarray && exp->type->ty == Tsarray)
+    {	StringExp *se = (StringExp *)exp;
+
+	if (!se->committed && se->type->ty == Tsarray &&
+	    ((TypeSArray *)se->type)->dim->toInteger() <
+	    ((TypeSArray *)t)->dim->toInteger())
+	{
+	    exp = se->castTo(sc, t);
+	    goto L1;
+	}
+    }
+
+    // Look for the case of statically initializing an array
+    // with a single member.
+    if (tb->ty == Tsarray &&
+	!tb->next->equals(exp->type->toBasetype()->next) &&
+	exp->implicitConvTo(tb->next)
+       )
+    {
+	t = tb->next;
+    }
+
+    exp = exp->implicitCastTo(sc, t);
+L1:
+    exp = exp->optimize(WANTvalue | WANTinterpret);
+    //printf("-ExpInitializer::semantic(): "); exp->print();
+    return this;
+}
+
+Type *ExpInitializer::inferType(Scope *sc)
+{
+    //printf("ExpInitializer::inferType() %s\n", toChars());
+    exp = exp->semantic(sc);
+    exp = resolveProperties(sc, exp);
+    return exp->type;
+}
+
+Expression *ExpInitializer::toExpression()
+{
+    return exp;
+}
+
+
+void ExpInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    exp->toCBuffer(buf, hgs);
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/init.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,129 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#ifndef INIT_H
+#define INIT_H
+
+#include "root.h"
+
+#include "mars.h"
+#include "arraytypes.h"
+
+struct Identifier;
+struct Expression;
+struct Scope;
+struct Type;
+struct dt_t;
+struct AggregateDeclaration;
+struct VoidInitializer;
+struct ArrayInitializer;
+struct ExpInitializer;
+struct StructInitializer;
+#ifdef _DH
+struct HdrGenState;
+#endif
+
+struct Initializer : Object
+{
+    Loc loc;
+
+    Initializer(Loc loc);
+    virtual Initializer *syntaxCopy();
+    virtual Initializer *semantic(Scope *sc, Type *t);
+    virtual Type *inferType(Scope *sc);
+    virtual Expression *toExpression() = 0;
+    virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs) = 0;
+    char *toChars();
+
+    static Initializers *arraySyntaxCopy(Initializers *ai);
+
+    virtual dt_t *toDt();
+
+    virtual VoidInitializer *isVoidInitializer() { return NULL; }
+    virtual ArrayInitializer  *isArrayInitializer()  { return NULL; }
+    virtual ExpInitializer  *isExpInitializer()  { return NULL; }
+    virtual StructInitializer  *isStructInitializer()  { return NULL; }
+};
+
+struct VoidInitializer : Initializer
+{
+    Type *type;		// type that this will initialize to
+
+    VoidInitializer(Loc loc);
+    Initializer *syntaxCopy();
+    Initializer *semantic(Scope *sc, Type *t);
+    Expression *toExpression();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    dt_t *toDt();
+
+    virtual VoidInitializer *isVoidInitializer() { return this; }
+};
+
+struct StructInitializer : Initializer
+{
+    Identifiers field;	// of Identifier *'s
+    Initializers value;	// parallel array of Initializer *'s
+
+    Array vars;		// parallel array of VarDeclaration *'s
+    AggregateDeclaration *ad;	// which aggregate this is for
+
+    StructInitializer(Loc loc);
+    Initializer *syntaxCopy();
+    void addInit(Identifier *field, Initializer *value);
+    Initializer *semantic(Scope *sc, Type *t);
+    Expression *toExpression();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    dt_t *toDt();
+
+    virtual StructInitializer  *isStructInitializer()  { return this; }
+};
+
+struct ArrayInitializer : Initializer
+{
+    Expressions index;	// indices
+    Initializers value;	// of Initializer *'s
+    unsigned dim;	// length of array being initialized
+    Type *type;		// type that array will be used to initialize
+    int sem;		// !=0 if semantic() is run
+
+    ArrayInitializer(Loc loc);
+    Initializer *syntaxCopy();
+    void addInit(Expression *index, Initializer *value);
+    Initializer *semantic(Scope *sc, Type *t);
+    Type *inferType(Scope *sc);
+    Expression *toExpression();
+    Initializer *toAssocArrayInitializer();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    dt_t *toDt();
+    dt_t *toDtBit();	// for bit arrays
+
+    ArrayInitializer *isArrayInitializer() { return this; }
+};
+
+struct ExpInitializer : Initializer
+{
+    Expression *exp;
+
+    ExpInitializer(Loc loc, Expression *exp);
+    Initializer *syntaxCopy();
+    Initializer *semantic(Scope *sc, Type *t);
+    Type *inferType(Scope *sc);
+    Expression *toExpression();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    dt_t *toDt();
+
+    virtual ExpInitializer *isExpInitializer() { return this; }
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/inline.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,1441 @@
+
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+// Routines to perform function inlining
+
+#define LOG 0
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "id.h"
+#include "init.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "expression.h"
+#include "statement.h"
+#include "mtype.h"
+
+/* ========== Compute cost of inlining =============== */
+
+/* Walk trees to determine if inlining can be done, and if so,
+ * if it is too complex to be worth inlining or not.
+ */
+
+struct InlineCostState
+{
+    int nested;
+    int hasthis;
+    int hdrscan;    // !=0 if inline scan for 'header' content
+    FuncDeclaration *fd;
+};
+
+const int COST_MAX = 250;
+
+int Statement::inlineCost(InlineCostState *ics)
+{
+    return COST_MAX;		// default is we can't inline it
+}
+
+int ExpStatement::inlineCost(InlineCostState *ics)
+{
+    return exp ? exp->inlineCost(ics) : 0;
+}
+
+int CompoundStatement::inlineCost(InlineCostState *ics)
+{   int cost = 0;
+
+    for (size_t i = 0; i < statements->dim; i++)
+    {	Statement *s = (Statement *) statements->data[i];
+	if (s)
+	{
+	    cost += s->inlineCost(ics);
+	    if (cost >= COST_MAX)
+		break;
+	}
+    }
+    return cost;
+}
+
+int UnrolledLoopStatement::inlineCost(InlineCostState *ics)
+{   int cost = 0;
+
+    for (size_t i = 0; i < statements->dim; i++)
+    {	Statement *s = (Statement *) statements->data[i];
+	if (s)
+	{
+	    cost += s->inlineCost(ics);
+	    if (cost >= COST_MAX)
+		break;
+	}
+    }
+    return cost;
+}
+
+int IfStatement::inlineCost(InlineCostState *ics)
+{
+    int cost;
+
+    /* Can't declare variables inside ?: expressions, so
+     * we cannot inline if a variable is declared.
+     */
+    if (arg)
+	return COST_MAX;
+
+    cost = condition->inlineCost(ics);
+
+    /* Specifically allow:
+     *	if (condition)
+     *	    return exp1;
+     *	else
+     *	    return exp2;
+     * Otherwise, we can't handle return statements nested in if's.
+     */
+
+    if (elsebody && ifbody &&
+	ifbody->isReturnStatement() &&
+	elsebody->isReturnStatement())
+    {
+	cost += ifbody->inlineCost(ics);
+	cost += elsebody->inlineCost(ics);
+	//printf("cost = %d\n", cost);
+    }
+    else
+    {
+	ics->nested += 1;
+	if (ifbody)
+	    cost += ifbody->inlineCost(ics);
+	if (elsebody)
+	    cost += elsebody->inlineCost(ics);
+	ics->nested -= 1;
+    }
+    return cost;
+}
+
+int ReturnStatement::inlineCost(InlineCostState *ics)
+{
+    // Can't handle return statements nested in if's
+    if (ics->nested)
+	return COST_MAX;
+    return exp ? exp->inlineCost(ics) : 0;
+}
+
+/* -------------------------- */
+
+int arrayInlineCost(InlineCostState *ics, Array *arguments)
+{   int cost = 0;
+
+    if (arguments)
+    {
+	for (int i = 0; i < arguments->dim; i++)
+	{   Expression *e = (Expression *)arguments->data[i];
+
+	    if (e)
+		cost += e->inlineCost(ics);
+	}
+    }
+    return cost;
+}
+
+int Expression::inlineCost(InlineCostState *ics)
+{
+    return 1;
+}
+
+int VarExp::inlineCost(InlineCostState *ics)
+{
+    //printf("VarExp::inlineCost() %s\n", toChars());
+    return 1;
+}
+
+int ThisExp::inlineCost(InlineCostState *ics)
+{
+    FuncDeclaration *fd = ics->fd;
+    if (!ics->hdrscan)
+	if (fd->isNested() || !ics->hasthis)
+	    return COST_MAX;
+    return 1;
+}
+
+int SuperExp::inlineCost(InlineCostState *ics)
+{
+    FuncDeclaration *fd = ics->fd;
+    if (!ics->hdrscan)
+	if (fd->isNested() || !ics->hasthis)
+	    return COST_MAX;
+    return 1;
+}
+
+int TupleExp::inlineCost(InlineCostState *ics)
+{
+    return 1 + arrayInlineCost(ics, exps);
+}
+
+int ArrayLiteralExp::inlineCost(InlineCostState *ics)
+{
+    return 1 + arrayInlineCost(ics, elements);
+}
+
+int AssocArrayLiteralExp::inlineCost(InlineCostState *ics)
+{
+    return 1 + arrayInlineCost(ics, keys) + arrayInlineCost(ics, values);
+}
+
+int StructLiteralExp::inlineCost(InlineCostState *ics)
+{
+    return 1 + arrayInlineCost(ics, elements);
+}
+
+int FuncExp::inlineCost(InlineCostState *ics)
+{
+    // Right now, this makes the function be output to the .obj file twice.
+    return COST_MAX;
+}
+
+int DelegateExp::inlineCost(InlineCostState *ics)
+{
+    return COST_MAX;
+}
+
+int DeclarationExp::inlineCost(InlineCostState *ics)
+{   int cost = 0;
+    VarDeclaration *vd;
+
+    //printf("DeclarationExp::inlineCost()\n");
+    vd = declaration->isVarDeclaration();
+    if (vd)
+    {
+	TupleDeclaration *td = vd->toAlias()->isTupleDeclaration();
+	if (td)
+	{
+#if 1
+	    return COST_MAX;	// finish DeclarationExp::doInline
+#else
+	    for (size_t i = 0; i < td->objects->dim; i++)
+	    {   Object *o = (Object *)td->objects->data[i];
+		if (o->dyncast() != DYNCAST_EXPRESSION)
+		    return COST_MAX;
+		Expression *eo = (Expression *)o;
+		if (eo->op != TOKdsymbol)
+		    return COST_MAX;
+	    }
+	    return td->objects->dim;
+#endif
+	}
+	if (!ics->hdrscan && vd->isDataseg())
+	    return COST_MAX;
+	cost += 1;
+
+	// Scan initializer (vd->init)
+	if (vd->init)
+	{
+	    ExpInitializer *ie = vd->init->isExpInitializer();
+
+	    if (ie)
+	    {
+		cost += ie->exp->inlineCost(ics);
+	    }
+	}
+    }
+
+    // These can contain functions, which when copied, get output twice.
+    if (declaration->isStructDeclaration() ||
+	declaration->isClassDeclaration() ||
+	declaration->isFuncDeclaration() ||
+	declaration->isTypedefDeclaration() ||
+	declaration->isTemplateMixin())
+	return COST_MAX;
+
+    //printf("DeclarationExp::inlineCost('%s')\n", toChars());
+    return cost;
+}
+
+int UnaExp::inlineCost(InlineCostState *ics)
+{
+    return 1 + e1->inlineCost(ics);
+}
+
+int AssertExp::inlineCost(InlineCostState *ics)
+{
+    return 1 + e1->inlineCost(ics) + (msg ? msg->inlineCost(ics) : 0);
+}
+
+int BinExp::inlineCost(InlineCostState *ics)
+{
+    return 1 + e1->inlineCost(ics) + e2->inlineCost(ics);
+}
+
+int CallExp::inlineCost(InlineCostState *ics)
+{
+    return 1 + e1->inlineCost(ics) + arrayInlineCost(ics, arguments);
+}
+
+int SliceExp::inlineCost(InlineCostState *ics)
+{   int cost;
+
+    cost = 1 + e1->inlineCost(ics);
+    if (lwr)
+	cost += lwr->inlineCost(ics);
+    if (upr)
+	cost += upr->inlineCost(ics);
+    return cost;
+}
+
+int ArrayExp::inlineCost(InlineCostState *ics)
+{
+    return 1 + e1->inlineCost(ics) + arrayInlineCost(ics, arguments);
+}
+
+
+int CondExp::inlineCost(InlineCostState *ics)
+{
+    return 1 +
+	 e1->inlineCost(ics) +
+	 e2->inlineCost(ics) +
+	 econd->inlineCost(ics);
+}
+
+
+/* ======================== Perform the inlining ============================== */
+
+/* Inlining is done by:
+ * o	Converting to an Expression
+ * o	Copying the trees of the function to be inlined
+ * o	Renaming the variables
+ */
+
+struct InlineDoState
+{
+    VarDeclaration *vthis;
+    Array from;		// old Dsymbols
+    Array to;		// parallel array of new Dsymbols
+    Dsymbol *parent;	// new parent
+};
+
+Expression *Statement::doInline(InlineDoState *ids)
+{
+    assert(0);
+    return NULL;		// default is we can't inline it
+}
+
+Expression *ExpStatement::doInline(InlineDoState *ids)
+{
+#if LOG
+    if (exp) printf("ExpStatement::doInline() '%s'\n", exp->toChars());
+#endif
+    return exp ? exp->doInline(ids) : NULL;
+}
+
+Expression *CompoundStatement::doInline(InlineDoState *ids)
+{
+    Expression *e = NULL;
+
+    //printf("CompoundStatement::doInline() %d\n", statements->dim);
+    for (size_t i = 0; i < statements->dim; i++)
+    {	Statement *s = (Statement *) statements->data[i];
+	if (s)
+	{
+	    Expression *e2 = s->doInline(ids);
+	    e = Expression::combine(e, e2);
+	    if (s->isReturnStatement())
+		break;
+
+	    /* Check for:
+	     *	if (condition)
+	     *	    return exp1;
+	     *	else
+	     *	    return exp2;
+	     */
+	    IfStatement *ifs = s->isIfStatement();
+	    if (ifs && ifs->elsebody && ifs->ifbody &&
+		ifs->ifbody->isReturnStatement() &&
+		ifs->elsebody->isReturnStatement()
+	       )
+		break;
+
+	}
+    }
+    return e;
+}
+
+Expression *UnrolledLoopStatement::doInline(InlineDoState *ids)
+{
+    Expression *e = NULL;
+
+    //printf("UnrolledLoopStatement::doInline() %d\n", statements->dim);
+    for (size_t i = 0; i < statements->dim; i++)
+    {	Statement *s = (Statement *) statements->data[i];
+	if (s)
+	{
+	    Expression *e2 = s->doInline(ids);
+	    e = Expression::combine(e, e2);
+	    if (s->isReturnStatement())
+		break;
+	}
+    }
+    return e;
+}
+
+Expression *IfStatement::doInline(InlineDoState *ids)
+{
+    Expression *econd;
+    Expression *e1;
+    Expression *e2;
+    Expression *e;
+
+    assert(!arg);
+    econd = condition->doInline(ids);
+    assert(econd);
+    if (ifbody)
+	e1 = ifbody->doInline(ids);
+    else
+	e1 = NULL;
+    if (elsebody)
+	e2 = elsebody->doInline(ids);
+    else
+	e2 = NULL;
+    if (e1 && e2)
+    {
+	e = new CondExp(econd->loc, econd, e1, e2);
+	e->type = e1->type;
+    }
+    else if (e1)
+    {
+	e = new AndAndExp(econd->loc, econd, e1);
+	e->type = Type::tvoid;
+    }
+    else if (e2)
+    {
+	e = new OrOrExp(econd->loc, econd, e2);
+	e->type = Type::tvoid;
+    }
+    else
+    {
+	e = econd;
+    }
+    return e;
+}
+
+Expression *ReturnStatement::doInline(InlineDoState *ids)
+{
+    //printf("ReturnStatement::doInline() '%s'\n", exp ? exp->toChars() : "");
+    return exp ? exp->doInline(ids) : 0;
+}
+
+/* --------------------------------------------------------------- */
+
+/******************************
+ * Perform doInline() on an array of Expressions.
+ */
+
+Expressions *arrayExpressiondoInline(Expressions *a, InlineDoState *ids)
+{   Expressions *newa = NULL;
+
+    if (a)
+    {
+	newa = new Expressions();
+	newa->setDim(a->dim);
+
+	for (int i = 0; i < a->dim; i++)
+	{   Expression *e = (Expression *)a->data[i];
+
+	    if (e)
+	    {
+		e = e->doInline(ids);
+		newa->data[i] = (void *)e;
+	    }
+	}
+    }
+    return newa;
+}
+
+Expression *Expression::doInline(InlineDoState *ids)
+{
+    //printf("Expression::doInline(%s): %s\n", Token::toChars(op), toChars());
+    return copy();
+}
+
+Expression *SymOffExp::doInline(InlineDoState *ids)
+{
+    int i;
+
+    //printf("SymOffExp::doInline(%s)\n", toChars());
+    for (i = 0; i < ids->from.dim; i++)
+    {
+	if (var == (Declaration *)ids->from.data[i])
+	{
+	    SymOffExp *se = (SymOffExp *)copy();
+
+	    se->var = (Declaration *)ids->to.data[i];
+	    return se;
+	}
+    }
+    return this;
+}
+
+Expression *VarExp::doInline(InlineDoState *ids)
+{
+    int i;
+
+    //printf("VarExp::doInline(%s)\n", toChars());
+    for (i = 0; i < ids->from.dim; i++)
+    {
+	if (var == (Declaration *)ids->from.data[i])
+	{
+	    VarExp *ve = (VarExp *)copy();
+
+	    ve->var = (Declaration *)ids->to.data[i];
+	    return ve;
+	}
+    }
+    return this;
+}
+
+Expression *ThisExp::doInline(InlineDoState *ids)
+{
+    //if (!ids->vthis)
+	//error("no 'this' when inlining %s", ids->parent->toChars());
+    if (!ids->vthis)
+    {
+	return this;
+    }
+
+    VarExp *ve = new VarExp(loc, ids->vthis);
+    ve->type = type;
+    return ve;
+}
+
+Expression *SuperExp::doInline(InlineDoState *ids)
+{
+    assert(ids->vthis);
+
+    VarExp *ve = new VarExp(loc, ids->vthis);
+    ve->type = type;
+    return ve;
+}
+
+Expression *DeclarationExp::doInline(InlineDoState *ids)
+{   DeclarationExp *de = (DeclarationExp *)copy();
+    VarDeclaration *vd;
+
+    //printf("DeclarationExp::doInline(%s)\n", toChars());
+    vd = declaration->isVarDeclaration();
+    if (vd)
+    {
+#if 0
+	// Need to figure this out before inlining can work for tuples
+	TupleDeclaration *td = vd->toAlias()->isTupleDeclaration();
+	if (td)
+	{
+	    for (size_t i = 0; i < td->objects->dim; i++)
+	    {   DsymbolExp *se = (DsymbolExp *)td->objects->data[i];
+		assert(se->op == TOKdsymbol);
+		se->s;
+	    }
+	    return st->objects->dim;
+	}
+#endif
+	if (vd->isStatic() || vd->isConst())
+	    ;
+	else
+	{
+	    ExpInitializer *ie;
+	    ExpInitializer *ieto;
+	    VarDeclaration *vto;
+
+	    vto = new VarDeclaration(vd->loc, vd->type, vd->ident, vd->init);
+	    *vto = *vd;
+	    vto->parent = ids->parent;
+	    vto->csym = NULL;
+	    vto->isym = NULL;
+
+	    ids->from.push(vd);
+	    ids->to.push(vto);
+
+	    if (vd->init->isVoidInitializer())
+	    {
+		vto->init = new VoidInitializer(vd->init->loc);
+	    }
+	    else
+	    {
+		ie = vd->init->isExpInitializer();
+		assert(ie);
+		ieto = new ExpInitializer(ie->loc, ie->exp->doInline(ids));
+		vto->init = ieto;
+	    }
+	    de->declaration = (Dsymbol *) (void *)vto;
+	}
+    }
+    /* This needs work, like DeclarationExp::toElem(), if we are
+     * to handle TemplateMixin's. For now, we just don't inline them.
+     */
+    return de;
+}
+
+Expression *NewExp::doInline(InlineDoState *ids)
+{
+    //printf("NewExp::doInline(): %s\n", toChars());
+    NewExp *ne = (NewExp *)copy();
+
+    if (thisexp)
+	ne->thisexp = thisexp->doInline(ids);
+    ne->newargs = arrayExpressiondoInline(ne->newargs, ids);
+    ne->arguments = arrayExpressiondoInline(ne->arguments, ids);
+    return ne;
+}
+
+Expression *UnaExp::doInline(InlineDoState *ids)
+{
+    UnaExp *ue = (UnaExp *)copy();
+
+    ue->e1 = e1->doInline(ids);
+    return ue;
+}
+
+Expression *AssertExp::doInline(InlineDoState *ids)
+{
+    AssertExp *ae = (AssertExp *)copy();
+
+    ae->e1 = e1->doInline(ids);
+    if (msg)
+	ae->msg = msg->doInline(ids);
+    return ae;
+}
+
+Expression *BinExp::doInline(InlineDoState *ids)
+{
+    BinExp *be = (BinExp *)copy();
+
+    be->e1 = e1->doInline(ids);
+    be->e2 = e2->doInline(ids);
+    return be;
+}
+
+Expression *CallExp::doInline(InlineDoState *ids)
+{
+    CallExp *ce;
+
+    ce = (CallExp *)copy();
+    ce->e1 = e1->doInline(ids);
+    ce->arguments = arrayExpressiondoInline(arguments, ids);
+    return ce;
+}
+
+
+Expression *IndexExp::doInline(InlineDoState *ids)
+{
+    IndexExp *are = (IndexExp *)copy();
+
+    are->e1 = e1->doInline(ids);
+
+    if (lengthVar)
+    {	//printf("lengthVar\n");
+	VarDeclaration *vd = lengthVar;
+	ExpInitializer *ie;
+	ExpInitializer *ieto;
+	VarDeclaration *vto;
+
+	vto = new VarDeclaration(vd->loc, vd->type, vd->ident, vd->init);
+	*vto = *vd;
+	vto->parent = ids->parent;
+	vto->csym = NULL;
+	vto->isym = NULL;
+
+	ids->from.push(vd);
+	ids->to.push(vto);
+
+	if (vd->init)
+	{
+	    ie = vd->init->isExpInitializer();
+	    assert(ie);
+	    ieto = new ExpInitializer(ie->loc, ie->exp->doInline(ids));
+	    vto->init = ieto;
+	}
+
+	are->lengthVar = (VarDeclaration *) (void *)vto;
+    }
+    are->e2 = e2->doInline(ids);
+    return are;
+}
+
+
+Expression *SliceExp::doInline(InlineDoState *ids)
+{
+    SliceExp *are = (SliceExp *)copy();
+
+    are->e1 = e1->doInline(ids);
+
+    if (lengthVar)
+    {	//printf("lengthVar\n");
+	VarDeclaration *vd = lengthVar;
+	ExpInitializer *ie;
+	ExpInitializer *ieto;
+	VarDeclaration *vto;
+
+	vto = new VarDeclaration(vd->loc, vd->type, vd->ident, vd->init);
+	*vto = *vd;
+	vto->parent = ids->parent;
+	vto->csym = NULL;
+	vto->isym = NULL;
+
+	ids->from.push(vd);
+	ids->to.push(vto);
+
+	if (vd->init)
+	{
+	    ie = vd->init->isExpInitializer();
+	    assert(ie);
+	    ieto = new ExpInitializer(ie->loc, ie->exp->doInline(ids));
+	    vto->init = ieto;
+	}
+
+	are->lengthVar = (VarDeclaration *) (void *)vto;
+    }
+    if (lwr)
+	are->lwr = lwr->doInline(ids);
+    if (upr)
+	are->upr = upr->doInline(ids);
+    return are;
+}
+
+
+Expression *TupleExp::doInline(InlineDoState *ids)
+{
+    TupleExp *ce;
+
+    ce = (TupleExp *)copy();
+    ce->exps = arrayExpressiondoInline(exps, ids);
+    return ce;
+}
+
+
+Expression *ArrayLiteralExp::doInline(InlineDoState *ids)
+{
+    ArrayLiteralExp *ce;
+
+    ce = (ArrayLiteralExp *)copy();
+    ce->elements = arrayExpressiondoInline(elements, ids);
+    return ce;
+}
+
+
+Expression *AssocArrayLiteralExp::doInline(InlineDoState *ids)
+{
+    AssocArrayLiteralExp *ce;
+
+    ce = (AssocArrayLiteralExp *)copy();
+    ce->keys = arrayExpressiondoInline(keys, ids);
+    ce->values = arrayExpressiondoInline(values, ids);
+    return ce;
+}
+
+
+Expression *StructLiteralExp::doInline(InlineDoState *ids)
+{
+    StructLiteralExp *ce;
+
+    ce = (StructLiteralExp *)copy();
+    ce->elements = arrayExpressiondoInline(elements, ids);
+    return ce;
+}
+
+
+Expression *ArrayExp::doInline(InlineDoState *ids)
+{
+    ArrayExp *ce;
+
+    ce = (ArrayExp *)copy();
+    ce->e1 = e1->doInline(ids);
+    ce->arguments = arrayExpressiondoInline(arguments, ids);
+    return ce;
+}
+
+
+Expression *CondExp::doInline(InlineDoState *ids)
+{
+    CondExp *ce = (CondExp *)copy();
+
+    ce->econd = econd->doInline(ids);
+    ce->e1 = e1->doInline(ids);
+    ce->e2 = e2->doInline(ids);
+    return ce;
+}
+
+
+/* ========== Walk the parse trees, and inline expand functions ============= */
+
+/* Walk the trees, looking for functions to inline.
+ * Inline any that can be.
+ */
+
+struct InlineScanState
+{
+    FuncDeclaration *fd;	// function being scanned
+};
+
+Statement *Statement::inlineScan(InlineScanState *iss)
+{
+    return this;
+}
+
+Statement *ExpStatement::inlineScan(InlineScanState *iss)
+{
+#if LOG
+    printf("ExpStatement::inlineScan(%s)\n", toChars());
+#endif
+    if (exp)
+	exp = exp->inlineScan(iss);
+    return this;
+}
+
+Statement *CompoundStatement::inlineScan(InlineScanState *iss)
+{
+    for (size_t i = 0; i < statements->dim; i++)
+    {	Statement *s = (Statement *) statements->data[i];
+	if (s)
+	    statements->data[i] = (void *)s->inlineScan(iss);
+    }
+    return this;
+}
+
+Statement *UnrolledLoopStatement::inlineScan(InlineScanState *iss)
+{
+    for (size_t i = 0; i < statements->dim; i++)
+    {	Statement *s = (Statement *) statements->data[i];
+	if (s)
+	    statements->data[i] = (void *)s->inlineScan(iss);
+    }
+    return this;
+}
+
+Statement *ScopeStatement::inlineScan(InlineScanState *iss)
+{
+    if (statement)
+	statement = statement->inlineScan(iss);
+    return this;
+}
+
+Statement *WhileStatement::inlineScan(InlineScanState *iss)
+{
+    condition = condition->inlineScan(iss);
+    body = body ? body->inlineScan(iss) : NULL;
+    return this;
+}
+
+
+Statement *DoStatement::inlineScan(InlineScanState *iss)
+{
+    body = body ? body->inlineScan(iss) : NULL;
+    condition = condition->inlineScan(iss);
+    return this;
+}
+
+
+Statement *ForStatement::inlineScan(InlineScanState *iss)
+{
+    if (init)
+	init = init->inlineScan(iss);
+    if (condition)
+	condition = condition->inlineScan(iss);
+    if (increment)
+	increment = increment->inlineScan(iss);
+    body = body->inlineScan(iss);
+    return this;
+}
+
+
+Statement *ForeachStatement::inlineScan(InlineScanState *iss)
+{
+    aggr = aggr->inlineScan(iss);
+    body = body->inlineScan(iss);
+    return this;
+}
+
+
+#if V2
+Statement *ForeachRangeStatement::inlineScan(InlineScanState *iss)
+{
+    lwr = lwr->inlineScan(iss);
+    upr = upr->inlineScan(iss);
+    body = body->inlineScan(iss);
+    return this;
+}
+#endif
+
+
+Statement *IfStatement::inlineScan(InlineScanState *iss)
+{
+    condition = condition->inlineScan(iss);
+    if (ifbody)
+	ifbody = ifbody->inlineScan(iss);
+    if (elsebody)
+	elsebody = elsebody->inlineScan(iss);
+    return this;
+}
+
+
+Statement *SwitchStatement::inlineScan(InlineScanState *iss)
+{
+    //printf("SwitchStatement::inlineScan()\n");
+    condition = condition->inlineScan(iss);
+    body = body ? body->inlineScan(iss) : NULL;
+    if (sdefault)
+	sdefault = (DefaultStatement *)sdefault->inlineScan(iss);
+    if (cases)
+    {
+	for (int i = 0; i < cases->dim; i++)
+	{   Statement *s;
+
+	    s = (Statement *) cases->data[i];
+	    cases->data[i] = (void *)s->inlineScan(iss);
+	}
+    }
+    return this;
+}
+
+
+Statement *CaseStatement::inlineScan(InlineScanState *iss)
+{
+    //printf("CaseStatement::inlineScan()\n");
+    exp = exp->inlineScan(iss);
+    if (statement)
+	statement = statement->inlineScan(iss);
+    return this;
+}
+
+
+Statement *DefaultStatement::inlineScan(InlineScanState *iss)
+{
+    if (statement)
+	statement = statement->inlineScan(iss);
+    return this;
+}
+
+
+Statement *ReturnStatement::inlineScan(InlineScanState *iss)
+{
+    if (exp)
+	exp = exp->inlineScan(iss);
+    return this;
+}
+
+
+Statement *SynchronizedStatement::inlineScan(InlineScanState *iss)
+{
+    if (exp)
+	exp = exp->inlineScan(iss);
+    if (body)
+	body = body->inlineScan(iss);
+    return this;
+}
+
+
+Statement *WithStatement::inlineScan(InlineScanState *iss)
+{
+    if (exp)
+	exp = exp->inlineScan(iss);
+    if (body)
+	body = body->inlineScan(iss);
+    return this;
+}
+
+
+Statement *TryCatchStatement::inlineScan(InlineScanState *iss)
+{
+    if (body)
+	body = body->inlineScan(iss);
+    if (catches)
+    {
+	for (int i = 0; i < catches->dim; i++)
+	{   Catch *c = (Catch *)catches->data[i];
+
+	    if (c->handler)
+		c->handler = c->handler->inlineScan(iss);
+	}
+    }
+    return this;
+}
+
+
+Statement *TryFinallyStatement::inlineScan(InlineScanState *iss)
+{
+    if (body)
+	body = body->inlineScan(iss);
+    if (finalbody)
+	finalbody = finalbody->inlineScan(iss);
+    return this;
+}
+
+
+Statement *ThrowStatement::inlineScan(InlineScanState *iss)
+{
+    if (exp)
+	exp = exp->inlineScan(iss);
+    return this;
+}
+
+
+Statement *VolatileStatement::inlineScan(InlineScanState *iss)
+{
+    if (statement)
+	statement = statement->inlineScan(iss);
+    return this;
+}
+
+
+Statement *LabelStatement::inlineScan(InlineScanState *iss)
+{
+    if (statement)
+	statement = statement->inlineScan(iss);
+    return this;
+}
+
+/* -------------------------- */
+
+void arrayInlineScan(InlineScanState *iss, Array *arguments)
+{
+    if (arguments)
+    {
+	for (int i = 0; i < arguments->dim; i++)
+	{   Expression *e = (Expression *)arguments->data[i];
+
+	    if (e)
+	    {
+		e = e->inlineScan(iss);
+		arguments->data[i] = (void *)e;
+	    }
+	}
+    }
+}
+
+Expression *Expression::inlineScan(InlineScanState *iss)
+{
+    return this;
+}
+
+void scanVar(Dsymbol *s, InlineScanState *iss)
+{
+    VarDeclaration *vd = s->isVarDeclaration();
+    if (vd)
+    {
+	TupleDeclaration *td = vd->toAlias()->isTupleDeclaration();
+	if (td)
+	{
+	    for (size_t i = 0; i < td->objects->dim; i++)
+	    {   DsymbolExp *se = (DsymbolExp *)td->objects->data[i];
+		assert(se->op == TOKdsymbol);
+		scanVar(se->s, iss);
+	    }
+	}
+	else
+	{
+	    // Scan initializer (vd->init)
+	    if (vd->init)
+	    {
+		ExpInitializer *ie = vd->init->isExpInitializer();
+
+		if (ie)
+		{
+		    ie->exp = ie->exp->inlineScan(iss);
+		}
+	    }
+	}
+    }
+}
+
+Expression *DeclarationExp::inlineScan(InlineScanState *iss)
+{
+    //printf("DeclarationExp::inlineScan()\n");
+    scanVar(declaration, iss);
+    return this;
+}
+
+Expression *UnaExp::inlineScan(InlineScanState *iss)
+{
+    e1 = e1->inlineScan(iss);
+    return this;
+}
+
+Expression *AssertExp::inlineScan(InlineScanState *iss)
+{
+    e1 = e1->inlineScan(iss);
+    if (msg)
+	msg = msg->inlineScan(iss);
+    return this;
+}
+
+Expression *BinExp::inlineScan(InlineScanState *iss)
+{
+    e1 = e1->inlineScan(iss);
+    e2 = e2->inlineScan(iss);
+    return this;
+}
+
+
+Expression *CallExp::inlineScan(InlineScanState *iss)
+{   Expression *e = this;
+
+    //printf("CallExp::inlineScan()\n");
+    e1 = e1->inlineScan(iss);
+    arrayInlineScan(iss, arguments);
+
+    if (e1->op == TOKvar)
+    {
+	VarExp *ve = (VarExp *)e1;
+	FuncDeclaration *fd = ve->var->isFuncDeclaration();
+
+	if (fd && fd != iss->fd && fd->canInline(0))
+	{
+	    e = fd->doInline(iss, NULL, arguments);
+	}
+    }
+    else if (e1->op == TOKdotvar)
+    {
+	DotVarExp *dve = (DotVarExp *)e1;
+	FuncDeclaration *fd = dve->var->isFuncDeclaration();
+
+	if (fd && fd != iss->fd && fd->canInline(1))
+	{
+	    if (dve->e1->op == TOKcall &&
+		dve->e1->type->toBasetype()->ty == Tstruct)
+	    {
+		/* To create ethis, we'll need to take the address
+		 * of dve->e1, but this won't work if dve->e1 is
+		 * a function call.
+		 */
+		;
+	    }
+	    else
+		e = fd->doInline(iss, dve->e1, arguments);
+	}
+    }
+
+    return e;
+}
+
+
+Expression *SliceExp::inlineScan(InlineScanState *iss)
+{
+    e1 = e1->inlineScan(iss);
+    if (lwr)
+	lwr = lwr->inlineScan(iss);
+    if (upr)
+	upr = upr->inlineScan(iss);
+    return this;
+}
+
+
+Expression *TupleExp::inlineScan(InlineScanState *iss)
+{   Expression *e = this;
+
+    //printf("TupleExp::inlineScan()\n");
+    arrayInlineScan(iss, exps);
+
+    return e;
+}
+
+
+Expression *ArrayLiteralExp::inlineScan(InlineScanState *iss)
+{   Expression *e = this;
+
+    //printf("ArrayLiteralExp::inlineScan()\n");
+    arrayInlineScan(iss, elements);
+
+    return e;
+}
+
+
+Expression *AssocArrayLiteralExp::inlineScan(InlineScanState *iss)
+{   Expression *e = this;
+
+    //printf("AssocArrayLiteralExp::inlineScan()\n");
+    arrayInlineScan(iss, keys);
+    arrayInlineScan(iss, values);
+
+    return e;
+}
+
+
+Expression *StructLiteralExp::inlineScan(InlineScanState *iss)
+{   Expression *e = this;
+
+    //printf("StructLiteralExp::inlineScan()\n");
+    arrayInlineScan(iss, elements);
+
+    return e;
+}
+
+
+Expression *ArrayExp::inlineScan(InlineScanState *iss)
+{   Expression *e = this;
+
+    //printf("ArrayExp::inlineScan()\n");
+    e1 = e1->inlineScan(iss);
+    arrayInlineScan(iss, arguments);
+
+    return e;
+}
+
+
+Expression *CondExp::inlineScan(InlineScanState *iss)
+{
+    econd = econd->inlineScan(iss);
+    e1 = e1->inlineScan(iss);
+    e2 = e2->inlineScan(iss);
+    return this;
+}
+
+
+/* ==========  =============== */
+
+void FuncDeclaration::inlineScan()
+{
+    InlineScanState iss;
+
+#if LOG
+    printf("FuncDeclaration::inlineScan('%s')\n", toChars());
+#endif
+    memset(&iss, 0, sizeof(iss));
+    iss.fd = this;
+    if (fbody)
+    {
+	inlineNest++;
+	fbody = fbody->inlineScan(&iss);
+	inlineNest--;
+    }
+}
+
+int FuncDeclaration::canInline(int hasthis, int hdrscan)
+{
+    InlineCostState ics;
+    int cost;
+
+#define CANINLINE_LOG 0
+
+#if CANINLINE_LOG
+    printf("FuncDeclaration::canInline(hasthis = %d, '%s')\n", hasthis, toChars());
+#endif
+
+    if (needThis() && !hasthis)
+	return 0;
+
+    if (inlineNest || (!semanticRun && !hdrscan))
+    {
+#if CANINLINE_LOG
+	printf("\t1: no, inlineNest = %d, semanticRun = %d\n", inlineNest, semanticRun);
+#endif
+	return 0;
+    }
+
+    switch (inlineStatus)
+    {
+	case ILSyes:
+#if CANINLINE_LOG
+	    printf("\tyes\n");
+#endif
+	    return 1;
+
+	case ILSno:
+#if CANINLINE_LOG
+	    printf("\t2: no\n");
+#endif
+	    return 0;
+
+	case ILSuninitialized:
+	    break;
+
+	default:
+	    assert(0);
+    }
+
+    if (type)
+    {	assert(type->ty == Tfunction);
+	TypeFunction *tf = (TypeFunction *)(type);
+	if (tf->varargs == 1)	// no variadic parameter lists
+	    goto Lno;
+
+	/* Don't inline a function that returns non-void, but has
+	 * no return expression.
+	 */
+	if (tf->next && tf->next->ty != Tvoid &&
+	    !(hasReturnExp & 1) &&
+	    !hdrscan)
+	    goto Lno;
+    }
+    else
+    {	CtorDeclaration *ctor = isCtorDeclaration();
+
+	if (ctor && ctor->varargs == 1)
+	    goto Lno;
+    }
+
+    if (
+	!fbody ||
+	!hdrscan &&
+	(
+#if 0
+	isCtorDeclaration() ||	// cannot because need to convert:
+				//	return;
+				// to:
+				//	return this;
+#endif
+	isSynchronized() ||
+	isImportedSymbol() ||
+	nestedFrameRef ||	// no nested references to this frame
+	(isVirtual() && !isFinal())
+       ))
+    {
+	goto Lno;
+    }
+
+    /* If any parameters are Tsarray's (which are passed by reference)
+     * or out parameters (also passed by reference), don't do inlining.
+     */
+    if (parameters)
+    {
+	for (int i = 0; i < parameters->dim; i++)
+	{
+	    VarDeclaration *v = (VarDeclaration *)parameters->data[i];
+	    if (v->isOut() || v->isRef() || v->type->toBasetype()->ty == Tsarray)
+		goto Lno;
+	}
+    }
+
+    memset(&ics, 0, sizeof(ics));
+    ics.hasthis = hasthis;
+    ics.fd = this;
+    ics.hdrscan = hdrscan;
+    cost = fbody->inlineCost(&ics);
+#if CANINLINE_LOG
+    printf("cost = %d\n", cost);
+#endif
+    if (cost >= COST_MAX)
+	goto Lno;
+
+    if (!hdrscan)    // Don't scan recursively for header content scan
+	inlineScan();
+
+Lyes:
+    if (!hdrscan)    // Don't modify inlineStatus for header content scan
+	inlineStatus = ILSyes;
+#if CANINLINE_LOG
+    printf("\tyes\n");
+#endif
+    return 1;
+
+Lno:
+    if (!hdrscan)    // Don't modify inlineStatus for header content scan
+	inlineStatus = ILSno;
+#if CANINLINE_LOG
+    printf("\tno\n");
+#endif
+    return 0;
+}
+
+Expression *FuncDeclaration::doInline(InlineScanState *iss, Expression *ethis, Array *arguments)
+{
+    InlineDoState ids;
+    DeclarationExp *de;
+    Expression *e = NULL;
+
+#if LOG
+    printf("FuncDeclaration::doInline('%s')\n", toChars());
+#endif
+
+    memset(&ids, 0, sizeof(ids));
+    ids.parent = iss->fd;
+
+    // Set up vthis
+    if (ethis)
+    {
+	VarDeclaration *vthis;
+	ExpInitializer *ei;
+	VarExp *ve;
+
+	if (ethis->type->ty != Tclass && ethis->type->ty != Tpointer)
+	{
+	    ethis = ethis->addressOf(NULL);
+	}
+
+	ei = new ExpInitializer(ethis->loc, ethis);
+
+	vthis = new VarDeclaration(ethis->loc, ethis->type, Id::This, ei);
+	vthis->storage_class = STCin;
+	vthis->linkage = LINKd;
+	vthis->parent = iss->fd;
+
+	ve = new VarExp(vthis->loc, vthis);
+	ve->type = vthis->type;
+
+	ei->exp = new AssignExp(vthis->loc, ve, ethis);
+	ei->exp->type = ve->type;
+
+	ids.vthis = vthis;
+    }
+
+    // Set up parameters
+    if (ethis)
+    {
+	e = new DeclarationExp(0, ids.vthis);
+	e->type = Type::tvoid;
+    }
+
+    if (arguments && arguments->dim)
+    {
+	assert(parameters->dim == arguments->dim);
+
+	for (int i = 0; i < arguments->dim; i++)
+	{
+	    VarDeclaration *vfrom = (VarDeclaration *)parameters->data[i];
+	    VarDeclaration *vto;
+	    Expression *arg = (Expression *)arguments->data[i];
+	    ExpInitializer *ei;
+	    VarExp *ve;
+
+	    ei = new ExpInitializer(arg->loc, arg);
+
+	    vto = new VarDeclaration(vfrom->loc, vfrom->type, vfrom->ident, ei);
+	    vto->storage_class |= vfrom->storage_class & (STCin | STCout | STClazy | STCref);
+	    vto->linkage = vfrom->linkage;
+	    vto->parent = iss->fd;
+	    //printf("vto = '%s', vto->storage_class = x%x\n", vto->toChars(), vto->storage_class);
+	    //printf("vto->parent = '%s'\n", iss->fd->toChars());
+
+	    ve = new VarExp(vto->loc, vto);
+	    //ve->type = vto->type;
+	    ve->type = arg->type;
+
+	    ei->exp = new AssignExp(vto->loc, ve, arg);
+	    ei->exp->type = ve->type;
+//ve->type->print();
+//arg->type->print();
+//ei->exp->print();
+
+	    ids.from.push(vfrom);
+	    ids.to.push(vto);
+
+	    de = new DeclarationExp(0, vto);
+	    de->type = Type::tvoid;
+
+	    e = Expression::combine(e, de);
+	}
+    }
+
+    inlineNest++;
+    Expression *eb = fbody->doInline(&ids);
+    inlineNest--;
+//eb->type->print();
+//eb->print();
+//eb->dump(0);
+    return Expression::combine(e, eb);
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/interpret.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,2106 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "mem.h"
+
+#include "statement.h"
+#include "expression.h"
+#include "cond.h"
+#include "init.h"
+#include "staticassert.h"
+#include "mtype.h"
+#include "scope.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "id.h"
+
+#define LOG	0
+
+struct InterState
+{
+    InterState *caller;		// calling function's InterState
+    FuncDeclaration *fd;	// function being interpreted
+    Dsymbols vars;		// variables used in this function
+    Statement *start;		// if !=NULL, start execution at this statement
+    Statement *gotoTarget;	// target of EXP_GOTO_INTERPRET result
+
+    InterState();
+};
+
+InterState::InterState()
+{
+    memset(this, 0, sizeof(InterState));
+}
+
+Expression *interpret_aaLen(InterState *istate, Expressions *arguments);
+Expression *interpret_aaKeys(InterState *istate, Expressions *arguments);
+Expression *interpret_aaValues(InterState *istate, Expressions *arguments);
+
+/*************************************
+ * Attempt to interpret a function given the arguments.
+ * Input:
+ *	istate	state for calling function (NULL if none)
+ * Return result expression if successful, NULL if not.
+ */
+
+Expression *FuncDeclaration::interpret(InterState *istate, Expressions *arguments)
+{
+#if LOG
+    printf("FuncDeclaration::interpret() %s\n", toChars());
+    printf("cantInterpret = %d, semanticRun = %d\n", cantInterpret, semanticRun);
+#endif
+    if (global.errors)
+	return NULL;
+    if (ident == Id::aaLen)
+	return interpret_aaLen(istate, arguments);
+    else if (ident == Id::aaKeys)
+	return interpret_aaKeys(istate, arguments);
+    else if (ident == Id::aaValues)
+	return interpret_aaValues(istate, arguments);
+
+    if (cantInterpret || semanticRun == 1)
+	return NULL;
+
+    if (needThis() || isNested() || !fbody)
+    {	cantInterpret = 1;
+	return NULL;
+    }
+
+    if (semanticRun == 0 && scope)
+    {
+	semantic3(scope);
+    }
+    if (semanticRun < 2)
+	return NULL;
+
+    Type *tb = type->toBasetype();
+    assert(tb->ty == Tfunction);
+    TypeFunction *tf = (TypeFunction *)tb;
+    Type *tret = tf->next->toBasetype();
+    if (tf->varargs /*|| tret->ty == Tvoid*/)
+    {	cantInterpret = 1;
+	return NULL;
+    }
+
+    if (tf->parameters)
+    {	size_t dim = Argument::dim(tf->parameters);
+	for (size_t i = 0; i < dim; i++)
+	{   Argument *arg = Argument::getNth(tf->parameters, i);
+	    if (arg->storageClass & STClazy)
+	    {   cantInterpret = 1;
+		return NULL;
+	    }
+	}
+    }
+
+    InterState istatex;
+    istatex.caller = istate;
+    istatex.fd = this;
+
+    Expressions vsave;
+    size_t dim = 0;
+    if (arguments)
+    {
+	dim = arguments->dim;
+	assert(!dim || parameters->dim == dim);
+	vsave.setDim(dim);
+
+	for (size_t i = 0; i < dim; i++)
+	{   Expression *earg = (Expression *)arguments->data[i];
+	    Argument *arg = Argument::getNth(tf->parameters, i);
+	    VarDeclaration *v = (VarDeclaration *)parameters->data[i];
+	    vsave.data[i] = v->value;
+#if LOG
+	    printf("arg[%d] = %s\n", i, earg->toChars());
+#endif
+	    if (arg->storageClass & (STCout | STCref))
+	    {
+		/* Bind out or ref parameter to the corresponding
+		 * variable v2
+		 */
+		if (!istate || earg->op != TOKvar)
+		    return NULL;	// can't bind to non-interpreted vars
+
+		VarDeclaration *v2;
+		while (1)
+		{
+		    VarExp *ve = (VarExp *)earg;
+		    v2 = ve->var->isVarDeclaration();
+		    if (!v2)
+			return NULL;
+		    if (!v2->value || v2->value->op != TOKvar)
+			break;
+		    earg = v2->value;
+		}
+
+		v->value = new VarExp(earg->loc, v2);
+
+		/* Don't restore the value of v2 upon function return
+		 */
+		assert(istate);
+		for (size_t i = 0; i < istate->vars.dim; i++)
+		{   VarDeclaration *v = (VarDeclaration *)istate->vars.data[i];
+		    if (v == v2)
+		    {	istate->vars.data[i] = NULL;
+			break;
+		    }
+		}
+	    }
+	    else
+	    {	/* Value parameters
+		 */
+		earg = earg->interpret(&istatex);
+		if (earg == EXP_CANT_INTERPRET)
+		    return NULL;
+		v->value = earg;
+	    }
+#if LOG
+	    printf("interpreted arg[%d] = %s\n", i, earg->toChars());
+#endif
+	}
+    }
+
+    /* Save the values of the local variables used
+     */
+    Expressions valueSaves;
+    if (istate)
+    {
+	//printf("saving state...\n");
+	valueSaves.setDim(istate->vars.dim);
+	for (size_t i = 0; i < istate->vars.dim; i++)
+	{   VarDeclaration *v = (VarDeclaration *)istate->vars.data[i];
+	    if (v)
+	    {
+		//printf("\tsaving [%d] %s = %s\n", i, v->toChars(), v->value->toChars());
+		valueSaves.data[i] = v->value;
+		v->value = NULL;
+	    }
+	}
+    }
+
+    Expression *e = NULL;
+
+    while (1)
+    {
+	e = fbody->interpret(&istatex);
+	if (e == EXP_CANT_INTERPRET)
+	{
+#if LOG
+	    printf("function body failed to interpret\n");
+#endif
+	    e = NULL;
+	}
+
+	/* This is how we deal with a recursive statement AST
+	 * that has arbitrary goto statements in it.
+	 * Bubble up a 'result' which is the target of the goto
+	 * statement, then go recursively down the AST looking
+	 * for that statement, then execute starting there.
+	 */
+	if (e == EXP_GOTO_INTERPRET)
+	{
+	    istatex.start = istatex.gotoTarget;	// set starting statement
+	    istatex.gotoTarget = NULL;
+	}
+	else
+	    break;
+    }
+
+    /* Restore the parameter values
+     */
+    for (size_t i = 0; i < dim; i++)
+    {
+	VarDeclaration *v = (VarDeclaration *)parameters->data[i];
+	v->value = (Expression *)vsave.data[i];
+    }
+
+    if (istate)
+    {
+	/* Restore the variable values
+	 */
+	for (size_t i = 0; i < istate->vars.dim; i++)
+	{   VarDeclaration *v = (VarDeclaration *)istate->vars.data[i];
+	    if (v)
+		v->value = (Expression *)valueSaves.data[i];
+	}
+    }
+
+    return e;
+}
+
+/******************************** Statement ***************************/
+
+#define START()				\
+    if (istate->start)			\
+    {	if (istate->start != this)	\
+	    return NULL;		\
+	istate->start = NULL;		\
+    }
+
+/***********************************
+ * Interpret the statement.
+ * Returns:
+ *	NULL	continue to next statement
+ *	EXP_CANT_INTERPRET	cannot interpret statement at compile time
+ *	!NULL	expression from return statement
+ */
+
+Expression *Statement::interpret(InterState *istate)
+{
+#if LOG
+    printf("Statement::interpret()\n");
+#endif
+    START()
+    return EXP_CANT_INTERPRET;
+}
+
+Expression *ExpStatement::interpret(InterState *istate)
+{
+#if LOG
+    printf("ExpStatement::interpret(%s)\n", exp ? exp->toChars() : "");
+#endif
+    START()
+    if (exp)
+    {
+	Expression *e = exp->interpret(istate);
+	if (e == EXP_CANT_INTERPRET)
+	{
+	    //printf("cannot interpret %s\n", exp->toChars());
+	    return EXP_CANT_INTERPRET;
+	}
+    }
+    return NULL;
+}
+
+Expression *CompoundStatement::interpret(InterState *istate)
+{   Expression *e = NULL;
+
+#if LOG
+    printf("CompoundStatement::interpret()\n");
+#endif
+    if (istate->start == this)
+	istate->start = NULL;
+    if (statements)
+    {
+	for (size_t i = 0; i < statements->dim; i++)
+	{   Statement *s = (Statement *)statements->data[i];
+
+	    if (s)
+	    {
+		e = s->interpret(istate);
+		if (e)
+		    break;
+	    }
+	}
+    }
+#if LOG
+    printf("-CompoundStatement::interpret() %p\n", e);
+#endif
+    return e;
+}
+
+Expression *UnrolledLoopStatement::interpret(InterState *istate)
+{   Expression *e = NULL;
+
+#if LOG
+    printf("UnrolledLoopStatement::interpret()\n");
+#endif
+    if (istate->start == this)
+	istate->start = NULL;
+    if (statements)
+    {
+	for (size_t i = 0; i < statements->dim; i++)
+	{   Statement *s = (Statement *)statements->data[i];
+
+	    e = s->interpret(istate);
+	    if (e == EXP_CANT_INTERPRET)
+		break;
+	    if (e == EXP_CONTINUE_INTERPRET)
+	    {	e = NULL;
+		continue;
+	    }
+	    if (e == EXP_BREAK_INTERPRET)
+	    {	e = NULL;
+		break;
+	    }
+	    if (e)
+		break;
+	}
+    }
+    return e;
+}
+
+Expression *IfStatement::interpret(InterState *istate)
+{
+#if LOG
+    printf("IfStatement::interpret(%s)\n", condition->toChars());
+#endif
+
+    if (istate->start == this)
+	istate->start = NULL;
+    if (istate->start)
+    {
+	Expression *e = NULL;
+	if (ifbody)
+	    e = ifbody->interpret(istate);
+	if (istate->start && elsebody)
+	    e = elsebody->interpret(istate);
+	return e;
+    }
+
+    Expression *e = condition->interpret(istate);
+    assert(e);
+    //if (e == EXP_CANT_INTERPRET) printf("cannot interpret\n");
+    if (e != EXP_CANT_INTERPRET)
+    {
+	if (!e->isConst())
+	{
+	    e = EXP_CANT_INTERPRET;
+	}
+	else
+	{
+	    if (e->isBool(TRUE))
+		e = ifbody ? ifbody->interpret(istate) : NULL;
+	    else if (e->isBool(FALSE))
+		e = elsebody ? elsebody->interpret(istate) : NULL;
+	    else
+	    {
+		e = EXP_CANT_INTERPRET;
+	    }
+	}
+    }
+    return e;
+}
+
+Expression *ScopeStatement::interpret(InterState *istate)
+{
+#if LOG
+    printf("ScopeStatement::interpret()\n");
+#endif
+    if (istate->start == this)
+	istate->start = NULL;
+    return statement ? statement->interpret(istate) : NULL;
+}
+
+Expression *ReturnStatement::interpret(InterState *istate)
+{
+#if LOG
+    printf("ReturnStatement::interpret(%s)\n", exp ? exp->toChars() : "");
+#endif
+    START()
+    if (!exp)
+	return EXP_VOID_INTERPRET;
+#if LOG
+    Expression *e = exp->interpret(istate);
+    printf("e = %p\n", e);
+    return e;
+#else
+    return exp->interpret(istate);
+#endif
+}
+
+Expression *BreakStatement::interpret(InterState *istate)
+{
+#if LOG
+    printf("BreakStatement::interpret()\n");
+#endif
+    START()
+    if (ident)
+	return EXP_CANT_INTERPRET;
+    else
+	return EXP_BREAK_INTERPRET;
+}
+
+Expression *ContinueStatement::interpret(InterState *istate)
+{
+#if LOG
+    printf("ContinueStatement::interpret()\n");
+#endif
+    START()
+    if (ident)
+	return EXP_CANT_INTERPRET;
+    else
+	return EXP_CONTINUE_INTERPRET;
+}
+
+Expression *WhileStatement::interpret(InterState *istate)
+{
+#if LOG
+    printf("WhileStatement::interpret()\n");
+#endif
+    if (istate->start == this)
+	istate->start = NULL;
+    Expression *e;
+
+    if (istate->start)
+    {
+	e = body ? body->interpret(istate) : NULL;
+	if (istate->start)
+	    return NULL;
+	if (e == EXP_CANT_INTERPRET)
+	    return e;
+	if (e == EXP_BREAK_INTERPRET)
+	    return NULL;
+	if (e != EXP_CONTINUE_INTERPRET)
+	    return e;
+    }
+
+    while (1)
+    {
+	e = condition->interpret(istate);
+	if (e == EXP_CANT_INTERPRET)
+	    break;
+	if (!e->isConst())
+	{   e = EXP_CANT_INTERPRET;
+	    break;
+	}
+	if (e->isBool(TRUE))
+	{   e = body ? body->interpret(istate) : NULL;
+	    if (e == EXP_CANT_INTERPRET)
+		break;
+	    if (e == EXP_CONTINUE_INTERPRET)
+		continue;
+	    if (e == EXP_BREAK_INTERPRET)
+	    {	e = NULL;
+		break;
+	    }
+	    if (e)
+		break;
+	}
+	else if (e->isBool(FALSE))
+	{   e = NULL;
+	    break;
+	}
+	else
+	    assert(0);
+    }
+    return e;
+}
+
+Expression *DoStatement::interpret(InterState *istate)
+{
+#if LOG
+    printf("DoStatement::interpret()\n");
+#endif
+    if (istate->start == this)
+	istate->start = NULL;
+    Expression *e;
+
+    if (istate->start)
+    {
+	e = body ? body->interpret(istate) : NULL;
+	if (istate->start)
+	    return NULL;
+	if (e == EXP_CANT_INTERPRET)
+	    return e;
+	if (e == EXP_BREAK_INTERPRET)
+	    return NULL;
+	if (e == EXP_CONTINUE_INTERPRET)
+	    goto Lcontinue;
+	if (e)
+	    return e;
+    }
+
+    while (1)
+    {
+	e = body ? body->interpret(istate) : NULL;
+	if (e == EXP_CANT_INTERPRET)
+	    break;
+	if (e == EXP_BREAK_INTERPRET)
+	{   e = NULL;
+	    break;
+	}
+	if (e && e != EXP_CONTINUE_INTERPRET)
+	    break;
+
+    Lcontinue:
+	e = condition->interpret(istate);
+	if (e == EXP_CANT_INTERPRET)
+	    break;
+	if (!e->isConst())
+	{   e = EXP_CANT_INTERPRET;
+	    break;
+	}
+	if (e->isBool(TRUE))
+	{
+	}
+	else if (e->isBool(FALSE))
+	{   e = NULL;
+	    break;
+	}
+	else
+	    assert(0);
+    }
+    return e;
+}
+
+Expression *ForStatement::interpret(InterState *istate)
+{
+#if LOG
+    printf("ForStatement::interpret()\n");
+#endif
+    if (istate->start == this)
+	istate->start = NULL;
+    Expression *e;
+
+    if (init)
+    {
+	e = init->interpret(istate);
+	if (e == EXP_CANT_INTERPRET)
+	    return e;
+	assert(!e);
+    }
+
+    if (istate->start)
+    {
+	e = body ? body->interpret(istate) : NULL;
+	if (istate->start)
+	    return NULL;
+	if (e == EXP_CANT_INTERPRET)
+	    return e;
+	if (e == EXP_BREAK_INTERPRET)
+	    return NULL;
+	if (e == EXP_CONTINUE_INTERPRET)
+	    goto Lcontinue;
+	if (e)
+	    return e;
+    }
+
+    while (1)
+    {
+	e = condition->interpret(istate);
+	if (e == EXP_CANT_INTERPRET)
+	    break;
+	if (!e->isConst())
+	{   e = EXP_CANT_INTERPRET;
+	    break;
+	}
+	if (e->isBool(TRUE))
+	{   e = body ? body->interpret(istate) : NULL;
+	    if (e == EXP_CANT_INTERPRET)
+		break;
+	    if (e == EXP_BREAK_INTERPRET)
+	    {   e = NULL;
+		break;
+	    }
+	    if (e && e != EXP_CONTINUE_INTERPRET)
+		break;
+	Lcontinue:
+	    e = increment->interpret(istate);
+	    if (e == EXP_CANT_INTERPRET)
+		break;
+	}
+	else if (e->isBool(FALSE))
+	{   e = NULL;
+	    break;
+	}
+	else
+	    assert(0);
+    }
+    return e;
+}
+
+Expression *ForeachStatement::interpret(InterState *istate)
+{
+#if LOG
+    printf("ForeachStatement::interpret()\n");
+#endif
+    if (istate->start == this)
+	istate->start = NULL;
+    if (istate->start)
+	return NULL;
+
+    Expression *e = NULL;
+    Expression *eaggr;
+
+    if (value->isOut() || value->isRef())
+	return EXP_CANT_INTERPRET;
+
+    eaggr = aggr->interpret(istate);
+    if (eaggr == EXP_CANT_INTERPRET)
+	return EXP_CANT_INTERPRET;
+
+    Expression *dim = ArrayLength(Type::tsize_t, eaggr);
+    if (dim == EXP_CANT_INTERPRET)
+	return EXP_CANT_INTERPRET;
+
+    Expression *keysave = key ? key->value : NULL;
+    Expression *valuesave = value->value;
+
+    uinteger_t d = dim->toUInteger();
+    uinteger_t index;
+
+    if (op == TOKforeach)
+    {
+	for (index = 0; index < d; index++)
+	{
+	    Expression *ekey = new IntegerExp(loc, index, Type::tsize_t);
+	    if (key)
+		key->value = ekey;
+	    e = Index(value->type, eaggr, ekey);
+	    if (e == EXP_CANT_INTERPRET)
+		break;
+	    value->value = e;
+
+	    e = body ? body->interpret(istate) : NULL;
+	    if (e == EXP_CANT_INTERPRET)
+		break;
+	    if (e == EXP_BREAK_INTERPRET)
+	    {   e = NULL;
+		break;
+	    }
+	    if (e == EXP_CONTINUE_INTERPRET)
+		e = NULL;
+	    else if (e)
+		break;
+	}
+    }
+    else // TOKforeach_reverse
+    {
+	for (index = d; index-- != 0;)
+	{
+	    Expression *ekey = new IntegerExp(loc, index, Type::tsize_t);
+	    if (key)
+		key->value = ekey;
+	    e = Index(value->type, eaggr, ekey);
+	    if (e == EXP_CANT_INTERPRET)
+		break;
+	    value->value = e;
+
+	    e = body ? body->interpret(istate) : NULL;
+	    if (e == EXP_CANT_INTERPRET)
+		break;
+	    if (e == EXP_BREAK_INTERPRET)
+	    {   e = NULL;
+		break;
+	    }
+	    if (e == EXP_CONTINUE_INTERPRET)
+		e = NULL;
+	    else if (e)
+		break;
+	}
+    }
+    value->value = valuesave;
+    if (key)
+	key->value = keysave;
+    return e;
+}
+
+#if V2
+Expression *ForeachRangeStatement::interpret(InterState *istate)
+{
+#if LOG
+    printf("ForeachRangeStatement::interpret()\n");
+#endif
+    if (istate->start == this)
+	istate->start = NULL;
+    if (istate->start)
+	return NULL;
+
+    Expression *e = NULL;
+    Expression *elwr = lwr->interpret(istate);
+    if (elwr == EXP_CANT_INTERPRET)
+	return EXP_CANT_INTERPRET;
+
+    Expression *eupr = upr->interpret(istate);
+    if (eupr == EXP_CANT_INTERPRET)
+	return EXP_CANT_INTERPRET;
+
+    Expression *keysave = key->value;
+
+    if (op == TOKforeach)
+    {
+	key->value = elwr;
+
+	while (1)
+	{
+	    e = Cmp(TOKlt, key->value->type, key->value, upr);
+	    if (e == EXP_CANT_INTERPRET)
+		break;
+	    if (e->isBool(TRUE) == FALSE)
+	    {	e = NULL;
+		break;
+	    }
+
+	    e = body ? body->interpret(istate) : NULL;
+	    if (e == EXP_CANT_INTERPRET)
+		break;
+	    if (e == EXP_BREAK_INTERPRET)
+	    {   e = NULL;
+		break;
+	    }
+	    e = Add(key->value->type, key->value, new IntegerExp(loc, 1, key->value->type));
+	    if (e == EXP_CANT_INTERPRET)
+		break;
+	    key->value = e;
+	}
+    }
+    else // TOKforeach_reverse
+    {
+	key->value = eupr;
+
+	while (1)
+	{
+	    e = Cmp(TOKgt, key->value->type, key->value, lwr);
+	    if (e == EXP_CANT_INTERPRET)
+		break;
+	    if (e->isBool(TRUE) == FALSE)
+	    {	e = NULL;
+		break;
+	    }
+
+	    e = Min(key->value->type, key->value, new IntegerExp(loc, 1, key->value->type));
+	    if (e == EXP_CANT_INTERPRET)
+		break;
+	    key->value = e;
+
+	    e = body ? body->interpret(istate) : NULL;
+	    if (e == EXP_CANT_INTERPRET)
+		break;
+	    if (e == EXP_BREAK_INTERPRET)
+	    {   e = NULL;
+		break;
+	    }
+	}
+    }
+    key->value = keysave;
+    return e;
+}
+#endif
+
+Expression *SwitchStatement::interpret(InterState *istate)
+{
+#if LOG
+    printf("SwitchStatement::interpret()\n");
+#endif
+    if (istate->start == this)
+	istate->start = NULL;
+    Expression *e = NULL;
+
+    if (istate->start)
+    {
+	e = body ? body->interpret(istate) : NULL;
+	if (istate->start)
+	    return NULL;
+	if (e == EXP_CANT_INTERPRET)
+	    return e;
+	if (e == EXP_BREAK_INTERPRET)
+	    return NULL;
+	return e;
+    }
+
+
+    Expression *econdition = condition->interpret(istate);
+    if (econdition == EXP_CANT_INTERPRET)
+	return EXP_CANT_INTERPRET;
+
+    Statement *s = NULL;
+    if (cases)
+    {
+	for (size_t i = 0; i < cases->dim; i++)
+	{
+	    CaseStatement *cs = (CaseStatement *)cases->data[i];
+	    e = Equal(TOKequal, Type::tint32, econdition, cs->exp);
+	    if (e == EXP_CANT_INTERPRET)
+		return EXP_CANT_INTERPRET;
+	    if (e->isBool(TRUE))
+	    {	s = cs;
+		break;
+	    }
+	}
+    }
+    if (!s)
+    {	if (hasNoDefault)
+	    error("no default or case for %s in switch statement", econdition->toChars());
+	s = sdefault;
+    }
+
+    assert(s);
+    istate->start = s;
+    e = body ? body->interpret(istate) : NULL;
+    assert(!istate->start);
+    if (e == EXP_BREAK_INTERPRET)
+	return NULL;
+    return e;
+}
+
+Expression *CaseStatement::interpret(InterState *istate)
+{
+#if LOG
+    printf("CaseStatement::interpret(%s) this = %p\n", exp->toChars(), this);
+#endif
+    if (istate->start == this)
+	istate->start = NULL;
+    if (statement)
+	return statement->interpret(istate);
+    else
+	return NULL;
+}
+
+Expression *DefaultStatement::interpret(InterState *istate)
+{
+#if LOG
+    printf("DefaultStatement::interpret()\n");
+#endif
+    if (istate->start == this)
+	istate->start = NULL;
+    if (statement)
+	return statement->interpret(istate);
+    else
+	return NULL;
+}
+
+Expression *GotoStatement::interpret(InterState *istate)
+{
+#if LOG
+    printf("GotoStatement::interpret()\n");
+#endif
+    START()
+    assert(label && label->statement);
+    istate->gotoTarget = label->statement;
+    return EXP_GOTO_INTERPRET;
+}
+
+Expression *GotoCaseStatement::interpret(InterState *istate)
+{
+#if LOG
+    printf("GotoCaseStatement::interpret()\n");
+#endif
+    START()
+    assert(cs);
+    istate->gotoTarget = cs;
+    return EXP_GOTO_INTERPRET;
+}
+
+Expression *GotoDefaultStatement::interpret(InterState *istate)
+{
+#if LOG
+    printf("GotoDefaultStatement::interpret()\n");
+#endif
+    START()
+    assert(sw && sw->sdefault);
+    istate->gotoTarget = sw->sdefault;
+    return EXP_GOTO_INTERPRET;
+}
+
+Expression *LabelStatement::interpret(InterState *istate)
+{
+#if LOG
+    printf("LabelStatement::interpret()\n");
+#endif
+    if (istate->start == this)
+	istate->start = NULL;
+    return statement ? statement->interpret(istate) : NULL;
+}
+
+/******************************** Expression ***************************/
+
+Expression *Expression::interpret(InterState *istate)
+{
+#if LOG
+    printf("Expression::interpret() %s\n", toChars());
+#endif
+    return EXP_CANT_INTERPRET;
+}
+
+Expression *NullExp::interpret(InterState *istate)
+{
+    return this;
+}
+
+Expression *IntegerExp::interpret(InterState *istate)
+{
+#if LOG
+    printf("IntegerExp::interpret() %s\n", toChars());
+#endif
+    return this;
+}
+
+Expression *RealExp::interpret(InterState *istate)
+{
+#if LOG
+    printf("RealExp::interpret() %s\n", toChars());
+#endif
+    return this;
+}
+
+Expression *ComplexExp::interpret(InterState *istate)
+{
+    return this;
+}
+
+Expression *StringExp::interpret(InterState *istate)
+{
+#if LOG
+    printf("StringExp::interpret() %s\n", toChars());
+#endif
+    return this;
+}
+
+Expression *getVarExp(Loc loc, InterState *istate, Declaration *d)
+{
+    Expression *e = EXP_CANT_INTERPRET;
+    VarDeclaration *v = d->isVarDeclaration();
+    SymbolDeclaration *s = d->isSymbolDeclaration();
+    if (v)
+    {
+	if (v->isConst() && v->init)
+	{   e = v->init->toExpression();
+	    if (!e->type)
+		e->type = v->type;
+	}
+	else
+	{   e = v->value;
+	    if (!e)
+		error(loc, "variable %s is used before initialization", v->toChars());
+	    else if (e != EXP_CANT_INTERPRET)
+		e = e->interpret(istate);
+	}
+	if (!e)
+	    e = EXP_CANT_INTERPRET;
+    }
+    else if (s)
+    {
+	if (s->dsym->toInitializer() == s->sym)
+	{   Expressions *exps = new Expressions();
+	    e = new StructLiteralExp(0, s->dsym, exps);
+	    e = e->semantic(NULL);
+	}
+    }
+    return e;
+}
+
+Expression *VarExp::interpret(InterState *istate)
+{
+#if LOG
+    printf("VarExp::interpret() %s\n", toChars());
+#endif
+    return getVarExp(loc, istate, var);
+}
+
+Expression *DeclarationExp::interpret(InterState *istate)
+{
+#if LOG
+    printf("DeclarationExp::interpret() %s\n", toChars());
+#endif
+    Expression *e = EXP_CANT_INTERPRET;
+    VarDeclaration *v = declaration->isVarDeclaration();
+    if (v)
+    {
+	Dsymbol *s = v->toAlias();
+	if (s == v && !v->isStatic() && v->init)
+	{
+	    ExpInitializer *ie = v->init->isExpInitializer();
+	    if (ie)
+		e = ie->exp->interpret(istate);
+	    else if (v->init->isVoidInitializer())
+		e = NULL;
+	}
+	else if (s == v && v->isConst() && v->init)
+	{   e = v->init->toExpression();
+	    if (!e)
+		e = EXP_CANT_INTERPRET;
+	    else if (!e->type)
+		e->type = v->type;
+	}
+    }
+    return e;
+}
+
+Expression *TupleExp::interpret(InterState *istate)
+{
+#if LOG
+    printf("TupleExp::interpret() %s\n", toChars());
+#endif
+    Expressions *expsx = NULL;
+
+    for (size_t i = 0; i < exps->dim; i++)
+    {   Expression *e = (Expression *)exps->data[i];
+	Expression *ex;
+
+	ex = e->interpret(istate);
+	if (ex == EXP_CANT_INTERPRET)
+	{   delete expsx;
+	    return ex;
+	}
+
+	/* If any changes, do Copy On Write
+	 */
+	if (ex != e)
+	{
+	    if (!expsx)
+	    {	expsx = new Expressions();
+		expsx->setDim(exps->dim);
+		for (size_t j = 0; j < i; j++)
+		{
+		    expsx->data[j] = exps->data[j];
+		}
+	    }
+	    expsx->data[i] = (void *)ex;
+	}
+    }
+    if (expsx)
+    {	TupleExp *te = new TupleExp(loc, expsx);
+	expandTuples(te->exps);
+	te->type = new TypeTuple(te->exps);
+	return te;
+    }
+    return this;
+}
+
+Expression *ArrayLiteralExp::interpret(InterState *istate)
+{   Expressions *expsx = NULL;
+
+#if LOG
+    printf("ArrayLiteralExp::interpret() %s\n", toChars());
+#endif
+    if (elements)
+    {
+	for (size_t i = 0; i < elements->dim; i++)
+	{   Expression *e = (Expression *)elements->data[i];
+	    Expression *ex;
+
+	    ex = e->interpret(istate);
+	    if (ex == EXP_CANT_INTERPRET)
+	    {   delete expsx;
+		return EXP_CANT_INTERPRET;
+	    }
+
+	    /* If any changes, do Copy On Write
+	     */
+	    if (ex != e)
+	    {
+		if (!expsx)
+		{   expsx = new Expressions();
+		    expsx->setDim(elements->dim);
+		    for (size_t j = 0; j < i; j++)
+		    {
+			expsx->data[j] = elements->data[j];
+		    }
+		}
+		expsx->data[i] = (void *)ex;
+	    }
+	}
+    }
+    if (elements && expsx)
+    {
+	expandTuples(expsx);
+	if (expsx->dim != elements->dim)
+	{   delete expsx;
+	    return EXP_CANT_INTERPRET;
+	}
+	ArrayLiteralExp *ae = new ArrayLiteralExp(loc, expsx);
+	ae->type = type;
+	return ae;
+    }
+    return this;
+}
+
+Expression *AssocArrayLiteralExp::interpret(InterState *istate)
+{   Expressions *keysx = keys;
+    Expressions *valuesx = values;
+
+#if LOG
+    printf("AssocArrayLiteralExp::interpret() %s\n", toChars());
+#endif
+    for (size_t i = 0; i < keys->dim; i++)
+    {   Expression *ekey = (Expression *)keys->data[i];
+	Expression *evalue = (Expression *)values->data[i];
+	Expression *ex;
+
+	ex = ekey->interpret(istate);
+	if (ex == EXP_CANT_INTERPRET)
+	    goto Lerr;
+
+	/* If any changes, do Copy On Write
+	 */
+	if (ex != ekey)
+	{
+	    if (keysx == keys)
+		keysx = (Expressions *)keys->copy();
+	    keysx->data[i] = (void *)ex;
+	}
+
+	ex = evalue->interpret(istate);
+	if (ex == EXP_CANT_INTERPRET)
+	    goto Lerr;
+
+	/* If any changes, do Copy On Write
+	 */
+	if (ex != evalue)
+	{
+	    if (valuesx == values)
+		valuesx = (Expressions *)values->copy();
+	    valuesx->data[i] = (void *)ex;
+	}
+    }
+    if (keysx != keys)
+	expandTuples(keysx);
+    if (valuesx != values)
+	expandTuples(valuesx);
+    if (keysx->dim != valuesx->dim)
+	goto Lerr;
+
+    /* Remove duplicate keys
+     */
+    for (size_t i = 1; i < keysx->dim; i++)
+    {   Expression *ekey = (Expression *)keysx->data[i - 1];
+
+	for (size_t j = i; j < keysx->dim; j++)
+	{   Expression *ekey2 = (Expression *)keysx->data[j];
+	    Expression *ex = Equal(TOKequal, Type::tbool, ekey, ekey2);
+	    if (ex == EXP_CANT_INTERPRET)
+		goto Lerr;
+	    if (ex->isBool(TRUE))	// if a match
+	    {
+		// Remove ekey
+		if (keysx == keys)
+		    keysx = (Expressions *)keys->copy();
+		if (valuesx == values)
+		    valuesx = (Expressions *)values->copy();
+		keysx->remove(i - 1);
+		valuesx->remove(i - 1);
+		i -= 1;		// redo the i'th iteration
+		break;
+	    }
+	}
+    }
+
+    if (keysx != keys || valuesx != values)
+    {
+	AssocArrayLiteralExp *ae;
+	ae = new AssocArrayLiteralExp(loc, keysx, valuesx);
+	ae->type = type;
+	return ae;
+    }
+    return this;
+
+Lerr:
+    if (keysx != keys)
+	delete keysx;
+    if (valuesx != values)
+	delete values;
+    return EXP_CANT_INTERPRET;
+}
+
+Expression *StructLiteralExp::interpret(InterState *istate)
+{   Expressions *expsx = NULL;
+
+#if LOG
+    printf("StructLiteralExp::interpret() %s\n", toChars());
+#endif
+    /* We don't know how to deal with overlapping fields
+     */
+    if (sd->hasUnions)
+	return EXP_CANT_INTERPRET;
+
+    if (elements)
+    {
+	for (size_t i = 0; i < elements->dim; i++)
+	{   Expression *e = (Expression *)elements->data[i];
+	    if (!e)
+		continue;
+
+	    Expression *ex = e->interpret(istate);
+	    if (ex == EXP_CANT_INTERPRET)
+	    {   delete expsx;
+		return EXP_CANT_INTERPRET;
+	    }
+
+	    /* If any changes, do Copy On Write
+	     */
+	    if (ex != e)
+	    {
+		if (!expsx)
+		{   expsx = new Expressions();
+		    expsx->setDim(elements->dim);
+		    for (size_t j = 0; j < elements->dim; j++)
+		    {
+			expsx->data[j] = elements->data[j];
+		    }
+		}
+		expsx->data[i] = (void *)ex;
+	    }
+	}
+    }
+    if (elements && expsx)
+    {
+	expandTuples(expsx);
+	if (expsx->dim != elements->dim)
+	{   delete expsx;
+	    return EXP_CANT_INTERPRET;
+	}
+	StructLiteralExp *se = new StructLiteralExp(loc, sd, expsx);
+	se->type = type;
+	return se;
+    }
+    return this;
+}
+
+Expression *UnaExp::interpretCommon(InterState *istate, Expression *(*fp)(Type *, Expression *))
+{   Expression *e;
+    Expression *e1;
+
+#if LOG
+    printf("UnaExp::interpretCommon() %s\n", toChars());
+#endif
+    e1 = this->e1->interpret(istate);
+    if (e1 == EXP_CANT_INTERPRET)
+	goto Lcant;
+    if (e1->isConst() != 1)
+	goto Lcant;
+
+    e = (*fp)(type, e1);
+    return e;
+
+Lcant:
+    return EXP_CANT_INTERPRET;
+}
+
+#define UNA_INTERPRET(op) \
+Expression *op##Exp::interpret(InterState *istate)	\
+{							\
+    return interpretCommon(istate, &op);		\
+}
+
+UNA_INTERPRET(Neg)
+UNA_INTERPRET(Com)
+UNA_INTERPRET(Not)
+UNA_INTERPRET(Bool)
+
+
+typedef Expression *(*fp_t)(Type *, Expression *, Expression *);
+
+Expression *BinExp::interpretCommon(InterState *istate, fp_t fp)
+{   Expression *e;
+    Expression *e1;
+    Expression *e2;
+
+#if LOG
+    printf("BinExp::interpretCommon() %s\n", toChars());
+#endif
+    e1 = this->e1->interpret(istate);
+    if (e1 == EXP_CANT_INTERPRET)
+	goto Lcant;
+    if (e1->isConst() != 1)
+	goto Lcant;
+
+    e2 = this->e2->interpret(istate);
+    if (e2 == EXP_CANT_INTERPRET)
+	goto Lcant;
+    if (e2->isConst() != 1)
+	goto Lcant;
+
+    e = (*fp)(type, e1, e2);
+    return e;
+
+Lcant:
+    return EXP_CANT_INTERPRET;
+}
+
+#define BIN_INTERPRET(op) \
+Expression *op##Exp::interpret(InterState *istate)	\
+{							\
+    return interpretCommon(istate, &op);		\
+}
+
+BIN_INTERPRET(Add)
+BIN_INTERPRET(Min)
+BIN_INTERPRET(Mul)
+BIN_INTERPRET(Div)
+BIN_INTERPRET(Mod)
+BIN_INTERPRET(Shl)
+BIN_INTERPRET(Shr)
+BIN_INTERPRET(Ushr)
+BIN_INTERPRET(And)
+BIN_INTERPRET(Or)
+BIN_INTERPRET(Xor)
+
+
+typedef Expression *(*fp2_t)(enum TOK, Type *, Expression *, Expression *);
+
+Expression *BinExp::interpretCommon2(InterState *istate, fp2_t fp)
+{   Expression *e;
+    Expression *e1;
+    Expression *e2;
+
+#if LOG
+    printf("BinExp::interpretCommon2() %s\n", toChars());
+#endif
+    e1 = this->e1->interpret(istate);
+    if (e1 == EXP_CANT_INTERPRET)
+	goto Lcant;
+    if (e1->isConst() != 1 &&
+	e1->op != TOKstring &&
+	e1->op != TOKarrayliteral &&
+	e1->op != TOKstructliteral)
+	goto Lcant;
+
+    e2 = this->e2->interpret(istate);
+    if (e2 == EXP_CANT_INTERPRET)
+	goto Lcant;
+    if (e2->isConst() != 1 &&
+	e2->op != TOKstring &&
+	e2->op != TOKarrayliteral &&
+	e2->op != TOKstructliteral)
+	goto Lcant;
+
+    e = (*fp)(op, type, e1, e2);
+    return e;
+
+Lcant:
+    return EXP_CANT_INTERPRET;
+}
+
+#define BIN_INTERPRET2(op) \
+Expression *op##Exp::interpret(InterState *istate)	\
+{							\
+    return interpretCommon2(istate, &op);		\
+}
+
+BIN_INTERPRET2(Equal)
+BIN_INTERPRET2(Identity)
+BIN_INTERPRET2(Cmp)
+
+Expression *BinExp::interpretAssignCommon(InterState *istate, fp_t fp, int post)
+{
+#if LOG
+    printf("BinExp::interpretAssignCommon() %s\n", toChars());
+#endif
+    Expression *e = EXP_CANT_INTERPRET;
+    Expression *e1 = this->e1;
+
+    if (fp)
+    {
+	if (e1->op == TOKcast)
+	{   CastExp *ce = (CastExp *)e1;
+	    e1 = ce->e1;
+	}
+    }
+    if (e1 == EXP_CANT_INTERPRET)
+	return e1;
+    Expression *e2 = this->e2->interpret(istate);
+    if (e2 == EXP_CANT_INTERPRET)
+	return e2;
+
+    /* Assignment to variable of the form:
+     *	v = e2
+     */
+    if (e1->op == TOKvar)
+    {
+	VarExp *ve = (VarExp *)e1;
+	VarDeclaration *v = ve->var->isVarDeclaration();
+	if (v && !v->isDataseg())
+	{
+	    /* Chase down rebinding of out and ref
+	     */
+	    if (v->value && v->value->op == TOKvar)
+	    {
+		ve = (VarExp *)v->value;
+		v = ve->var->isVarDeclaration();
+		assert(v);
+	    }
+
+	    Expression *ev = v->value;
+	    if (fp && !ev)
+	    {	error("variable %s is used before initialization", v->toChars());
+		return e;
+	    }
+	    if (fp)
+		e2 = (*fp)(v->type, ev, e2);
+	    else
+		e2 = Cast(v->type, v->type, e2);
+	    if (e2 != EXP_CANT_INTERPRET)
+	    {
+		if (!v->isParameter())
+		{
+		    for (size_t i = 0; 1; i++)
+		    {
+			if (i == istate->vars.dim)
+			{   istate->vars.push(v);
+			    break;
+			}
+			if (v == (VarDeclaration *)istate->vars.data[i])
+			    break;
+		    }
+		}
+		v->value = e2;
+		e = Cast(type, type, post ? ev : e2);
+	    }
+	}
+    }
+    /* Assignment to struct member of the form:
+     *   *(symoffexp) = e2
+     */
+    else if (e1->op == TOKstar && ((PtrExp *)e1)->e1->op == TOKsymoff)
+    {	SymOffExp *soe = (SymOffExp *)((PtrExp *)e1)->e1;
+	VarDeclaration *v = soe->var->isVarDeclaration();
+
+	if (v->isDataseg())
+	    return EXP_CANT_INTERPRET;
+	if (fp && !v->value)
+	{   error("variable %s is used before initialization", v->toChars());
+	    return e;
+	}
+	if (v->value->op != TOKstructliteral)
+	    return EXP_CANT_INTERPRET;
+	StructLiteralExp *se = (StructLiteralExp *)v->value;
+	int fieldi = se->getFieldIndex(type, soe->offset);
+	if (fieldi == -1)
+	    return EXP_CANT_INTERPRET;
+	Expression *ev = se->getField(type, soe->offset);
+	if (fp)
+	    e2 = (*fp)(type, ev, e2);
+	else
+	    e2 = Cast(type, type, e2);
+	if (e2 == EXP_CANT_INTERPRET)
+	    return e2;
+
+	if (!v->isParameter())
+	{
+	    for (size_t i = 0; 1; i++)
+	    {
+		if (i == istate->vars.dim)
+		{   istate->vars.push(v);
+		    break;
+		}
+		if (v == (VarDeclaration *)istate->vars.data[i])
+		    break;
+	    }
+	}
+
+	/* Create new struct literal reflecting updated fieldi
+	 */
+	Expressions *expsx = new Expressions();
+	expsx->setDim(se->elements->dim);
+	for (size_t j = 0; j < expsx->dim; j++)
+	{
+	    if (j == fieldi)
+		expsx->data[j] = (void *)e2;
+	    else
+		expsx->data[j] = se->elements->data[j];
+	}
+	v->value = new StructLiteralExp(se->loc, se->sd, expsx);
+	v->value->type = se->type;
+
+	e = Cast(type, type, post ? ev : e2);
+    }
+    /* Assignment to array element of the form:
+     *   a[i] = e2
+     */
+    else if (e1->op == TOKindex && ((IndexExp *)e1)->e1->op == TOKvar)
+    {	IndexExp *ie = (IndexExp *)e1;
+	VarExp *ve = (VarExp *)ie->e1;
+	VarDeclaration *v = ve->var->isVarDeclaration();
+
+	if (!v || v->isDataseg())
+	    return EXP_CANT_INTERPRET;
+	if (!v->value)
+	{
+	    if (fp)
+	    {   error("variable %s is used before initialization", v->toChars());
+		return e;
+	    }
+
+	    Type *t = v->type->toBasetype();
+	    if (t->ty == Tsarray)
+	    {
+		/* This array was void initialized. Create a
+		 * default initializer for it.
+		 * What we should do is fill the array literal with
+		 * NULL data, so use-before-initialized can be detected.
+		 * But we're too lazy at the moment to do it, as that
+		 * involves redoing Index() and whoever calls it.
+		 */
+		Expression *ev = v->type->defaultInit();
+		size_t dim = ((TypeSArray *)t)->dim->toInteger();
+		Expressions *elements = new Expressions();
+		elements->setDim(dim);
+		for (size_t i = 0; i < dim; i++)
+		    elements->data[i] = (void *)ev;
+		ArrayLiteralExp *ae = new ArrayLiteralExp(0, elements);
+		ae->type = v->type;
+		v->value = ae;
+	    }
+	    else
+		return EXP_CANT_INTERPRET;
+	}
+
+	ArrayLiteralExp *ae = NULL;
+	AssocArrayLiteralExp *aae = NULL;
+	StringExp *se = NULL;
+	if (v->value->op == TOKarrayliteral)
+	    ae = (ArrayLiteralExp *)v->value;
+	else if (v->value->op == TOKassocarrayliteral)
+	    aae = (AssocArrayLiteralExp *)v->value;
+	else if (v->value->op == TOKstring)
+	    se = (StringExp *)v->value;
+	else
+	    return EXP_CANT_INTERPRET;
+
+	Expression *index = ie->e2->interpret(istate);
+	if (index == EXP_CANT_INTERPRET)
+	    return EXP_CANT_INTERPRET;
+	Expression *ev;
+	if (fp || ae || se)	// not for aae, because key might not be there
+	{
+	    ev = Index(type, v->value, index);
+	    if (ev == EXP_CANT_INTERPRET)
+		return EXP_CANT_INTERPRET;
+	}
+
+	if (fp)
+	    e2 = (*fp)(type, ev, e2);
+	else
+	    e2 = Cast(type, type, e2);
+	if (e2 == EXP_CANT_INTERPRET)
+	    return e2;
+
+	if (!v->isParameter())
+	{
+	    for (size_t i = 0; 1; i++)
+	    {
+		if (i == istate->vars.dim)
+		{   istate->vars.push(v);
+		    break;
+		}
+		if (v == (VarDeclaration *)istate->vars.data[i])
+		    break;
+	    }
+	}
+
+	if (ae)
+	{
+	    /* Create new array literal reflecting updated elem
+	     */
+	    int elemi = index->toInteger();
+	    Expressions *expsx = new Expressions();
+	    expsx->setDim(ae->elements->dim);
+	    for (size_t j = 0; j < expsx->dim; j++)
+	    {
+		if (j == elemi)
+		    expsx->data[j] = (void *)e2;
+		else
+		    expsx->data[j] = ae->elements->data[j];
+	    }
+	    v->value = new ArrayLiteralExp(ae->loc, expsx);
+	    v->value->type = ae->type;
+	}
+	else if (aae)
+	{
+	    /* Create new associative array literal reflecting updated key/value
+	     */
+	    Expressions *keysx = aae->keys;
+	    Expressions *valuesx = new Expressions();
+	    valuesx->setDim(aae->values->dim);
+	    int updated = 0;
+	    for (size_t j = valuesx->dim; j; )
+	    {	j--;
+		Expression *ekey = (Expression *)aae->keys->data[j];
+		Expression *ex = Equal(TOKequal, Type::tbool, ekey, index);
+		if (ex == EXP_CANT_INTERPRET)
+		    return EXP_CANT_INTERPRET;
+		if (ex->isBool(TRUE))
+		{   valuesx->data[j] = (void *)e2;
+		    updated = 1;
+		}
+		else
+		    valuesx->data[j] = aae->values->data[j];
+	    }
+	    if (!updated)
+	    {	// Append index/e2 to keysx[]/valuesx[]
+		valuesx->push(e2);
+		keysx = (Expressions *)keysx->copy();
+		keysx->push(index);
+	    }
+	    v->value = new AssocArrayLiteralExp(aae->loc, keysx, valuesx);
+	    v->value->type = aae->type;
+	}
+	else if (se)
+	{
+	    /* Create new string literal reflecting updated elem
+	     */
+	    int elemi = index->toInteger();
+	    unsigned char *s;
+	    s = (unsigned char *)mem.calloc(se->len + 1, se->sz);
+	    memcpy(s, se->string, se->len * se->sz);
+	    unsigned value = e2->toInteger();
+	    switch (se->sz)
+	    {
+		case 1:	s[elemi] = value; break;
+		case 2:	((unsigned short *)s)[elemi] = value; break;
+		case 4:	((unsigned *)s)[elemi] = value; break;
+		default:
+		    assert(0);
+		    break;
+	    }
+	    StringExp *se2 = new StringExp(se->loc, s, se->len);
+	    se2->committed = se->committed;
+	    se2->postfix = se->postfix;
+	    se2->type = se->type;
+	    v->value = se2;
+	}
+	else
+	    assert(0);
+
+	e = Cast(type, type, post ? ev : e2);
+    }
+    else
+    {
+#ifdef DEBUG
+	dump(0);
+#endif
+    }
+    return e;
+}
+
+Expression *AssignExp::interpret(InterState *istate)
+{
+    return interpretAssignCommon(istate, NULL);
+}
+
+#define BIN_ASSIGN_INTERPRET(op) \
+Expression *op##AssignExp::interpret(InterState *istate)	\
+{								\
+    return interpretAssignCommon(istate, &op);			\
+}
+
+BIN_ASSIGN_INTERPRET(Add)
+BIN_ASSIGN_INTERPRET(Min)
+BIN_ASSIGN_INTERPRET(Cat)
+BIN_ASSIGN_INTERPRET(Mul)
+BIN_ASSIGN_INTERPRET(Div)
+BIN_ASSIGN_INTERPRET(Mod)
+BIN_ASSIGN_INTERPRET(Shl)
+BIN_ASSIGN_INTERPRET(Shr)
+BIN_ASSIGN_INTERPRET(Ushr)
+BIN_ASSIGN_INTERPRET(And)
+BIN_ASSIGN_INTERPRET(Or)
+BIN_ASSIGN_INTERPRET(Xor)
+
+Expression *PostExp::interpret(InterState *istate)
+{
+#if LOG
+    printf("PostExp::interpret() %s\n", toChars());
+#endif
+    Expression *e;
+    if (op == TOKplusplus)
+	e = interpretAssignCommon(istate, &Add, 1);
+    else
+	e = interpretAssignCommon(istate, &Min, 1);
+#if LOG
+    if (e == EXP_CANT_INTERPRET)
+	printf("PostExp::interpret() CANT\n");
+#endif
+    return e;
+}
+
+Expression *AndAndExp::interpret(InterState *istate)
+{
+#if LOG
+    printf("AndAndExp::interpret() %s\n", toChars());
+#endif
+    Expression *e = e1->interpret(istate);
+    if (e != EXP_CANT_INTERPRET)
+    {
+	if (e->isBool(FALSE))
+	    e = new IntegerExp(e1->loc, 0, type);
+	else if (e->isBool(TRUE))
+	{
+	    e = e2->interpret(istate);
+	    if (e != EXP_CANT_INTERPRET)
+	    {
+		if (e->isBool(FALSE))
+		    e = new IntegerExp(e1->loc, 0, type);
+		else if (e->isBool(TRUE))
+		    e = new IntegerExp(e1->loc, 1, type);
+		else
+		    e = EXP_CANT_INTERPRET;
+	    }
+	}
+	else
+	    e = EXP_CANT_INTERPRET;
+    }
+    return e;
+}
+
+Expression *OrOrExp::interpret(InterState *istate)
+{
+#if LOG
+    printf("OrOrExp::interpret() %s\n", toChars());
+#endif
+    Expression *e = e1->interpret(istate);
+    if (e != EXP_CANT_INTERPRET)
+    {
+	if (e->isBool(TRUE))
+	    e = new IntegerExp(e1->loc, 1, type);
+	else if (e->isBool(FALSE))
+	{
+	    e = e2->interpret(istate);
+	    if (e != EXP_CANT_INTERPRET)
+	    {
+		if (e->isBool(FALSE))
+		    e = new IntegerExp(e1->loc, 0, type);
+		else if (e->isBool(TRUE))
+		    e = new IntegerExp(e1->loc, 1, type);
+		else
+		    e = EXP_CANT_INTERPRET;
+	    }
+	}
+	else
+	    e = EXP_CANT_INTERPRET;
+    }
+    return e;
+}
+
+
+Expression *CallExp::interpret(InterState *istate)
+{   Expression *e = EXP_CANT_INTERPRET;
+
+#if LOG
+    printf("CallExp::interpret() %s\n", toChars());
+#endif
+    if (e1->op == TOKvar)
+    {
+	FuncDeclaration *fd = ((VarExp *)e1)->var->isFuncDeclaration();
+	if (fd)
+	{   // Inline .dup
+	    if (fd->ident == Id::adDup && arguments && arguments->dim == 2)
+	    {
+		e = (Expression *)arguments->data[1];
+		e = e->interpret(istate);
+		if (e != EXP_CANT_INTERPRET)
+		{
+		    e = expType(type, e);
+		}
+	    }
+	    else
+	    {
+		Expression *eresult = fd->interpret(istate, arguments);
+		if (eresult)
+		    e = eresult;
+		else if (fd->type->toBasetype()->nextOf()->ty == Tvoid)
+		    e = EXP_VOID_INTERPRET;
+		else
+		    error("cannot evaluate %s at compile time", toChars());
+	    }
+	}
+    }
+    return e;
+}
+
+Expression *CommaExp::interpret(InterState *istate)
+{
+#if LOG
+    printf("CommaExp::interpret() %s\n", toChars());
+#endif
+    Expression *e = e1->interpret(istate);
+    if (e != EXP_CANT_INTERPRET)
+	e = e2->interpret(istate);
+    return e;
+}
+
+Expression *CondExp::interpret(InterState *istate)
+{
+#if LOG
+    printf("CondExp::interpret() %s\n", toChars());
+#endif
+    Expression *e = econd->interpret(istate);
+    if (e != EXP_CANT_INTERPRET)
+    {
+	if (e->isBool(TRUE))
+	    e = e1->interpret(istate);
+	else if (e->isBool(FALSE))
+	    e = e2->interpret(istate);
+	else
+	    e = EXP_CANT_INTERPRET;
+    }
+    return e;
+}
+
+Expression *ArrayLengthExp::interpret(InterState *istate)
+{   Expression *e;
+    Expression *e1;
+
+#if LOG
+    printf("ArrayLengthExp::interpret() %s\n", toChars());
+#endif
+    e1 = this->e1->interpret(istate);
+    if (e1 == EXP_CANT_INTERPRET)
+	goto Lcant;
+    if (e1->op == TOKstring || e1->op == TOKarrayliteral || e1->op == TOKassocarrayliteral)
+    {
+	e = ArrayLength(type, e1);
+    }
+    else
+	goto Lcant;
+    return e;
+
+Lcant:
+    return EXP_CANT_INTERPRET;
+}
+
+Expression *IndexExp::interpret(InterState *istate)
+{   Expression *e;
+    Expression *e1;
+    Expression *e2;
+
+#if LOG
+    printf("IndexExp::interpret() %s\n", toChars());
+#endif
+    e1 = this->e1->interpret(istate);
+    if (e1 == EXP_CANT_INTERPRET)
+	goto Lcant;
+
+    if (e1->op == TOKstring || e1->op == TOKarrayliteral)
+    {
+	/* Set the $ variable
+	 */
+	e = ArrayLength(Type::tsize_t, e1);
+	if (e == EXP_CANT_INTERPRET)
+	    goto Lcant;
+	if (lengthVar)
+	    lengthVar->value = e;
+    }
+
+    e2 = this->e2->interpret(istate);
+    if (e2 == EXP_CANT_INTERPRET)
+	goto Lcant;
+    return Index(type, e1, e2);
+
+Lcant:
+    return EXP_CANT_INTERPRET;
+}
+
+
+Expression *SliceExp::interpret(InterState *istate)
+{   Expression *e;
+    Expression *e1;
+    Expression *lwr;
+    Expression *upr;
+
+#if LOG
+    printf("SliceExp::interpret() %s\n", toChars());
+#endif
+    e1 = this->e1->interpret(istate);
+    if (e1 == EXP_CANT_INTERPRET)
+	goto Lcant;
+    if (!this->lwr)
+    {
+	e = e1->castTo(NULL, type);
+	return e->interpret(istate);
+    }
+
+    /* Set the $ variable
+     */
+    e = ArrayLength(Type::tsize_t, e1);
+    if (e == EXP_CANT_INTERPRET)
+	goto Lcant;
+    if (lengthVar)
+	lengthVar->value = e;
+
+    /* Evaluate lower and upper bounds of slice
+     */
+    lwr = this->lwr->interpret(istate);
+    if (lwr == EXP_CANT_INTERPRET)
+	goto Lcant;
+    upr = this->upr->interpret(istate);
+    if (upr == EXP_CANT_INTERPRET)
+	goto Lcant;
+
+    return Slice(type, e1, lwr, upr);
+
+Lcant:
+    return EXP_CANT_INTERPRET;
+}
+
+
+Expression *CatExp::interpret(InterState *istate)
+{   Expression *e;
+    Expression *e1;
+    Expression *e2;
+
+#if LOG
+    printf("CatExp::interpret() %s\n", toChars());
+#endif
+    e1 = this->e1->interpret(istate);
+    if (e1 == EXP_CANT_INTERPRET)
+    {
+	goto Lcant;
+    }
+    e2 = this->e2->interpret(istate);
+    if (e2 == EXP_CANT_INTERPRET)
+	goto Lcant;
+    return Cat(type, e1, e2);
+
+Lcant:
+#if LOG
+    printf("CatExp::interpret() %s CANT\n", toChars());
+#endif
+    return EXP_CANT_INTERPRET;
+}
+
+
+Expression *CastExp::interpret(InterState *istate)
+{   Expression *e;
+    Expression *e1;
+
+#if LOG
+    printf("CastExp::interpret() %s\n", toChars());
+#endif
+    e1 = this->e1->interpret(istate);
+    if (e1 == EXP_CANT_INTERPRET)
+	goto Lcant;
+    return Cast(type, to, e1);
+
+Lcant:
+#if LOG
+    printf("CastExp::interpret() %s CANT\n", toChars());
+#endif
+    return EXP_CANT_INTERPRET;
+}
+
+
+Expression *AssertExp::interpret(InterState *istate)
+{   Expression *e;
+    Expression *e1;
+
+#if LOG
+    printf("AssertExp::interpret() %s\n", toChars());
+#endif
+    e1 = this->e1->interpret(istate);
+    if (e1 == EXP_CANT_INTERPRET)
+	goto Lcant;
+    if (e1->isBool(TRUE))
+    {
+    }
+    else if (e1->isBool(FALSE))
+    {
+	if (msg)
+	{
+	    e = msg->interpret(istate);
+	    if (e == EXP_CANT_INTERPRET)
+		goto Lcant;
+	    error("%s", e->toChars());
+	}
+	else
+	    error("%s failed", toChars());
+	goto Lcant;
+    }
+    else
+	goto Lcant;
+    return e1;
+
+Lcant:
+    return EXP_CANT_INTERPRET;
+}
+
+Expression *PtrExp::interpret(InterState *istate)
+{   Expression *e = EXP_CANT_INTERPRET;
+
+#if LOG
+    printf("PtrExp::interpret() %s\n", toChars());
+#endif
+
+    // Constant fold *(&structliteral + offset)
+    if (e1->op == TOKadd)
+    {	AddExp *ae = (AddExp *)e1;
+	if (ae->e1->op == TOKaddress && ae->e2->op == TOKint64)
+	{   AddrExp *ade = (AddrExp *)ae->e1;
+	    Expression *ex = ade->e1;
+	    ex = ex->interpret(istate);
+	    if (ex != EXP_CANT_INTERPRET)
+	    {
+		if (ex->op == TOKstructliteral)
+		{   StructLiteralExp *se = (StructLiteralExp *)ex;
+		    unsigned offset = ae->e2->toInteger();
+		    e = se->getField(type, offset);
+		    if (!e)
+			e = EXP_CANT_INTERPRET;
+		    return e;
+		}
+	    }
+	}
+	e = Ptr(type, e1);
+    }
+    else if (e1->op == TOKsymoff)
+    {	SymOffExp *soe = (SymOffExp *)e1;
+	VarDeclaration *v = soe->var->isVarDeclaration();
+	if (v)
+	{   Expression *ev = getVarExp(loc, istate, v);
+	    if (ev != EXP_CANT_INTERPRET && ev->op == TOKstructliteral)
+	    {	StructLiteralExp *se = (StructLiteralExp *)ev;
+		e = se->getField(type, soe->offset);
+		if (!e)
+		    e = EXP_CANT_INTERPRET;
+	    }
+	}
+    }
+#if LOG
+    if (e == EXP_CANT_INTERPRET)
+	printf("PtrExp::interpret() %s = EXP_CANT_INTERPRET\n", toChars());
+#endif
+    return e;
+}
+
+/******************************* Special Functions ***************************/
+
+Expression *interpret_aaLen(InterState *istate, Expressions *arguments)
+{
+    if (!arguments || arguments->dim != 1)
+	return NULL;
+    Expression *earg = (Expression *)arguments->data[0];
+    earg = earg->interpret(istate);
+    if (earg == EXP_CANT_INTERPRET)
+	return NULL;
+    if (earg->op != TOKassocarrayliteral)
+	return NULL;
+    AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg;
+    Expression *e = new IntegerExp(aae->loc, aae->keys->dim, Type::tsize_t);
+    return e;
+}
+
+Expression *interpret_aaKeys(InterState *istate, Expressions *arguments)
+{
+    //printf("interpret_aaKeys()\n");
+    if (!arguments || arguments->dim != 2)
+	return NULL;
+    Expression *earg = (Expression *)arguments->data[0];
+    earg = earg->interpret(istate);
+    if (earg == EXP_CANT_INTERPRET)
+	return NULL;
+    if (earg->op != TOKassocarrayliteral)
+	return NULL;
+    AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg;
+    Expression *e = new ArrayLiteralExp(aae->loc, aae->keys);
+    return e;
+}
+
+Expression *interpret_aaValues(InterState *istate, Expressions *arguments)
+{
+    //printf("interpret_aaValues()\n");
+    if (!arguments || arguments->dim != 3)
+	return NULL;
+    Expression *earg = (Expression *)arguments->data[0];
+    earg = earg->interpret(istate);
+    if (earg == EXP_CANT_INTERPRET)
+	return NULL;
+    if (earg->op != TOKassocarrayliteral)
+	return NULL;
+    AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg;
+    Expression *e = new ArrayLiteralExp(aae->loc, aae->values);
+    //printf("result is %s\n", e->toChars());
+    return e;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/lexer.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,2778 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+/* Lexical Analyzer */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <wchar.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <sys/time.h>
+
+#ifdef IN_GCC
+
+#include <time.h>
+#include "mem.h"
+
+#else
+
+#if __GNUC__
+#include <time.h>
+#endif
+
+#if IN_LLVM
+#include "mem.h"
+#elif _WIN32
+#include "..\root\mem.h"
+#else
+#include "../root/mem.h"
+#endif
+#endif
+
+#include "stringtable.h"
+
+#include "lexer.h"
+#include "utf.h"
+#include "identifier.h"
+#include "id.h"
+#include "module.h"
+
+#if _WIN32 && __DMC__
+// from \dm\src\include\setlocal.h
+extern "C" char * __cdecl __locale_decpoint;
+#endif
+
+extern int HtmlNamedEntity(unsigned char *p, int length);
+
+#define LS 0x2028	// UTF line separator
+#define PS 0x2029	// UTF paragraph separator
+
+/********************************************
+ * Do our own char maps
+ */
+
+static unsigned char cmtable[256];
+
+const int CMoctal =	0x1;
+const int CMhex =	0x2;
+const int CMidchar =	0x4;
+
+inline unsigned char isoctal (unsigned char c) { return cmtable[c] & CMoctal; }
+inline unsigned char ishex   (unsigned char c) { return cmtable[c] & CMhex; }
+inline unsigned char isidchar(unsigned char c) { return cmtable[c] & CMidchar; }
+
+static void cmtable_init()
+{
+    for (unsigned c = 0; c < sizeof(cmtable) / sizeof(cmtable[0]); c++)
+    {
+	if ('0' <= c && c <= '7')
+	    cmtable[c] |= CMoctal;
+	if (isdigit(c) || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F'))
+	    cmtable[c] |= CMhex;
+	if (isalnum(c) || c == '_')
+	    cmtable[c] |= CMidchar;
+    }
+}
+
+
+/************************* Token **********************************************/
+
+char *Token::tochars[TOKMAX];
+
+void *Token::operator new(size_t size)
+{   Token *t;
+
+    if (Lexer::freelist)
+    {
+	t = Lexer::freelist;
+	Lexer::freelist = t->next;
+	return t;
+    }
+
+    return ::operator new(size);
+}
+
+#ifdef DEBUG
+void Token::print()
+{
+    fprintf(stdmsg, "%s\n", toChars());
+}
+#endif
+
+char *Token::toChars()
+{   char *p;
+    static char buffer[3 + 3 * sizeof(value) + 1];
+
+    p = buffer;
+    switch (value)
+    {
+	case TOKint32v:
+#if IN_GCC
+	    sprintf(buffer,"%d",(d_int32)int64value);
+#else
+	    sprintf(buffer,"%d",int32value);
+#endif
+	    break;
+
+	case TOKuns32v:
+	case TOKcharv:
+	case TOKwcharv:
+	case TOKdcharv:
+#if IN_GCC
+	    sprintf(buffer,"%uU",(d_uns32)uns64value);
+#else
+	    sprintf(buffer,"%uU",uns32value);
+#endif
+	    break;
+
+	case TOKint64v:
+	    sprintf(buffer,"%jdL",int64value);
+	    break;
+
+	case TOKuns64v:
+	    sprintf(buffer,"%juUL",uns64value);
+	    break;
+
+#if IN_GCC
+	case TOKfloat32v:
+	case TOKfloat64v:
+	case TOKfloat80v:
+	    float80value.format(buffer, sizeof(buffer));
+	    break;
+	case TOKimaginary32v:
+	case TOKimaginary64v:
+	case TOKimaginary80v:
+	    float80value.format(buffer, sizeof(buffer));
+	    // %% buffer
+	    strcat(buffer, "i");
+	    break;
+#else
+	case TOKfloat32v:
+	    sprintf(buffer,"%Lgf", float80value);
+	    break;
+
+	case TOKfloat64v:
+	    sprintf(buffer,"%Lg", float80value);
+	    break;
+
+	case TOKfloat80v:
+	    sprintf(buffer,"%LgL", float80value);
+	    break;
+
+	case TOKimaginary32v:
+	    sprintf(buffer,"%Lgfi", float80value);
+	    break;
+
+	case TOKimaginary64v:
+	    sprintf(buffer,"%Lgi", float80value);
+	    break;
+
+	case TOKimaginary80v:
+	    sprintf(buffer,"%LgLi", float80value);
+	    break;
+#endif
+
+	case TOKstring:
+#if CSTRINGS
+	    p = string;
+#else
+	{   OutBuffer buf;
+
+	    buf.writeByte('"');
+	    for (size_t i = 0; i < len; )
+	    {	unsigned c;
+
+		utf_decodeChar((unsigned char *)ustring, len, &i, &c);
+		switch (c)
+		{
+		    case 0:
+			break;
+
+		    case '"':
+		    case '\\':
+			buf.writeByte('\\');
+		    default:
+			if (isprint(c))
+			    buf.writeByte(c);
+			else if (c <= 0x7F)
+			    buf.printf("\\x%02x", c);
+			else if (c <= 0xFFFF)
+			    buf.printf("\\u%04x", c);
+			else
+			    buf.printf("\\U%08x", c);
+			continue;
+		}
+		break;
+	    }
+	    buf.writeByte('"');
+	    if (postfix)
+		buf.writeByte('"');
+	    buf.writeByte(0);
+	    p = (char *)buf.extractData();
+	}
+#endif
+	    break;
+
+	case TOKidentifier:
+	case TOKenum:
+	case TOKstruct:
+	case TOKimport:
+	CASE_BASIC_TYPES:
+	    p = ident->toChars();
+	    break;
+
+	default:
+	    p = toChars(value);
+	    break;
+    }
+    return p;
+}
+
+char *Token::toChars(enum TOK value)
+{   char *p;
+    static char buffer[3 + 3 * sizeof(value) + 1];
+
+    p = tochars[value];
+    if (!p)
+    {	sprintf(buffer,"TOK%d",value);
+	p = buffer;
+    }
+    return p;
+}
+
+/*************************** Lexer ********************************************/
+
+Token *Lexer::freelist = NULL;
+StringTable Lexer::stringtable;
+OutBuffer Lexer::stringbuffer;
+
+Lexer::Lexer(Module *mod,
+	unsigned char *base, unsigned begoffset, unsigned endoffset,
+	int doDocComment, int commentToken)
+    : loc(mod, 1)
+{
+    //printf("Lexer::Lexer(%p,%d)\n",base,length);
+    //printf("lexer.mod = %p, %p\n", mod, this->loc.mod);
+    memset(&token,0,sizeof(token));
+    this->base = base;
+    this->end  = base + endoffset;
+    p = base + begoffset;
+    this->mod = mod;
+    this->doDocComment = doDocComment;
+    this->anyToken = 0;
+    this->commentToken = commentToken;
+    //initKeywords();
+
+    /* If first line starts with '#!', ignore the line
+     */
+
+    if (p[0] == '#' && p[1] =='!')
+    {
+	p += 2;
+	while (1)
+	{   unsigned char c = *p;
+	    switch (c)
+	    {
+		case '\n':
+		    p++;
+		    break;
+
+		case '\r':
+		    p++;
+		    if (*p == '\n')
+			p++;
+		    break;
+
+		case 0:
+		case 0x1A:
+		    break;
+
+		default:
+		    if (c & 0x80)
+		    {   unsigned u = decodeUTF();
+			if (u == PS || u == LS)
+			    break;
+		    }
+		    p++;
+		    continue;
+	    }
+	    break;
+	}
+	loc.linnum = 2;
+    }
+}
+
+
+void Lexer::error(const char *format, ...)
+{
+    if (mod && !global.gag)
+    {
+	char *p = loc.toChars();
+	if (*p)
+	    fprintf(stdmsg, "%s: ", p);
+	mem.free(p);
+
+	va_list ap;
+	va_start(ap, format);
+	vfprintf(stdmsg, format, ap);
+	va_end(ap);
+
+	fprintf(stdmsg, "\n");
+	fflush(stdmsg);
+
+	if (global.errors >= 20)	// moderate blizzard of cascading messages
+	    fatal();
+    }
+    global.errors++;
+}
+
+void Lexer::error(Loc loc, const char *format, ...)
+{
+    if (mod && !global.gag)
+    {
+	char *p = loc.toChars();
+	if (*p)
+	    fprintf(stdmsg, "%s: ", p);
+	mem.free(p);
+
+	va_list ap;
+	va_start(ap, format);
+	vfprintf(stdmsg, format, ap);
+	va_end(ap);
+
+	fprintf(stdmsg, "\n");
+	fflush(stdmsg);
+
+	if (global.errors >= 20)	// moderate blizzard of cascading messages
+	    fatal();
+    }
+    global.errors++;
+}
+
+TOK Lexer::nextToken()
+{   Token *t;
+
+    if (token.next)
+    {
+	t = token.next;
+	memcpy(&token,t,sizeof(Token));
+	t->next = freelist;
+	freelist = t;
+    }
+    else
+    {
+	scan(&token);
+    }
+    //token.print();
+    return token.value;
+}
+
+Token *Lexer::peek(Token *ct)
+{   Token *t;
+
+    if (ct->next)
+	t = ct->next;
+    else
+    {
+	t = new Token();
+	scan(t);
+	t->next = NULL;
+	ct->next = t;
+    }
+    return t;
+}
+
+/*********************************
+ * tk is on the opening (.
+ * Look ahead and return token that is past the closing ).
+ */
+
+Token *Lexer::peekPastParen(Token *tk)
+{
+    //printf("peekPastParen()\n");
+    int parens = 1;
+    int curlynest = 0;
+    while (1)
+    {
+	tk = peek(tk);
+	//tk->print();
+	switch (tk->value)
+	{
+	    case TOKlparen:
+		parens++;
+		continue;
+
+	    case TOKrparen:
+		--parens;
+		if (parens)
+		    continue;
+		tk = peek(tk);
+		break;
+
+	    case TOKlcurly:
+		curlynest++;
+		continue;
+
+	    case TOKrcurly:
+		if (--curlynest >= 0)
+		    continue;
+		break;
+
+	    case TOKsemicolon:
+		if (curlynest)
+		    continue;
+		break;
+
+	    case TOKeof:
+		break;
+
+	    default:
+		continue;
+	}
+	return tk;
+    }
+}
+
+/**********************************
+ * Determine if string is a valid Identifier.
+ * Placed here because of commonality with Lexer functionality.
+ * Returns:
+ *	0	invalid
+ */
+
+int Lexer::isValidIdentifier(char *p)
+{
+    size_t len;
+    size_t idx;
+
+    if (!p || !*p)
+	goto Linvalid;
+
+    if (isdigit(*p))
+	goto Linvalid;
+
+    len = strlen(p);
+    idx = 0;
+    while (p[idx])
+    {   dchar_t dc;
+
+	char *q = utf_decodeChar((unsigned char *)p, len, &idx, &dc);
+	if (q)
+	    goto Linvalid;
+
+	if (!((dc >= 0x80 && isUniAlpha(dc)) || isalnum(dc) || dc == '_'))
+	    goto Linvalid;
+    }
+    return 1;
+
+Linvalid:
+    return 0;
+}
+
+/****************************
+ * Turn next token in buffer into a token.
+ */
+
+void Lexer::scan(Token *t)
+{
+    unsigned lastLine = loc.linnum;
+    unsigned linnum;
+
+    t->blockComment = NULL;
+    t->lineComment = NULL;
+    while (1)
+    {
+	t->ptr = p;
+	//printf("p = %p, *p = '%c'\n",p,*p);
+	switch (*p)
+	{
+	    case 0:
+	    case 0x1A:
+		t->value = TOKeof;			// end of file
+		return;
+
+	    case ' ':
+	    case '\t':
+	    case '\v':
+	    case '\f':
+		p++;
+		continue;			// skip white space
+
+	    case '\r':
+		p++;
+		if (*p != '\n')			// if CR stands by itself
+		    loc.linnum++;
+		continue;			// skip white space
+
+	    case '\n':
+		p++;
+		loc.linnum++;
+		continue;			// skip white space
+
+	    case '0':  	case '1':   case '2':   case '3':   case '4':
+	    case '5':  	case '6':   case '7':   case '8':   case '9':
+		t->value = number(t);
+		return;
+
+#if CSTRINGS
+	    case '\'':
+		t->value = charConstant(t, 0);
+		return;
+
+	    case '"':
+		t->value = stringConstant(t,0);
+		return;
+
+	    case 'l':
+	    case 'L':
+		if (p[1] == '\'')
+		{
+		    p++;
+		    t->value = charConstant(t, 1);
+		    return;
+		}
+		else if (p[1] == '"')
+		{
+		    p++;
+		    t->value = stringConstant(t, 1);
+		    return;
+		}
+#else
+	    case '\'':
+		t->value = charConstant(t,0);
+		return;
+
+	    case 'r':
+		if (p[1] != '"')
+		    goto case_ident;
+		p++;
+	    case '`':
+		t->value = wysiwygStringConstant(t, *p);
+		return;
+
+	    case 'x':
+		if (p[1] != '"')
+		    goto case_ident;
+		p++;
+		t->value = hexStringConstant(t);
+		return;
+
+
+	    case '"':
+		t->value = escapeStringConstant(t,0);
+		return;
+
+	    case '\\':			// escaped string literal
+	    {	unsigned c;
+
+		stringbuffer.reset();
+		do
+		{
+		    p++;
+		    c = escapeSequence();
+		    stringbuffer.writeUTF8(c);
+		} while (*p == '\\');
+		t->len = stringbuffer.offset;
+		stringbuffer.writeByte(0);
+		t->ustring = (unsigned char *)mem.malloc(stringbuffer.offset);
+		memcpy(t->ustring, stringbuffer.data, stringbuffer.offset);
+		t->postfix = 0;
+		t->value = TOKstring;
+		return;
+	    }
+
+	    case 'l':
+	    case 'L':
+#endif
+	    case 'a':  	case 'b':   case 'c':   case 'd':   case 'e':
+	    case 'f':  	case 'g':   case 'h':   case 'i':   case 'j':
+	    case 'k':  	            case 'm':   case 'n':   case 'o':
+	    case 'p':  	case 'q': /*case 'r':*/ case 's':   case 't':
+	    case 'u':  	case 'v':   case 'w': /*case 'x':*/ case 'y':
+	    case 'z':
+	    case 'A':  	case 'B':   case 'C':   case 'D':   case 'E':
+	    case 'F':  	case 'G':   case 'H':   case 'I':   case 'J':
+	    case 'K':  	            case 'M':   case 'N':   case 'O':
+	    case 'P':  	case 'Q':   case 'R':   case 'S':   case 'T':
+	    case 'U':  	case 'V':   case 'W':   case 'X':   case 'Y':
+	    case 'Z':
+	    case '_':
+	    case_ident:
+	    {   unsigned char c;
+		StringValue *sv;
+		Identifier *id;
+
+		do
+		{
+		    c = *++p;
+		} while (isidchar(c) || (c & 0x80 && isUniAlpha(decodeUTF())));
+		sv = stringtable.update((char *)t->ptr, p - t->ptr);
+		id = (Identifier *) sv->ptrvalue;
+		if (!id)
+		{   id = new Identifier(sv->lstring.string,TOKidentifier);
+		    sv->ptrvalue = id;
+		}
+		t->ident = id;
+		t->value = (enum TOK) id->value;
+		anyToken = 1;
+		if (*t->ptr == '_')	// if special identifier token
+		{
+		    static char date[11+1];
+		    static char time[8+1];
+		    static char timestamp[24+1];
+
+		    if (!date[0])	// lazy evaluation
+		    {   time_t t;
+			char *p;
+
+			::time(&t);
+			p = ctime(&t);
+			assert(p);
+			sprintf(date, "%.6s %.4s", p + 4, p + 20);
+			sprintf(time, "%.8s", p + 11);
+			sprintf(timestamp, "%.24s", p);
+		    }
+
+		    if (mod && id == Id::FILE)
+		    {
+			t->ustring = (unsigned char *)(loc.filename ? loc.filename : mod->ident->toChars());
+			goto Lstring;
+		    }
+		    else if (mod && id == Id::LINE)
+		    {
+			t->value = TOKint64v;
+			t->uns64value = loc.linnum;
+		    }
+		    else if (id == Id::DATE)
+		    {
+			t->ustring = (unsigned char *)date;
+			goto Lstring;
+		    }
+		    else if (id == Id::TIME)
+		    {
+			t->ustring = (unsigned char *)time;
+			goto Lstring;
+		    }
+		    else if (id == Id::VENDOR)
+		    {
+			t->ustring = (unsigned char *)"Digital Mars D";
+			goto Lstring;
+		    }
+		    else if (id == Id::TIMESTAMP)
+		    {
+			t->ustring = (unsigned char *)timestamp;
+		     Lstring:
+			t->value = TOKstring;
+		     Llen:
+			t->postfix = 0;
+			t->len = strlen((char *)t->ustring);
+		    }
+		    else if (id == Id::VERSIONX)
+		    {	unsigned major = 0;
+			unsigned minor = 0;
+
+			for (char *p = global.version + 1; 1; p++)
+			{
+			    char c = *p;
+			    if (isdigit(c))
+				minor = minor * 10 + c - '0';
+			    else if (c == '.')
+			    {	major = minor;
+				minor = 0;
+			    }
+			    else
+				break;
+			}
+			t->value = TOKint64v;
+			t->uns64value = major * 1000 + minor;
+		    }
+		}
+		//printf("t->value = %d\n",t->value);
+		return;
+	    }
+
+	    case '/':
+		p++;
+		switch (*p)
+		{
+		    case '=':
+			p++;
+			t->value = TOKdivass;
+			return;
+
+		    case '*':
+			p++;
+			linnum = loc.linnum;
+			while (1)
+			{
+			    while (1)
+			    {	unsigned char c = *p;
+				switch (c)
+				{
+				    case '/':
+					break;
+
+				    case '\n':
+					loc.linnum++;
+					p++;
+					continue;
+
+				    case '\r':
+					p++;
+					if (*p != '\n')
+					    loc.linnum++;
+					continue;
+
+				    case 0:
+				    case 0x1A:
+					error("unterminated /* */ comment");
+					p = end;
+					t->value = TOKeof;
+					return;
+
+				    default:
+					if (c & 0x80)
+					{   unsigned u = decodeUTF();
+					    if (u == PS || u == LS)
+						loc.linnum++;
+					}
+					p++;
+					continue;
+				}
+				break;
+			    }
+			    p++;
+			    if (p[-2] == '*' && p - 3 != t->ptr)
+				break;
+			}
+			if (commentToken)
+			{
+			    t->value = TOKcomment;
+			    return;
+			}
+			else if (doDocComment && t->ptr[2] == '*' && p - 4 != t->ptr)
+			{   // if /** but not /**/
+			    getDocComment(t, lastLine == linnum);
+			}
+			continue;
+
+		    case '/':		// do // style comments
+			linnum = loc.linnum;
+			while (1)
+			{   unsigned char c = *++p;
+			    switch (c)
+			    {
+				case '\n':
+				    break;
+
+				case '\r':
+				    if (p[1] == '\n')
+					p++;
+				    break;
+
+				case 0:
+				case 0x1A:
+				    if (commentToken)
+				    {
+					p = end;
+					t->value = TOKcomment;
+					return;
+				    }
+				    if (doDocComment && t->ptr[2] == '/')
+					getDocComment(t, lastLine == linnum);
+				    p = end;
+				    t->value = TOKeof;
+				    return;
+
+				default:
+				    if (c & 0x80)
+				    {   unsigned u = decodeUTF();
+					if (u == PS || u == LS)
+					    break;
+				    }
+				    continue;
+			    }
+			    break;
+			}
+
+			if (commentToken)
+			{
+			    p++;
+			    loc.linnum++;
+			    t->value = TOKcomment;
+			    return;
+			}
+			if (doDocComment && t->ptr[2] == '/')
+			    getDocComment(t, lastLine == linnum);
+
+			p++;
+			loc.linnum++;
+			continue;
+
+		    case '+':
+		    {	int nest;
+
+			linnum = loc.linnum;
+			p++;
+			nest = 1;
+			while (1)
+			{   unsigned char c = *p;
+			    switch (c)
+			    {
+				case '/':
+				    p++;
+				    if (*p == '+')
+				    {
+					p++;
+					nest++;
+				    }
+				    continue;
+
+				case '+':
+				    p++;
+				    if (*p == '/')
+				    {
+					p++;
+					if (--nest == 0)
+					    break;
+				    }
+				    continue;
+
+				case '\r':
+				    p++;
+				    if (*p != '\n')
+					loc.linnum++;
+				    continue;
+
+				case '\n':
+				    loc.linnum++;
+				    p++;
+				    continue;
+
+				case 0:
+				case 0x1A:
+				    error("unterminated /+ +/ comment");
+				    p = end;
+				    t->value = TOKeof;
+				    return;
+
+				default:
+				    if (c & 0x80)
+				    {   unsigned u = decodeUTF();
+					if (u == PS || u == LS)
+					    loc.linnum++;
+				    }
+				    p++;
+				    continue;
+			    }
+			    break;
+			}
+			if (commentToken)
+			{
+			    t->value = TOKcomment;
+			    return;
+			}
+			if (doDocComment && t->ptr[2] == '+' && p - 4 != t->ptr)
+			{   // if /++ but not /++/
+			    getDocComment(t, lastLine == linnum);
+			}
+			continue;
+		    }
+		}
+		t->value = TOKdiv;
+		return;
+
+	    case '.':
+		p++;
+		if (isdigit(*p))
+		{   /* Note that we don't allow ._1 and ._ as being
+		     * valid floating point numbers.
+		     */
+		    p--;
+		    t->value = inreal(t);
+		}
+		else if (p[0] == '.')
+		{
+		    if (p[1] == '.')
+		    {   p += 2;
+			t->value = TOKdotdotdot;
+		    }
+		    else
+		    {   p++;
+			t->value = TOKslice;
+		    }
+		}
+		else
+		    t->value = TOKdot;
+		return;
+
+	    case '&':
+		p++;
+		if (*p == '=')
+		{   p++;
+		    t->value = TOKandass;
+		}
+		else if (*p == '&')
+		{   p++;
+		    t->value = TOKandand;
+		}
+		else
+		    t->value = TOKand;
+		return;
+
+	    case '|':
+		p++;
+		if (*p == '=')
+		{   p++;
+		    t->value = TOKorass;
+		}
+		else if (*p == '|')
+		{   p++;
+		    t->value = TOKoror;
+		}
+		else
+		    t->value = TOKor;
+		return;
+
+	    case '-':
+		p++;
+		if (*p == '=')
+		{   p++;
+		    t->value = TOKminass;
+		}
+#if 0
+		else if (*p == '>')
+		{   p++;
+		    t->value = TOKarrow;
+		}
+#endif
+		else if (*p == '-')
+		{   p++;
+		    t->value = TOKminusminus;
+		}
+		else
+		    t->value = TOKmin;
+		return;
+
+	    case '+':
+		p++;
+		if (*p == '=')
+		{   p++;
+		    t->value = TOKaddass;
+		}
+		else if (*p == '+')
+		{   p++;
+		    t->value = TOKplusplus;
+		}
+		else
+		    t->value = TOKadd;
+		return;
+
+	    case '<':
+		p++;
+		if (*p == '=')
+		{   p++;
+		    t->value = TOKle;			// <=
+		}
+		else if (*p == '<')
+		{   p++;
+		    if (*p == '=')
+		    {   p++;
+			t->value = TOKshlass;		// <<=
+		    }
+		    else
+			t->value = TOKshl;		// <<
+		}
+		else if (*p == '>')
+		{   p++;
+		    if (*p == '=')
+		    {   p++;
+			t->value = TOKleg;		// <>=
+		    }
+		    else
+			t->value = TOKlg;		// <>
+		}
+		else
+		    t->value = TOKlt;			// <
+		return;
+
+	    case '>':
+		p++;
+		if (*p == '=')
+		{   p++;
+		    t->value = TOKge;			// >=
+		}
+		else if (*p == '>')
+		{   p++;
+		    if (*p == '=')
+		    {   p++;
+			t->value = TOKshrass;		// >>=
+		    }
+		    else if (*p == '>')
+		    {	p++;
+			if (*p == '=')
+			{   p++;
+			    t->value = TOKushrass;	// >>>=
+			}
+			else
+			    t->value = TOKushr;		// >>>
+		    }
+		    else
+			t->value = TOKshr;		// >>
+		}
+		else
+		    t->value = TOKgt;			// >
+		return;
+
+	    case '!':
+		p++;
+		if (*p == '=')
+		{   p++;
+		    if (*p == '=' && global.params.Dversion == 1)
+		    {	p++;
+			t->value = TOKnotidentity;	// !==
+		    }
+		    else
+			t->value = TOKnotequal;		// !=
+		}
+		else if (*p == '<')
+		{   p++;
+		    if (*p == '>')
+		    {	p++;
+			if (*p == '=')
+			{   p++;
+			    t->value = TOKunord; // !<>=
+			}
+			else
+			    t->value = TOKue;	// !<>
+		    }
+		    else if (*p == '=')
+		    {	p++;
+			t->value = TOKug;	// !<=
+		    }
+		    else
+			t->value = TOKuge;	// !<
+		}
+		else if (*p == '>')
+		{   p++;
+		    if (*p == '=')
+		    {	p++;
+			t->value = TOKul;	// !>=
+		    }
+		    else
+			t->value = TOKule;	// !>
+		}
+		else
+		    t->value = TOKnot;		// !
+		return;
+
+	    case '=':
+		p++;
+		if (*p == '=')
+		{   p++;
+		    if (*p == '=' && global.params.Dversion == 1)
+		    {	p++;
+			t->value = TOKidentity;		// ===
+		    }
+		    else
+			t->value = TOKequal;		// ==
+		}
+		else
+		    t->value = TOKassign;		// =
+		return;
+
+	    case '~':
+		p++;
+		if (*p == '=')
+		{   p++;
+		    t->value = TOKcatass;		// ~=
+		}
+		else
+		    t->value = TOKtilde;		// ~
+		return;
+
+#define SINGLE(c,tok) case c: p++; t->value = tok; return;
+
+	    SINGLE('(',	TOKlparen)
+	    SINGLE(')', TOKrparen)
+	    SINGLE('[', TOKlbracket)
+	    SINGLE(']', TOKrbracket)
+	    SINGLE('{', TOKlcurly)
+	    SINGLE('}', TOKrcurly)
+	    SINGLE('?', TOKquestion)
+	    SINGLE(',', TOKcomma)
+	    SINGLE(';', TOKsemicolon)
+	    SINGLE(':', TOKcolon)
+	    SINGLE('$', TOKdollar)
+
+#undef SINGLE
+
+#define DOUBLE(c1,tok1,c2,tok2)		\
+	    case c1:			\
+		p++;			\
+		if (*p == c2)		\
+		{   p++;		\
+		    t->value = tok2;	\
+		}			\
+		else			\
+		    t->value = tok1;	\
+		return;
+
+	    DOUBLE('*', TOKmul, '=', TOKmulass)
+	    DOUBLE('%', TOKmod, '=', TOKmodass)
+	    DOUBLE('^', TOKxor, '=', TOKxorass)
+
+#undef DOUBLE
+
+	    case '#':
+		p++;
+		pragma();
+		continue;
+
+	    default:
+	    {	unsigned char c = *p;
+
+		if (c & 0x80)
+		{   unsigned u = decodeUTF();
+
+		    // Check for start of unicode identifier
+		    if (isUniAlpha(u))
+			goto case_ident;
+
+		    if (u == PS || u == LS)
+		    {
+			loc.linnum++;
+			p++;
+			continue;
+		    }
+		}
+		if (isprint(c))
+		    error("unsupported char '%c'", c);
+		else
+		    error("unsupported char 0x%02x", c);
+		p++;
+		continue;
+	    }
+	}
+    }
+}
+
+/*******************************************
+ * Parse escape sequence.
+ */
+
+unsigned Lexer::escapeSequence()
+{   unsigned c;
+    int n;
+    int ndigits;
+
+    c = *p;
+    switch (c)
+    {
+	case '\'':
+	case '"':
+	case '?':
+	case '\\':
+	Lconsume:
+		p++;
+		break;
+
+	case 'a':	c = 7;		goto Lconsume;
+	case 'b':	c = 8;		goto Lconsume;
+	case 'f':	c = 12;		goto Lconsume;
+	case 'n':	c = 10;		goto Lconsume;
+	case 'r':	c = 13;		goto Lconsume;
+	case 't':	c = 9;		goto Lconsume;
+	case 'v':	c = 11;		goto Lconsume;
+
+	case 'u':
+		ndigits = 4;
+		goto Lhex;
+	case 'U':
+		ndigits = 8;
+		goto Lhex;
+	case 'x':
+		ndigits = 2;
+	Lhex:
+		p++;
+		c = *p;
+		if (ishex(c))
+		{   unsigned v;
+
+		    n = 0;
+		    v = 0;
+		    while (1)
+		    {
+			if (isdigit(c))
+			    c -= '0';
+			else if (islower(c))
+			    c -= 'a' - 10;
+			else
+			    c -= 'A' - 10;
+			v = v * 16 + c;
+			c = *++p;
+			if (++n == ndigits)
+			    break;
+			if (!ishex(c))
+			{   error("escape hex sequence has %d hex digits instead of %d", n, ndigits);
+			    break;
+			}
+		    }
+		    if (ndigits != 2 && !utf_isValidDchar(v))
+			error("invalid UTF character \\U%08x", v);
+		    c = v;
+		}
+		else
+		    error("undefined escape hex sequence \\%c\n",c);
+		break;
+
+	case '&':			// named character entity
+		for (unsigned char *idstart = ++p; 1; p++)
+		{
+		    switch (*p)
+		    {
+			case ';':
+			    c = HtmlNamedEntity(idstart, p - idstart);
+			    if (c == ~0)
+			    {   error("unnamed character entity &%.*s;", (int)(p - idstart), idstart);
+				c = ' ';
+			    }
+			    p++;
+			    break;
+
+			default:
+			    if (isalpha(*p) ||
+				(p != idstart + 1 && isdigit(*p)))
+				continue;
+			    error("unterminated named entity");
+			    break;
+		    }
+		    break;
+		}
+		break;
+
+	case 0:
+	case 0x1A:			// end of file
+		c = '\\';
+		break;
+
+	default:
+		if (isoctal(c))
+		{   unsigned char v;
+
+		    n = 0;
+		    v = 0;
+		    do
+		    {
+			v = v * 8 + (c - '0');
+			c = *++p;
+		    } while (++n < 3 && isoctal(c));
+		    c = v;
+		}
+		else
+		    error("undefined escape sequence \\%c\n",c);
+		break;
+    }
+    return c;
+}
+
+/**************************************
+ */
+
+TOK Lexer::wysiwygStringConstant(Token *t, int tc)
+{   unsigned c;
+    Loc start = loc;
+
+    p++;
+    stringbuffer.reset();
+    while (1)
+    {
+	c = *p++;
+	switch (c)
+	{
+	    case '\n':
+		loc.linnum++;
+		break;
+
+	    case '\r':
+		if (*p == '\n')
+		    continue;	// ignore
+		c = '\n';	// treat EndOfLine as \n character
+		loc.linnum++;
+		break;
+
+	    case 0:
+	    case 0x1A:
+		error("unterminated string constant starting at %s", start.toChars());
+		t->ustring = (unsigned char *)"";
+		t->len = 0;
+		t->postfix = 0;
+		return TOKstring;
+
+	    case '"':
+	    case '`':
+		if (c == tc)
+		{
+		    t->len = stringbuffer.offset;
+		    stringbuffer.writeByte(0);
+		    t->ustring = (unsigned char *)mem.malloc(stringbuffer.offset);
+		    memcpy(t->ustring, stringbuffer.data, stringbuffer.offset);
+		    stringPostfix(t);
+		    return TOKstring;
+		}
+		break;
+
+	    default:
+		if (c & 0x80)
+		{   p--;
+		    unsigned u = decodeUTF();
+		    p++;
+		    if (u == PS || u == LS)
+			loc.linnum++;
+		    stringbuffer.writeUTF8(u);
+		    continue;
+		}
+		break;
+	}
+	stringbuffer.writeByte(c);
+    }
+}
+
+/**************************************
+ * Lex hex strings:
+ *	x"0A ae 34FE BD"
+ */
+
+TOK Lexer::hexStringConstant(Token *t)
+{   unsigned c;
+    Loc start = loc;
+    unsigned n = 0;
+    unsigned v;
+
+    p++;
+    stringbuffer.reset();
+    while (1)
+    {
+	c = *p++;
+	switch (c)
+	{
+	    case ' ':
+	    case '\t':
+	    case '\v':
+	    case '\f':
+		continue;			// skip white space
+
+	    case '\r':
+		if (*p == '\n')
+		    continue;			// ignore
+		// Treat isolated '\r' as if it were a '\n'
+	    case '\n':
+		loc.linnum++;
+		continue;
+
+	    case 0:
+	    case 0x1A:
+		error("unterminated string constant starting at %s", start.toChars());
+		t->ustring = (unsigned char *)"";
+		t->len = 0;
+		t->postfix = 0;
+		return TOKstring;
+
+	    case '"':
+		if (n & 1)
+		{   error("odd number (%d) of hex characters in hex string", n);
+		    stringbuffer.writeByte(v);
+		}
+		t->len = stringbuffer.offset;
+		stringbuffer.writeByte(0);
+		t->ustring = (unsigned char *)mem.malloc(stringbuffer.offset);
+		memcpy(t->ustring, stringbuffer.data, stringbuffer.offset);
+		stringPostfix(t);
+		return TOKstring;
+
+	    default:
+		if (c >= '0' && c <= '9')
+		    c -= '0';
+		else if (c >= 'a' && c <= 'f')
+		    c -= 'a' - 10;
+		else if (c >= 'A' && c <= 'F')
+		    c -= 'A' - 10;
+		else if (c & 0x80)
+		{   p--;
+		    unsigned u = decodeUTF();
+		    p++;
+		    if (u == PS || u == LS)
+			loc.linnum++;
+		    else
+			error("non-hex character \\u%x", u);
+		}
+		else
+		    error("non-hex character '%c'", c);
+		if (n & 1)
+		{   v = (v << 4) | c;
+		    stringbuffer.writeByte(v);
+		}
+		else
+		    v = c;
+		n++;
+		break;
+	}
+    }
+}
+
+/**************************************
+ */
+
+TOK Lexer::escapeStringConstant(Token *t, int wide)
+{   unsigned c;
+    Loc start = loc;
+
+    p++;
+    stringbuffer.reset();
+    while (1)
+    {
+	c = *p++;
+	switch (c)
+	{
+	    case '\\':
+		switch (*p)
+		{
+		    case 'u':
+		    case 'U':
+		    case '&':
+			c = escapeSequence();
+			stringbuffer.writeUTF8(c);
+			continue;
+
+		    default:
+			c = escapeSequence();
+			break;
+		}
+		break;
+
+	    case '\n':
+		loc.linnum++;
+		break;
+
+	    case '\r':
+		if (*p == '\n')
+		    continue;	// ignore
+		c = '\n';	// treat EndOfLine as \n character
+		loc.linnum++;
+		break;
+
+	    case '"':
+		t->len = stringbuffer.offset;
+		stringbuffer.writeByte(0);
+		t->ustring = (unsigned char *)mem.malloc(stringbuffer.offset);
+		memcpy(t->ustring, stringbuffer.data, stringbuffer.offset);
+		stringPostfix(t);
+		return TOKstring;
+
+	    case 0:
+	    case 0x1A:
+		p--;
+		error("unterminated string constant starting at %s", start.toChars());
+		t->ustring = (unsigned char *)"";
+		t->len = 0;
+		t->postfix = 0;
+		return TOKstring;
+
+	    default:
+		if (c & 0x80)
+		{
+		    p--;
+		    c = decodeUTF();
+		    if (c == LS || c == PS)
+		    {	c = '\n';
+			loc.linnum++;
+		    }
+		    p++;
+		    stringbuffer.writeUTF8(c);
+		    continue;
+		}
+		break;
+	}
+	stringbuffer.writeByte(c);
+    }
+}
+
+/**************************************
+ */
+
+TOK Lexer::charConstant(Token *t, int wide)
+{
+    unsigned c;
+    TOK tk = TOKcharv;
+
+    //printf("Lexer::charConstant\n");
+    p++;
+    c = *p++;
+    switch (c)
+    {
+	case '\\':
+	    switch (*p)
+	    {
+		case 'u':
+		    t->uns64value = escapeSequence();
+		    tk = TOKwcharv;
+		    break;
+
+		case 'U':
+		case '&':
+		    t->uns64value = escapeSequence();
+		    tk = TOKdcharv;
+		    break;
+
+		default:
+		    t->uns64value = escapeSequence();
+		    break;
+	    }
+	    break;
+
+	case '\n':
+	L1:
+	    loc.linnum++;
+	case '\r':
+	case 0:
+	case 0x1A:
+	case '\'':
+	    error("unterminated character constant");
+	    return tk;
+
+	default:
+	    if (c & 0x80)
+	    {
+		p--;
+		c = decodeUTF();
+		p++;
+		if (c == LS || c == PS)
+		    goto L1;
+		if (c < 0xD800 || (c >= 0xE000 && c < 0xFFFE))
+		    tk = TOKwcharv;
+		else
+		    tk = TOKdcharv;
+	    }
+	    t->uns64value = c;
+	    break;
+    }
+
+    if (*p != '\'')
+    {	error("unterminated character constant");
+	return tk;
+    }
+    p++;
+    return tk;
+}
+
+/***************************************
+ * Get postfix of string literal.
+ */
+
+void Lexer::stringPostfix(Token *t)
+{
+    switch (*p)
+    {
+	case 'c':
+	case 'w':
+	case 'd':
+	    t->postfix = *p;
+	    p++;
+	    break;
+
+	default:
+	    t->postfix = 0;
+	    break;
+    }
+}
+
+/***************************************
+ * Read \u or \U unicode sequence
+ * Input:
+ *	u	'u' or 'U'
+ */
+
+#if 0
+unsigned Lexer::wchar(unsigned u)
+{
+    unsigned value;
+    unsigned n;
+    unsigned char c;
+    unsigned nchars;
+
+    nchars = (u == 'U') ? 8 : 4;
+    value = 0;
+    for (n = 0; 1; n++)
+    {
+	++p;
+	if (n == nchars)
+	    break;
+	c = *p;
+	if (!ishex(c))
+	{   error("\\%c sequence must be followed by %d hex characters", u, nchars);
+	    break;
+	}
+	if (isdigit(c))
+	    c -= '0';
+	else if (islower(c))
+	    c -= 'a' - 10;
+	else
+	    c -= 'A' - 10;
+	value <<= 4;
+	value |= c;
+    }
+    return value;
+}
+#endif
+
+/**************************************
+ * Read in a number.
+ * If it's an integer, store it in tok.TKutok.Vlong.
+ *	integers can be decimal, octal or hex
+ *	Handle the suffixes U, UL, LU, L, etc.
+ * If it's double, store it in tok.TKutok.Vdouble.
+ * Returns:
+ *	TKnum
+ *	TKdouble,...
+ */
+
+TOK Lexer::number(Token *t)
+{
+    // We use a state machine to collect numbers
+    enum STATE { STATE_initial, STATE_0, STATE_decimal, STATE_octal, STATE_octale,
+	STATE_hex, STATE_binary, STATE_hex0, STATE_binary0,
+	STATE_hexh, STATE_error };
+    enum STATE state;
+
+    enum FLAGS
+    {	FLAGS_decimal  = 1,		// decimal
+	FLAGS_unsigned = 2,		// u or U suffix
+	FLAGS_long     = 4,		// l or L suffix
+    };
+    enum FLAGS flags = FLAGS_decimal;
+
+    int i;
+    int base;
+    unsigned c;
+    unsigned char *start;
+    TOK result;
+
+    //printf("Lexer::number()\n");
+    state = STATE_initial;
+    base = 0;
+    stringbuffer.reset();
+    start = p;
+    while (1)
+    {
+	c = *p;
+	switch (state)
+	{
+	    case STATE_initial:		// opening state
+		if (c == '0')
+		    state = STATE_0;
+		else
+		    state = STATE_decimal;
+		break;
+
+	    case STATE_0:
+		flags = (FLAGS) (flags & ~FLAGS_decimal);
+		switch (c)
+		{
+#if ZEROH
+		    case 'H':			// 0h
+		    case 'h':
+			goto hexh;
+#endif
+		    case 'X':
+		    case 'x':
+			state = STATE_hex0;
+			break;
+
+		    case '.':
+			if (p[1] == '.')	// .. is a separate token
+			    goto done;
+		    case 'i':
+		    case 'f':
+		    case 'F':
+			goto real;
+#if ZEROH
+		    case 'E':
+		    case 'e':
+			goto case_hex;
+#endif
+		    case 'B':
+		    case 'b':
+			state = STATE_binary0;
+			break;
+
+		    case '0': case '1': case '2': case '3':
+		    case '4': case '5': case '6': case '7':
+			state = STATE_octal;
+			break;
+
+#if ZEROH
+		    case '8': case '9': case 'A':
+		    case 'C': case 'D': case 'F':
+		    case 'a': case 'c': case 'd': case 'f':
+		    case_hex:
+			state = STATE_hexh;
+			break;
+#endif
+		    case '_':
+			state = STATE_octal;
+			p++;
+			continue;
+
+		    case 'L':
+			if (p[1] == 'i')
+			    goto real;
+			goto done;
+
+		    default:
+			goto done;
+		}
+		break;
+
+	    case STATE_decimal:		// reading decimal number
+		if (!isdigit(c))
+		{
+#if ZEROH
+		    if (ishex(c)
+			|| c == 'H' || c == 'h'
+		       )
+			goto hexh;
+#endif
+		    if (c == '_')		// ignore embedded _
+		    {	p++;
+			continue;
+		    }
+		    if (c == '.' && p[1] != '.')
+			goto real;
+		    else if (c == 'i' || c == 'f' || c == 'F' ||
+			     c == 'e' || c == 'E')
+		    {
+	    real:	// It's a real number. Back up and rescan as a real
+			p = start;
+			return inreal(t);
+		    }
+		    else if (c == 'L' && p[1] == 'i')
+			goto real;
+		    goto done;
+		}
+		break;
+
+	    case STATE_hex0:		// reading hex number
+	    case STATE_hex:
+		if (!ishex(c))
+		{
+		    if (c == '_')		// ignore embedded _
+		    {	p++;
+			continue;
+		    }
+		    if (c == '.' && p[1] != '.')
+			goto real;
+		    if (c == 'P' || c == 'p' || c == 'i')
+			goto real;
+		    if (state == STATE_hex0)
+			error("Hex digit expected, not '%c'", c);
+		    goto done;
+		}
+		state = STATE_hex;
+		break;
+
+#if ZEROH
+	    hexh:
+		state = STATE_hexh;
+	    case STATE_hexh:		// parse numbers like 0FFh
+		if (!ishex(c))
+		{
+		    if (c == 'H' || c == 'h')
+		    {
+			p++;
+			base = 16;
+			goto done;
+		    }
+		    else
+		    {
+			// Check for something like 1E3 or 0E24
+			if (memchr((char *)stringbuffer.data, 'E', stringbuffer.offset) ||
+			    memchr((char *)stringbuffer.data, 'e', stringbuffer.offset))
+			    goto real;
+			error("Hex digit expected, not '%c'", c);
+			goto done;
+		    }
+		}
+		break;
+#endif
+
+	    case STATE_octal:		// reading octal number
+	    case STATE_octale:		// reading octal number with non-octal digits
+		if (!isoctal(c))
+		{
+#if ZEROH
+		    if (ishex(c)
+			|| c == 'H' || c == 'h'
+		       )
+			goto hexh;
+#endif
+		    if (c == '_')		// ignore embedded _
+		    {	p++;
+			continue;
+		    }
+		    if (c == '.' && p[1] != '.')
+			goto real;
+		    if (c == 'i')
+			goto real;
+		    if (isdigit(c))
+		    {
+			state = STATE_octale;
+		    }
+		    else
+			goto done;
+		}
+		break;
+
+	    case STATE_binary0:		// starting binary number
+	    case STATE_binary:		// reading binary number
+		if (c != '0' && c != '1')
+		{
+#if ZEROH
+		    if (ishex(c)
+			|| c == 'H' || c == 'h'
+		       )
+			goto hexh;
+#endif
+		    if (c == '_')		// ignore embedded _
+		    {	p++;
+			continue;
+		    }
+		    if (state == STATE_binary0)
+		    {	error("binary digit expected");
+			state = STATE_error;
+			break;
+		    }
+		    else
+			goto done;
+		}
+		state = STATE_binary;
+		break;
+
+	    case STATE_error:		// for error recovery
+		if (!isdigit(c))	// scan until non-digit
+		    goto done;
+		break;
+
+	    default:
+		assert(0);
+	}
+	stringbuffer.writeByte(c);
+	p++;
+    }
+done:
+    stringbuffer.writeByte(0);		// terminate string
+    if (state == STATE_octale)
+	error("Octal digit expected");
+
+    uinteger_t n;			// unsigned >=64 bit integer type
+
+    if (stringbuffer.offset == 2 && (state == STATE_decimal || state == STATE_0))
+	n = stringbuffer.data[0] - '0';
+    else
+    {
+	// Convert string to integer
+#if __DMC__
+	errno = 0;
+	n = strtoull((char *)stringbuffer.data,NULL,base);
+	if (errno == ERANGE)
+	    error("integer overflow");
+#else
+	// Not everybody implements strtoull()
+	char *p = (char *)stringbuffer.data;
+	int r = 10, d;
+
+	if (*p == '0')
+	{
+	    if (p[1] == 'x' || p[1] == 'X')
+		p += 2, r = 16;
+	    else if (p[1] == 'b' || p[1] == 'B')
+		p += 2, r = 2;
+	    else if (isdigit(p[1]))
+		p += 1, r = 8;
+	}
+
+	n = 0;
+	while (1)
+	{
+	    if (*p >= '0' && *p <= '9')
+		d = *p - '0';
+	    else if (*p >= 'a' && *p <= 'z')
+		d = *p - 'a' + 10;
+	    else if (*p >= 'A' && *p <= 'Z')
+		d = *p - 'A' + 10;
+	    else
+		break;
+	    if (d >= r)
+		break;
+	    if (n * r + d < n)
+	    {
+		error ("integer overflow");
+		break;
+	    }
+
+	    n = n * r + d;
+	    p++;
+	}
+#endif
+	if (sizeof(n) > 8 &&
+	    n > 0xFFFFFFFFFFFFFFFFULL)	// if n needs more than 64 bits
+	    error("integer overflow");
+    }
+
+    // Parse trailing 'u', 'U', 'l' or 'L' in any combination
+    while (1)
+    {   unsigned char f;
+
+	switch (*p)
+	{   case 'U':
+	    case 'u':
+		f = FLAGS_unsigned;
+		goto L1;
+
+	    case 'l':
+		if (1 || !global.params.useDeprecated)
+		    error("'l' suffix is deprecated, use 'L' instead");
+	    case 'L':
+		f = FLAGS_long;
+	    L1:
+		p++;
+		if (flags & f)
+		    error("unrecognized token");
+		flags = (FLAGS) (flags | f);
+		continue;
+	    default:
+		break;
+	}
+	break;
+    }
+
+    switch (flags)
+    {
+	case 0:
+	    /* Octal or Hexadecimal constant.
+	     * First that fits: int, uint, long, ulong
+	     */
+	    if (n & 0x8000000000000000LL)
+		    result = TOKuns64v;
+	    else if (n & 0xFFFFFFFF00000000LL)
+		    result = TOKint64v;
+	    else if (n & 0x80000000)
+		    result = TOKuns32v;
+	    else
+		    result = TOKint32v;
+	    break;
+
+	case FLAGS_decimal:
+	    /* First that fits: int, long, long long
+	     */
+	    if (n & 0x8000000000000000LL)
+	    {	    error("signed integer overflow");
+		    result = TOKuns64v;
+	    }
+	    else if (n & 0xFFFFFFFF80000000LL)
+		    result = TOKint64v;
+	    else
+		    result = TOKint32v;
+	    break;
+
+	case FLAGS_unsigned:
+	case FLAGS_decimal | FLAGS_unsigned:
+	    /* First that fits: uint, ulong
+	     */
+	    if (n & 0xFFFFFFFF00000000LL)
+		    result = TOKuns64v;
+	    else
+		    result = TOKuns32v;
+	    break;
+
+	case FLAGS_decimal | FLAGS_long:
+	    if (n & 0x8000000000000000LL)
+	    {	    error("signed integer overflow");
+		    result = TOKuns64v;
+	    }
+	    else
+		    result = TOKint64v;
+	    break;
+
+	case FLAGS_long:
+	    if (n & 0x8000000000000000LL)
+		    result = TOKuns64v;
+	    else
+		    result = TOKint64v;
+	    break;
+
+	case FLAGS_unsigned | FLAGS_long:
+	case FLAGS_decimal | FLAGS_unsigned | FLAGS_long:
+	    result = TOKuns64v;
+	    break;
+
+	default:
+	    #ifdef DEBUG
+		printf("%x\n",flags);
+	    #endif
+	    assert(0);
+    }
+    t->uns64value = n;
+    return result;
+}
+
+/**************************************
+ * Read in characters, converting them to real.
+ * Bugs:
+ *	Exponent overflow not detected.
+ *	Too much requested precision is not detected.
+ */
+
+TOK Lexer::inreal(Token *t)
+#ifdef __DMC__
+__in
+{
+    assert(*p == '.' || isdigit(*p));
+}
+__out (result)
+{
+    switch (result)
+    {
+	case TOKfloat32v:
+	case TOKfloat64v:
+	case TOKfloat80v:
+	case TOKimaginary32v:
+	case TOKimaginary64v:
+	case TOKimaginary80v:
+	    break;
+
+	default:
+	    assert(0);
+    }
+}
+__body
+#endif /* __DMC__ */
+{   int dblstate;
+    unsigned c;
+    char hex;			// is this a hexadecimal-floating-constant?
+    TOK result;
+
+    //printf("Lexer::inreal()\n");
+    stringbuffer.reset();
+    dblstate = 0;
+    hex = 0;
+Lnext:
+    while (1)
+    {
+	// Get next char from input
+	c = *p++;
+	//printf("dblstate = %d, c = '%c'\n", dblstate, c);
+	while (1)
+	{
+	    switch (dblstate)
+	    {
+		case 0:			// opening state
+		    if (c == '0')
+			dblstate = 9;
+		    else if (c == '.')
+			dblstate = 3;
+		    else
+			dblstate = 1;
+		    break;
+
+		case 9:
+		    dblstate = 1;
+		    if (c == 'X' || c == 'x')
+		    {	hex++;
+			break;
+		    }
+		case 1:			// digits to left of .
+		case 3:			// digits to right of .
+		case 7:			// continuing exponent digits
+		    if (!isdigit(c) && !(hex && isxdigit(c)))
+		    {
+			if (c == '_')
+			    goto Lnext;	// ignore embedded '_'
+			dblstate++;
+			continue;
+		    }
+		    break;
+
+		case 2:			// no more digits to left of .
+		    if (c == '.')
+		    {   dblstate++;
+			break;
+		    }
+		case 4:			// no more digits to right of .
+		    if ((c == 'E' || c == 'e') ||
+			hex && (c == 'P' || c == 'p'))
+		    {   dblstate = 5;
+			hex = 0;	// exponent is always decimal
+			break;
+		    }
+		    if (hex)
+			error("binary-exponent-part required");
+		    goto done;
+
+		case 5:			// looking immediately to right of E
+		    dblstate++;
+		    if (c == '-' || c == '+')
+			break;
+		case 6:			// 1st exponent digit expected
+		    if (!isdigit(c))
+			error("exponent expected");
+		    dblstate++;
+		    break;
+
+		case 8:			// past end of exponent digits
+		    goto done;
+	    }
+	    break;
+	}
+	stringbuffer.writeByte(c);
+    }
+done:
+    p--;
+
+    stringbuffer.writeByte(0);
+
+#if _WIN32 && __DMC__
+    char *save = __locale_decpoint;
+    __locale_decpoint = ".";
+#endif
+#ifdef IN_GCC
+    t->float80value = real_t::parse((char *)stringbuffer.data, real_t::LongDouble);
+#else
+    t->float80value = strtold((char *)stringbuffer.data, NULL);
+#endif
+    errno = 0;
+    switch (*p)
+    {
+	case 'F':
+	case 'f':
+#ifdef IN_GCC
+	    real_t::parse((char *)stringbuffer.data, real_t::Float);
+#else
+	    strtof((char *)stringbuffer.data, NULL);
+#endif
+	    result = TOKfloat32v;
+	    p++;
+	    break;
+
+	default:
+#ifdef IN_GCC
+	    real_t::parse((char *)stringbuffer.data, real_t::Double);
+#else
+	    strtod((char *)stringbuffer.data, NULL);
+#endif
+	    result = TOKfloat64v;
+	    break;
+
+	case 'l':
+	    if (!global.params.useDeprecated)
+		error("'l' suffix is deprecated, use 'L' instead");
+	case 'L':
+	    result = TOKfloat80v;
+	    p++;
+	    break;
+    }
+    if (*p == 'i' || *p == 'I')
+    {
+	if (!global.params.useDeprecated && *p == 'I')
+	    error("'I' suffix is deprecated, use 'i' instead");
+	p++;
+	switch (result)
+	{
+	    case TOKfloat32v:
+		result = TOKimaginary32v;
+		break;
+	    case TOKfloat64v:
+		result = TOKimaginary64v;
+		break;
+	    case TOKfloat80v:
+		result = TOKimaginary80v;
+		break;
+	}
+    }
+#if _WIN32 && __DMC__
+    __locale_decpoint = save;
+#endif
+    if (errno == ERANGE)
+	error("number is not representable");
+    return result;
+}
+
+/*********************************************
+ * Do pragma.
+ * Currently, the only pragma supported is:
+ *	#line linnum [filespec]
+ */
+
+void Lexer::pragma()
+{
+    Token tok;
+    int linnum;
+    char *filespec = NULL;
+    Loc loc = this->loc;
+
+    scan(&tok);
+    if (tok.value != TOKidentifier || tok.ident != Id::line)
+	goto Lerr;
+
+    scan(&tok);
+    if (tok.value == TOKint32v || tok.value == TOKint64v)
+	linnum = tok.uns64value - 1;
+    else
+	goto Lerr;
+
+    while (1)
+    {
+	switch (*p)
+	{
+	    case 0:
+	    case 0x1A:
+	    case '\n':
+	    Lnewline:
+		this->loc.linnum = linnum;
+		if (filespec)
+		    this->loc.filename = filespec;
+		return;
+
+	    case '\r':
+		p++;
+		if (*p != '\n')
+		{   p--;
+		    goto Lnewline;
+		}
+		continue;
+
+	    case ' ':
+	    case '\t':
+	    case '\v':
+	    case '\f':
+		p++;
+		continue;			// skip white space
+
+	    case '_':
+		if (mod && memcmp(p, "__FILE__", 8) == 0)
+		{
+		    p += 8;
+		    filespec = mem.strdup(loc.filename ? loc.filename : mod->ident->toChars());
+		}
+		continue;
+
+	    case '"':
+		if (filespec)
+		    goto Lerr;
+		stringbuffer.reset();
+		p++;
+		while (1)
+		{   unsigned c;
+
+		    c = *p;
+		    switch (c)
+		    {
+			case '\n':
+			case '\r':
+			case 0:
+			case 0x1A:
+			    goto Lerr;
+
+			case '"':
+			    stringbuffer.writeByte(0);
+			    filespec = mem.strdup((char *)stringbuffer.data);
+			    p++;
+			    break;
+
+			default:
+			    if (c & 0x80)
+			    {   unsigned u = decodeUTF();
+				if (u == PS || u == LS)
+				    goto Lerr;
+			    }
+			    stringbuffer.writeByte(c);
+			    p++;
+			    continue;
+		    }
+		    break;
+		}
+		continue;
+
+	    default:
+		if (*p & 0x80)
+		{   unsigned u = decodeUTF();
+		    if (u == PS || u == LS)
+			goto Lnewline;
+		}
+		goto Lerr;
+	}
+    }
+
+Lerr:
+    error(loc, "#line integer [\"filespec\"]\\n expected");
+}
+
+
+/********************************************
+ * Decode UTF character.
+ * Issue error messages for invalid sequences.
+ * Return decoded character, advance p to last character in UTF sequence.
+ */
+
+unsigned Lexer::decodeUTF()
+{
+    dchar_t u;
+    unsigned char c;
+    unsigned char *s = p;
+    size_t len;
+    size_t idx;
+    char *msg;
+
+    c = *s;
+    assert(c & 0x80);
+
+    // Check length of remaining string up to 6 UTF-8 characters
+    for (len = 1; len < 6 && s[len]; len++)
+	;
+
+    idx = 0;
+    msg = utf_decodeChar(s, len, &idx, &u);
+    p += idx - 1;
+    if (msg)
+    {
+	error("%s", msg);
+    }
+    return u;
+}
+
+
+/***************************************************
+ * Parse doc comment embedded between t->ptr and p.
+ * Remove trailing blanks and tabs from lines.
+ * Replace all newlines with \n.
+ * Remove leading comment character from each line.
+ * Decide if it's a lineComment or a blockComment.
+ * Append to previous one for this token.
+ */
+
+void Lexer::getDocComment(Token *t, unsigned lineComment)
+{
+    OutBuffer buf;
+    unsigned char ct = t->ptr[2];
+    unsigned char *q = t->ptr + 3;	// start of comment text
+    int linestart = 0;
+
+    unsigned char *qend = p;
+    if (ct == '*' || ct == '+')
+	qend -= 2;
+
+    /* Scan over initial row of ****'s or ++++'s or ////'s
+     */
+    for (; q < qend; q++)
+    {
+	if (*q != ct)
+	    break;
+    }
+
+    /* Remove trailing row of ****'s or ++++'s
+     */
+    if (ct != '/')
+    {
+	for (; q < qend; qend--)
+	{
+	    if (qend[-1] != ct)
+		break;
+	}
+    }
+
+    for (; q < qend; q++)
+    {
+	unsigned char c = *q;
+
+	switch (c)
+	{
+	    case '*':
+	    case '+':
+		if (linestart && c == ct)
+		{   linestart = 0;
+		    /* Trim preceding whitespace up to preceding \n
+		     */
+		    while (buf.offset && (buf.data[buf.offset - 1] == ' ' || buf.data[buf.offset - 1] == '\t'))
+			buf.offset--;
+		    continue;
+		}
+		break;
+
+	    case ' ':
+	    case '\t':
+		break;
+
+	    case '\r':
+		if (q[1] == '\n')
+		    continue;		// skip the \r
+		goto Lnewline;
+
+	    default:
+		if (c == 226)
+		{
+		    // If LS or PS
+		    if (q[1] == 128 &&
+			(q[2] == 168 || q[2] == 169))
+		    {
+			q += 2;
+			goto Lnewline;
+		    }
+		}
+		linestart = 0;
+		break;
+
+	    Lnewline:
+		c = '\n';		// replace all newlines with \n
+	    case '\n':
+		linestart = 1;
+
+		/* Trim trailing whitespace
+		 */
+		while (buf.offset && (buf.data[buf.offset - 1] == ' ' || buf.data[buf.offset - 1] == '\t'))
+		    buf.offset--;
+
+		break;
+	}
+	buf.writeByte(c);
+    }
+
+    // Always end with a newline
+    if (!buf.offset || buf.data[buf.offset - 1] != '\n')
+	buf.writeByte('\n');
+
+    buf.writeByte(0);
+
+    // It's a line comment if the start of the doc comment comes
+    // after other non-whitespace on the same line.
+    unsigned char** dc = (lineComment && anyToken)
+			 ? &t->lineComment
+			 : &t->blockComment;
+
+    // Combine with previous doc comment, if any
+    if (*dc)
+	*dc = combineComments(*dc, (unsigned char *)buf.data);
+    else
+	*dc = (unsigned char *)buf.extractData();
+}
+
+/********************************************
+ * Combine two document comments into one.
+ */
+
+unsigned char *Lexer::combineComments(unsigned char *c1, unsigned char *c2)
+{
+    unsigned char *c = c2;
+
+    if (c1)
+    {	c = c1;
+	if (c2)
+	{   size_t len1 = strlen((char *)c1);
+	    size_t len2 = strlen((char *)c2);
+
+	    c = (unsigned char *)mem.malloc(len1 + 1 + len2 + 1);
+	    memcpy(c, c1, len1);
+	    c[len1] = '\n';
+	    memcpy(c + len1 + 1, c2, len2);
+	    c[len1 + 1 + len2] = 0;
+	}
+    }
+    return c;
+}
+
+/********************************************
+ * Create an identifier in the string table.
+ */
+
+Identifier *Lexer::idPool(const char *s)
+{   unsigned len;
+    Identifier *id;
+    StringValue *sv;
+
+    len = strlen(s);
+    sv = stringtable.update(s, len);
+    id = (Identifier *) sv->ptrvalue;
+    if (!id)
+    {
+	id = new Identifier(sv->lstring.string, TOKidentifier);
+	sv->ptrvalue = id;
+    }
+    return id;
+}
+
+/****************************************
+ */
+
+struct Keyword
+{   char *name;
+    enum TOK value;
+};
+
+static Keyword keywords[] =
+{
+//    {	"",		TOK	},
+
+    {	"this",		TOKthis		},
+    {	"super",	TOKsuper	},
+    {	"assert",	TOKassert	},
+    {	"null",		TOKnull		},
+    {	"true",		TOKtrue		},
+    {	"false",	TOKfalse	},
+    {	"cast",		TOKcast		},
+    {	"new",		TOKnew		},
+    {	"delete",	TOKdelete	},
+    {	"throw",	TOKthrow	},
+    {	"module",	TOKmodule	},
+    {	"pragma",	TOKpragma	},
+    {	"typeof",	TOKtypeof	},
+    {	"typeid",	TOKtypeid	},
+
+    {	"template",	TOKtemplate	},
+
+    {	"void",		TOKvoid		},
+    {	"byte",		TOKint8		},
+    {	"ubyte",	TOKuns8		},
+    {	"short",	TOKint16	},
+    {	"ushort",	TOKuns16	},
+    {	"int",		TOKint32	},
+    {	"uint",		TOKuns32	},
+    {	"long",		TOKint64	},
+    {	"ulong",	TOKuns64	},
+    {	"cent",		TOKcent,	},
+    {	"ucent",	TOKucent,	},
+    {	"float",	TOKfloat32	},
+    {	"double",	TOKfloat64	},
+    {	"real",		TOKfloat80	},
+
+    {	"bool",		TOKbool		},
+    {	"char",		TOKchar		},
+    {	"wchar",	TOKwchar	},
+    {	"dchar",	TOKdchar	},
+
+    {	"ifloat",	TOKimaginary32	},
+    {	"idouble",	TOKimaginary64	},
+    {	"ireal",	TOKimaginary80	},
+
+    {	"cfloat",	TOKcomplex32	},
+    {	"cdouble",	TOKcomplex64	},
+    {	"creal",	TOKcomplex80	},
+
+    {	"delegate",	TOKdelegate	},
+    {	"function",	TOKfunction	},
+
+    {	"is",		TOKis		},
+    {	"if",		TOKif		},
+    {	"else",		TOKelse		},
+    {	"while",	TOKwhile	},
+    {	"for",		TOKfor		},
+    {	"do",		TOKdo		},
+    {	"switch",	TOKswitch	},
+    {	"case",		TOKcase		},
+    {	"default",	TOKdefault	},
+    {	"break",	TOKbreak	},
+    {	"continue",	TOKcontinue	},
+    {	"synchronized",	TOKsynchronized	},
+    {	"return",	TOKreturn	},
+    {	"goto",		TOKgoto		},
+    {	"try",		TOKtry		},
+    {	"catch",	TOKcatch	},
+    {	"finally",	TOKfinally	},
+    {	"with",		TOKwith		},
+    {	"asm",		TOKasm		},
+    {	"foreach",	TOKforeach	},
+    {	"foreach_reverse",	TOKforeach_reverse	},
+    {	"scope",	TOKscope	},
+
+    {	"struct",	TOKstruct	},
+    {	"class",	TOKclass	},
+    {	"interface",	TOKinterface	},
+    {	"union",	TOKunion	},
+    {	"enum",		TOKenum		},
+    {	"import",	TOKimport	},
+    {	"mixin",	TOKmixin	},
+    {	"static",	TOKstatic	},
+    {	"final",	TOKfinal	},
+    {	"const",	TOKconst	},
+    {	"typedef",	TOKtypedef	},
+    {	"alias",	TOKalias	},
+    {	"override",	TOKoverride	},
+    {	"abstract",	TOKabstract	},
+    {	"volatile",	TOKvolatile	},
+    {	"debug",	TOKdebug	},
+    {	"deprecated",	TOKdeprecated	},
+    {	"in",		TOKin		},
+    {	"out",		TOKout		},
+    {	"inout",	TOKinout	},
+    {	"lazy",		TOKlazy		},
+    {	"auto",		TOKauto		},
+
+    {	"align",	TOKalign	},
+    {	"extern",	TOKextern	},
+    {	"private",	TOKprivate	},
+    {	"package",	TOKpackage	},
+    {	"protected",	TOKprotected	},
+    {	"public",	TOKpublic	},
+    {	"export",	TOKexport	},
+
+    {	"body",		TOKbody		},
+    {	"invariant",	TOKinvariant	},
+    {	"unittest",	TOKunittest	},
+    {	"version",	TOKversion	},
+
+    // Added after 1.0
+    {	"ref",		TOKref		},
+    {	"macro",	TOKmacro	},
+};
+
+int Token::isKeyword()
+{
+    for (unsigned u = 0; u < sizeof(keywords) / sizeof(keywords[0]); u++)
+    {
+	if (keywords[u].value == value)
+	    return 1;
+    }
+    return 0;
+}
+
+void Lexer::initKeywords()
+{   StringValue *sv;
+    unsigned u;
+    enum TOK v;
+    unsigned nkeywords = sizeof(keywords) / sizeof(keywords[0]);
+
+    if (global.params.Dversion == 1)
+	nkeywords -= 2;
+
+    cmtable_init();
+
+    for (u = 0; u < nkeywords; u++)
+    {	char *s;
+
+	//printf("keyword[%d] = '%s'\n",u, keywords[u].name);
+	s = keywords[u].name;
+	v = keywords[u].value;
+	sv = stringtable.insert(s, strlen(s));
+	sv->ptrvalue = (void *) new Identifier(sv->lstring.string,v);
+
+	//printf("tochars[%d] = '%s'\n",v, s);
+	Token::tochars[v] = s;
+    }
+
+    Token::tochars[TOKeof]		= "EOF";
+    Token::tochars[TOKlcurly]		= "{";
+    Token::tochars[TOKrcurly]		= "}";
+    Token::tochars[TOKlparen]		= "(";
+    Token::tochars[TOKrparen]		= ")";
+    Token::tochars[TOKlbracket]		= "[";
+    Token::tochars[TOKrbracket]		= "]";
+    Token::tochars[TOKsemicolon]	= ";";
+    Token::tochars[TOKcolon]		= ":";
+    Token::tochars[TOKcomma]		= ",";
+    Token::tochars[TOKdot]		= ".";
+    Token::tochars[TOKxor]		= "^";
+    Token::tochars[TOKxorass]		= "^=";
+    Token::tochars[TOKassign]		= "=";
+    Token::tochars[TOKconstruct]	= "=";
+    Token::tochars[TOKlt]		= "<";
+    Token::tochars[TOKgt]		= ">";
+    Token::tochars[TOKle]		= "<=";
+    Token::tochars[TOKge]		= ">=";
+    Token::tochars[TOKequal]		= "==";
+    Token::tochars[TOKnotequal]		= "!=";
+    Token::tochars[TOKnotidentity]	= "!is";
+    Token::tochars[TOKtobool]		= "!!";
+
+    Token::tochars[TOKunord]		= "!<>=";
+    Token::tochars[TOKue]		= "!<>";
+    Token::tochars[TOKlg]		= "<>";
+    Token::tochars[TOKleg]		= "<>=";
+    Token::tochars[TOKule]		= "!>";
+    Token::tochars[TOKul]		= "!>=";
+    Token::tochars[TOKuge]		= "!<";
+    Token::tochars[TOKug]		= "!<=";
+
+    Token::tochars[TOKnot]		= "!";
+    Token::tochars[TOKtobool]		= "!!";
+    Token::tochars[TOKshl]		= "<<";
+    Token::tochars[TOKshr]		= ">>";
+    Token::tochars[TOKushr]		= ">>>";
+    Token::tochars[TOKadd]		= "+";
+    Token::tochars[TOKmin]		= "-";
+    Token::tochars[TOKmul]		= "*";
+    Token::tochars[TOKdiv]		= "/";
+    Token::tochars[TOKmod]		= "%";
+    Token::tochars[TOKslice]		= "..";
+    Token::tochars[TOKdotdotdot]	= "...";
+    Token::tochars[TOKand]		= "&";
+    Token::tochars[TOKandand]		= "&&";
+    Token::tochars[TOKor]		= "|";
+    Token::tochars[TOKoror]		= "||";
+    Token::tochars[TOKarray]		= "[]";
+    Token::tochars[TOKindex]		= "[i]";
+    Token::tochars[TOKaddress]		= "&";
+    Token::tochars[TOKstar]		= "*";
+    Token::tochars[TOKtilde]		= "~";
+    Token::tochars[TOKdollar]		= "$";
+    Token::tochars[TOKcast]		= "cast";
+    Token::tochars[TOKplusplus]		= "++";
+    Token::tochars[TOKminusminus]	= "--";
+    Token::tochars[TOKtype]		= "type";
+    Token::tochars[TOKquestion]		= "?";
+    Token::tochars[TOKneg]		= "-";
+    Token::tochars[TOKuadd]		= "+";
+    Token::tochars[TOKvar]		= "var";
+    Token::tochars[TOKaddass]		= "+=";
+    Token::tochars[TOKminass]		= "-=";
+    Token::tochars[TOKmulass]		= "*=";
+    Token::tochars[TOKdivass]		= "/=";
+    Token::tochars[TOKmodass]		= "%=";
+    Token::tochars[TOKshlass]		= "<<=";
+    Token::tochars[TOKshrass]		= ">>=";
+    Token::tochars[TOKushrass]		= ">>>=";
+    Token::tochars[TOKandass]		= "&=";
+    Token::tochars[TOKorass]		= "|=";
+    Token::tochars[TOKcatass]		= "~=";
+    Token::tochars[TOKcat]		= "~";
+    Token::tochars[TOKcall]		= "call";
+    Token::tochars[TOKidentity]		= "is";
+    Token::tochars[TOKnotidentity]	= "!is";
+
+    Token::tochars[TOKorass]		= "|=";
+    Token::tochars[TOKidentifier]	= "identifier";
+
+     // For debugging
+    Token::tochars[TOKdotexp]		= "dotexp";
+    Token::tochars[TOKdotti]		= "dotti";
+    Token::tochars[TOKdotvar]		= "dotvar";
+    Token::tochars[TOKdottype]		= "dottype";
+    Token::tochars[TOKsymoff]		= "symoff";
+    Token::tochars[TOKtypedot]		= "typedot";
+    Token::tochars[TOKarraylength]	= "arraylength";
+    Token::tochars[TOKarrayliteral]	= "arrayliteral";
+    Token::tochars[TOKassocarrayliteral] = "assocarrayliteral";
+    Token::tochars[TOKstructliteral]	= "structliteral";
+    Token::tochars[TOKstring]		= "string";
+    Token::tochars[TOKdsymbol]		= "symbol";
+    Token::tochars[TOKtuple]		= "tuple";
+    Token::tochars[TOKdeclaration]	= "declaration";
+    Token::tochars[TOKdottd]		= "dottd";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/lexer.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,285 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#ifndef DMD_LEXER_H
+#define DMD_LEXER_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include "root.h"
+#include "mars.h"
+
+struct StringTable;
+struct Identifier;
+struct Module;
+
+/* Tokens:
+	(	)
+	[	]
+	{	}
+	<	>	<=	>=	==	!=	===	!==
+	<<	>>	<<=	>>=	>>>	>>>=
+	+	-	+=	-=
+	*	/	%	*=	/=	%=
+	&	| 	^	&=	|=	^=
+	=	!	~
+	++	--
+	.	->	:	,
+	?	&&	||
+ */
+
+enum TOK
+{
+	TOKreserved,
+
+	// Other
+	TOKlparen,	TOKrparen,
+	TOKlbracket,	TOKrbracket,
+	TOKlcurly,	TOKrcurly,
+	TOKcolon,	TOKneg,
+	TOKsemicolon,	TOKdotdotdot,
+	TOKeof,		TOKcast,
+	TOKnull,	TOKassert,
+	TOKtrue,	TOKfalse,
+	TOKarray,	TOKcall,
+	TOKaddress,	TOKtypedot,
+	TOKtype,	TOKthrow,
+	TOKnew,		TOKdelete,
+	TOKstar,	TOKsymoff,
+	TOKvar,		TOKdotvar,
+	TOKdotti,	TOKdotexp,
+	TOKdottype,	TOKslice,
+	TOKarraylength,	TOKversion,
+	TOKmodule,	TOKdollar,
+	TOKtemplate,	TOKdottd,
+	TOKdeclaration,	TOKtypeof,
+	TOKpragma,	TOKdsymbol,
+	TOKtypeid,	TOKuadd,
+	TOKremove,
+	TOKnewanonclass, TOKcomment,
+	TOKarrayliteral, TOKassocarrayliteral,
+	TOKstructliteral,
+
+	// Operators
+	TOKlt,		TOKgt,
+	TOKle,		TOKge,
+	TOKequal,	TOKnotequal,
+	TOKidentity,	TOKnotidentity,
+	TOKindex,	TOKis,
+	TOKtobool,
+
+// 60
+	// NCEG floating point compares
+	// !<>=     <>    <>=    !>     !>=   !<     !<=   !<>
+	TOKunord,TOKlg,TOKleg,TOKule,TOKul,TOKuge,TOKug,TOKue,
+
+	TOKshl,		TOKshr,
+	TOKshlass,	TOKshrass,
+	TOKushr,	TOKushrass,
+	TOKcat,		TOKcatass,	// ~ ~=
+	TOKadd,		TOKmin,		TOKaddass,	TOKminass,
+	TOKmul,		TOKdiv,		TOKmod,
+	TOKmulass,	TOKdivass,	TOKmodass,
+	TOKand,		TOKor,		TOKxor,
+	TOKandass,	TOKorass,	TOKxorass,
+	TOKassign,	TOKnot,		TOKtilde,
+	TOKplusplus,	TOKminusminus,	TOKconstruct,
+	TOKdot,		TOKarrow,	TOKcomma,
+	TOKquestion,	TOKandand,	TOKoror,
+
+// 103
+	// Numeric literals
+	TOKint32v, TOKuns32v,
+	TOKint64v, TOKuns64v,
+	TOKfloat32v, TOKfloat64v, TOKfloat80v,
+	TOKimaginary32v, TOKimaginary64v, TOKimaginary80v,
+
+	// Char constants
+	TOKcharv, TOKwcharv, TOKdcharv,
+
+	// Leaf operators
+	TOKidentifier,	TOKstring,
+	TOKthis,	TOKsuper,
+	TOKhalt,	TOKtuple,
+
+	// Basic types
+	TOKvoid,
+	TOKint8, TOKuns8,
+	TOKint16, TOKuns16,
+	TOKint32, TOKuns32,
+	TOKint64, TOKuns64,
+	TOKfloat32, TOKfloat64, TOKfloat80,
+	TOKimaginary32, TOKimaginary64, TOKimaginary80,
+	TOKcomplex32, TOKcomplex64, TOKcomplex80,
+	TOKchar, TOKwchar, TOKdchar, TOKbit, TOKbool,
+	TOKcent, TOKucent,
+
+	// Aggregates
+	TOKstruct, TOKclass, TOKinterface, TOKunion, TOKenum, TOKimport,
+	TOKtypedef, TOKalias, TOKoverride, TOKdelegate, TOKfunction,
+	TOKmixin,
+
+	TOKalign, TOKextern, TOKprivate, TOKprotected, TOKpublic, TOKexport,
+	TOKstatic, /*TOKvirtual,*/ TOKfinal, TOKconst, TOKabstract, TOKvolatile,
+	TOKdebug, TOKdeprecated, TOKin, TOKout, TOKinout, TOKlazy,
+	TOKauto, TOKpackage,
+
+	// Statements
+	TOKif, TOKelse, TOKwhile, TOKfor, TOKdo, TOKswitch,
+	TOKcase, TOKdefault, TOKbreak, TOKcontinue, TOKwith,
+	TOKsynchronized, TOKreturn, TOKgoto, TOKtry, TOKcatch, TOKfinally,
+	TOKasm, TOKforeach, TOKforeach_reverse,
+	TOKscope,
+	TOKon_scope_exit, TOKon_scope_failure, TOKon_scope_success,
+
+	// Contracts
+	TOKbody, TOKinvariant,
+
+	// Testing
+	TOKunittest,
+
+	// Added after 1.0
+	TOKref,
+	TOKmacro,
+
+	TOKMAX
+};
+
+#define CASE_BASIC_TYPES			\
+	case TOKwchar: case TOKdchar:		\
+	case TOKbit: case TOKbool: case TOKchar:	\
+	case TOKint8: case TOKuns8:		\
+	case TOKint16: case TOKuns16:		\
+	case TOKint32: case TOKuns32:		\
+	case TOKint64: case TOKuns64:		\
+	case TOKfloat32: case TOKfloat64: case TOKfloat80:		\
+	case TOKimaginary32: case TOKimaginary64: case TOKimaginary80:	\
+	case TOKcomplex32: case TOKcomplex64: case TOKcomplex80:	\
+	case TOKvoid
+
+#define CASE_BASIC_TYPES_X(t)					\
+	case TOKvoid:	 t = Type::tvoid;  goto LabelX;		\
+	case TOKint8:	 t = Type::tint8;  goto LabelX;		\
+	case TOKuns8:	 t = Type::tuns8;  goto LabelX;		\
+	case TOKint16:	 t = Type::tint16; goto LabelX;		\
+	case TOKuns16:	 t = Type::tuns16; goto LabelX;		\
+	case TOKint32:	 t = Type::tint32; goto LabelX;		\
+	case TOKuns32:	 t = Type::tuns32; goto LabelX;		\
+	case TOKint64:	 t = Type::tint64; goto LabelX;		\
+	case TOKuns64:	 t = Type::tuns64; goto LabelX;		\
+	case TOKfloat32: t = Type::tfloat32; goto LabelX;	\
+	case TOKfloat64: t = Type::tfloat64; goto LabelX;	\
+	case TOKfloat80: t = Type::tfloat80; goto LabelX;	\
+	case TOKimaginary32: t = Type::timaginary32; goto LabelX;	\
+	case TOKimaginary64: t = Type::timaginary64; goto LabelX;	\
+	case TOKimaginary80: t = Type::timaginary80; goto LabelX;	\
+	case TOKcomplex32: t = Type::tcomplex32; goto LabelX;	\
+	case TOKcomplex64: t = Type::tcomplex64; goto LabelX;	\
+	case TOKcomplex80: t = Type::tcomplex80; goto LabelX;	\
+	case TOKbit:	 t = Type::tbit;     goto LabelX;	\
+	case TOKbool:	 t = Type::tbool;    goto LabelX;	\
+	case TOKchar:	 t = Type::tchar;    goto LabelX;	\
+	case TOKwchar:	 t = Type::twchar; goto LabelX;	\
+	case TOKdchar:	 t = Type::tdchar; goto LabelX;	\
+	LabelX
+
+struct Token
+{
+    Token *next;
+    unsigned char *ptr;		// pointer to first character of this token within buffer
+    enum TOK value;
+    unsigned char *blockComment; // doc comment string prior to this token
+    unsigned char *lineComment;	 // doc comment for previous token
+    union
+    {
+	// Integers
+	d_int32 int32value;
+	d_uns32	uns32value;
+	d_int64	int64value;
+	d_uns64	uns64value;
+
+	// Floats
+#ifdef IN_GCC
+	// real_t float80value; // can't use this in a union!
+#else
+	d_float80 float80value;
+#endif
+
+	struct
+	{   unsigned char *ustring;	// UTF8 string
+	    unsigned len;
+	    unsigned char postfix;	// 'c', 'w', 'd'
+	};
+
+	Identifier *ident;
+    };
+#ifdef IN_GCC
+    real_t float80value; // can't use this in a union!
+#endif
+
+    static char *tochars[TOKMAX];
+    static void *operator new(size_t sz);
+
+    int isKeyword();
+    void print();
+    char *toChars();
+    static char *toChars(enum TOK);
+};
+
+struct Lexer
+{
+    static StringTable stringtable;
+    static OutBuffer stringbuffer;
+    static Token *freelist;
+
+    Loc loc;			// for error messages
+
+    unsigned char *base;	// pointer to start of buffer
+    unsigned char *end;		// past end of buffer
+    unsigned char *p;		// current character
+    Token token;
+    Module *mod;
+    int doDocComment;		// collect doc comment information
+    int anyToken;		// !=0 means seen at least one token
+    int commentToken;		// !=0 means comments are TOKcomment's
+
+    Lexer(Module *mod,
+	unsigned char *base, unsigned begoffset, unsigned endoffset,
+	int doDocComment, int commentToken);
+
+    static void initKeywords();
+    static Identifier *idPool(const char *s);
+
+    TOK nextToken();
+    void scan(Token *t);
+    Token *peek(Token *t);
+    Token *peekPastParen(Token *t);
+    unsigned escapeSequence();
+    TOK wysiwygStringConstant(Token *t, int tc);
+    TOK hexStringConstant(Token *t);
+    TOK escapeStringConstant(Token *t, int wide);
+    TOK charConstant(Token *t, int wide);
+    void stringPostfix(Token *t);
+    unsigned wchar(unsigned u);
+    TOK number(Token *t);
+    TOK inreal(Token *t);
+    void error(const char *format, ...);
+    void error(Loc loc, const char *format, ...);
+    void pragma();
+    unsigned decodeUTF();
+    void getDocComment(Token *t, unsigned lineComment);
+
+    static int isValidIdentifier(char *p);
+    static unsigned char *combineComments(unsigned char *c1, unsigned char *c2);
+};
+
+#endif /* DMD_LEXER_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/link.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,504 @@
+
+
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+
+#include	<stdio.h>
+#include	<ctype.h>
+#include	<assert.h>
+#include	<stdarg.h>
+#include	<string.h>
+#include	<stdlib.h>
+
+#if _WIN32
+#include	<process.h>
+#endif
+
+#if linux
+#include	<sys/types.h>
+#include	<sys/wait.h>
+#include	<unistd.h>
+#endif
+
+#include	"root.h"
+
+#include	"mars.h"
+
+#include	"mem.h"
+
+int executecmd(char *cmd, char *args, int useenv);
+int executearg0(char *cmd, char *args);
+
+/*****************************
+ * Run the linker.  Return status of execution.
+ */
+
+int runLINK()
+{
+#if _WIN32
+    assert(0 && "linking not done for win32");
+
+    char *p;
+    int i;
+    int status;
+    OutBuffer cmdbuf;
+
+    global.params.libfiles->push((void *) "user32");
+    global.params.libfiles->push((void *) "kernel32");
+
+    for (i = 0; i < global.params.objfiles->dim; i++)
+    {
+	if (i)
+	    cmdbuf.writeByte('+');
+	p = (char *)global.params.objfiles->data[i];
+	char *ext = FileName::ext(p);
+	if (ext)
+	    cmdbuf.write(p, ext - p - 1);
+	else
+	    cmdbuf.writestring(p);
+    }
+    cmdbuf.writeByte(',');
+    if (global.params.exefile)
+	cmdbuf.writestring(global.params.exefile);
+    else
+    {	// Generate exe file name from first obj name
+	char *n = (char *)global.params.objfiles->data[0];
+	char *ex;
+
+	n = FileName::name(n);
+	FileName *fn = FileName::forceExt(n, "exe");
+	global.params.exefile = fn->toChars();
+    }
+
+    // Make sure path to exe file exists
+    {	char *p = FileName::path(global.params.exefile);
+	FileName::ensurePathExists(p);
+	mem.free(p);
+    }
+
+    cmdbuf.writeByte(',');
+    if (global.params.run)
+	cmdbuf.writestring("nul");
+//    if (mapfile)
+//	cmdbuf.writestring(output);
+    cmdbuf.writeByte(',');
+
+    for (i = 0; i < global.params.libfiles->dim; i++)
+    {
+	if (i)
+	    cmdbuf.writeByte('+');
+	cmdbuf.writestring((char *) global.params.libfiles->data[i]);
+    }
+
+    if (global.params.deffile)
+    {
+	cmdbuf.writeByte(',');
+	cmdbuf.writestring(global.params.deffile);
+    }
+
+    /* Eliminate unnecessary trailing commas	*/
+    while (1)
+    {   i = cmdbuf.offset;
+	if (!i || cmdbuf.data[i - 1] != ',')
+	    break;
+	cmdbuf.offset--;
+    }
+
+    if (global.params.resfile)
+    {
+	cmdbuf.writestring("/RC:");
+	cmdbuf.writestring(global.params.resfile);
+    }
+
+#if 0
+    if (mapfile)
+	cmdbuf.writestring("/m");
+    if (debuginfo)
+	cmdbuf.writestring("/li");
+    if (codeview)
+    {
+	cmdbuf.writestring("/co");
+	if (codeview3)
+	    cmdbuf.writestring(":3");
+    }
+#else
+    if (global.params.symdebug)
+	cmdbuf.writestring("/co");
+#endif
+
+    cmdbuf.writestring("/noi");
+    for (i = 0; i < global.params.linkswitches->dim; i++)
+    {
+	cmdbuf.writestring((char *) global.params.linkswitches->data[i]);
+    }
+    cmdbuf.writeByte(';');
+
+    p = cmdbuf.toChars();
+
+    FileName *lnkfilename = NULL;
+    size_t plen = strlen(p);
+    if (plen > 7000)
+    {
+	lnkfilename = FileName::forceExt(global.params.exefile, "lnk");
+	File flnk(lnkfilename);
+	flnk.setbuffer(p, plen);
+	flnk.ref = 1;
+	if (flnk.write())
+	    error("error writing file %s", lnkfilename);
+	if (lnkfilename->len() < plen)
+	    sprintf(p, "@%s", lnkfilename->toChars());
+    }
+
+    char *linkcmd = getenv("LINKCMD");
+    if (!linkcmd)
+	linkcmd = "link";
+    status = executecmd(linkcmd, p, 1);
+    if (lnkfilename)
+    {
+	remove(lnkfilename->toChars());
+	delete lnkfilename;
+    }
+    return status;
+#elif linux
+    pid_t childpid;
+    int i;
+    int status;
+
+    // Build argv[]
+    Array argv;
+
+    //char *cc = getenv("CC");
+    //if (!cc)
+	//cc = "gcc";
+    char *cc = "llvm-ld";
+    argv.push((void *)cc);
+
+    // None of that a.out stuff. Use explicit exe file name, or
+    // generate one from name of first source file.
+    OutBuffer* exestr = new OutBuffer;
+    if (global.params.exefile)
+    {
+        exestr->printf("-o=%s", global.params.exefile);
+        argv.push(exestr->toChars());
+    }
+    else
+    {	// Generate exe file name from first obj name
+	char *n = (char *)global.params.objfiles->data[0];
+	char *e;
+	char *ex;
+
+	n = FileName::name(n);
+	e = FileName::ext(n);
+	if (e)
+	{
+	    e--;			// back up over '.'
+	    ex = (char *)mem.malloc(e - n + 1);
+	    memcpy(ex, n, e - n);
+	    ex[e - n] = 0;
+	}
+	else
+	    ex = (char *)"a.out";	// no extension, so give up
+    exestr->printf("-o=%s", ex);
+    ex = exestr->toChars();
+	argv.push(ex);
+	global.params.exefile = ex;
+    }
+
+    // Make sure path to exe file exists
+    {	char *p = FileName::path(global.params.exefile);
+	FileName::ensurePathExists(p);
+	mem.free(p);
+    }
+
+    argv.insert(argv.dim, global.params.libfiles);
+
+    //if (global.params.symdebug)
+	//argv.push((void *)"-g");
+
+    //argv.push((void *)"-m32");
+
+
+    if (!global.params.optimize)
+    argv.push((void *)"-disable-opt");
+    else {
+        const char* s = 0;
+        switch(global.params.optimizeLevel) {
+        case 0:
+        s = "-O0"; break;
+        case 1:
+        s = "-O1"; break;
+        case 2:
+        s = "-O2"; break;
+        case 3:
+        s = "-O3"; break;
+        case 4:
+        s = "-O4"; break;
+        case 5:
+        s = "-O5"; break;
+        default:
+        assert(0);
+        }
+        argv.push((void*)s);
+    }
+
+#if 0
+    if (0 && global.params.exefile)
+    {
+	/* This switch enables what is known as 'smart linking'
+	 * in the Windows world, where unreferenced sections
+	 * are removed from the executable. It eliminates unreferenced
+	 * functions, essentially making a 'library' out of a module.
+	 * Although it is documented to work with ld version 2.13,
+	 * in practice it does not, but just seems to be ignored.
+	 * Thomas Kuehne has verified that it works with ld 2.16.1.
+	 * BUG: disabled because it causes exception handling to fail
+	 */
+	argv.push((void *)"-Xlinker");
+	argv.push((void *)"--gc-sections");
+    }
+#endif
+
+    for (i = 0; i < global.params.linkswitches->dim; i++)
+    {	char *p = (char *)global.params.linkswitches->data[i];
+	//if (!p || !p[0] || !(p[0] == '-' && p[1] == 'l'))
+    //{   // Don't need -Xlinker if switch starts with -l
+	//    argv.push((void *)"-Xlinker");
+    //}
+	argv.push((void *) p);
+    }
+
+    argv.push((void*)"-native");
+    
+    /* Standard libraries must go after user specified libraries
+     * passed with -l.
+     */
+    //argv.push((void *)"-lphobos");	// turns into /usr/lib/libphobos.a
+    //argv.push((void *)"-lpthread");
+    //argv.push((void *)"-lm");
+
+    std::string corelibpath = global.params.runtimeImppath;
+    corelibpath.append("/llvmdcore.bc");
+    argv.append(global.params.objfiles);
+    argv.push((void *)corelibpath.c_str());
+    
+    if (!global.params.quiet)
+    {
+	// Print it
+	for (i = 0; i < argv.dim; i++)
+	    printf("%s ", (char *)argv.data[i]);
+	printf("\n");
+	fflush(stdout);
+    }
+
+    argv.push(NULL);
+    childpid = fork();
+    if (childpid == 0)
+    {
+	execvp((char *)argv.data[0], (char **)argv.data);
+	perror((char *)argv.data[0]);		// failed to execute
+	return -1;
+    }
+
+    waitpid(childpid, &status, 0);
+
+    status=WEXITSTATUS(status);
+    if (status)
+	printf("--- errorlevel %d\n", status);
+    return status;
+#else
+    printf ("Linking is not yet supported for this version of LLVMDMD.\n");
+    return -1;
+#endif
+}
+
+/**********************************
+ * Delete generated EXE file.
+ */
+
+void deleteExeFile()
+{
+    if (global.params.exefile)
+    {
+	//printf("deleteExeFile() %s\n", global.params.exefile);
+	remove(global.params.exefile);
+    }
+}
+
+/******************************
+ * Execute a rule.  Return the status.
+ *	cmd	program to run
+ *	args	arguments to cmd, as a string
+ *	useenv	if cmd knows about _CMDLINE environment variable
+ */
+
+#if _WIN32
+int executecmd(char *cmd, char *args, int useenv)
+{
+    int status;
+    char *buff;
+    size_t len;
+
+    if (!global.params.quiet || global.params.verbose)
+    {
+	printf("%s %s\n", cmd, args);
+	fflush(stdout);
+    }
+
+    if ((len = strlen(args)) > 255)
+    {   char *q;
+	static char envname[] = "@_CMDLINE";
+
+	envname[0] = '@';
+	switch (useenv)
+	{   case 0:	goto L1;
+	    case 2: envname[0] = '%';	break;
+	}
+	q = (char *) alloca(sizeof(envname) + len + 1);
+	sprintf(q,"%s=%s", envname + 1, args);
+	status = putenv(q);
+	if (status == 0)
+	    args = envname;
+	else
+	{
+	L1:
+	    error("command line length of %d is too long",len);
+	}
+    }
+
+    status = executearg0(cmd,args);
+#if _WIN32
+    if (status == -1)
+	status = spawnlp(0,cmd,cmd,args,NULL);
+#endif
+//    if (global.params.verbose)
+//	printf("\n");
+    if (status)
+    {
+	if (status == -1)
+	    printf("Can't run '%s', check PATH\n", cmd);
+	else
+	    printf("--- errorlevel %d\n", status);
+    }
+    return status;
+}
+#endif
+
+/**************************************
+ * Attempt to find command to execute by first looking in the directory
+ * where DMD was run from.
+ * Returns:
+ *	-1	did not find command there
+ *	!=-1	exit status from command
+ */
+
+#if _WIN32
+int executearg0(char *cmd, char *args)
+{
+    char *file;
+    char *argv0 = global.params.argv0;
+
+    //printf("argv0='%s', cmd='%s', args='%s'\n",argv0,cmd,args);
+
+    // If cmd is fully qualified, we don't do this
+    if (FileName::absolute(cmd))
+	return -1;
+
+    file = FileName::replaceName(argv0, cmd);
+
+    //printf("spawning '%s'\n",file);
+#if _WIN32
+    return spawnl(0,file,file,args,NULL);
+#elif linux
+    char *full;
+    int cmdl = strlen(cmd);
+
+    full = (char*) mem.malloc(cmdl + strlen(args) + 2);
+    if (full == NULL)
+	return 1;
+    strcpy(full, cmd);
+    full [cmdl] = ' ';
+    strcpy(full + cmdl + 1, args);
+
+    int result = system(full);
+
+    mem.free(full);
+    return result;
+#else
+    assert(0);
+#endif
+}
+#endif
+
+/***************************************
+ * Run the compiled program.
+ * Return exit status.
+ */
+
+int runProgram()
+{
+    //printf("runProgram()\n");
+    if (global.params.verbose)
+    {
+	printf("%s", global.params.exefile);
+	for (size_t i = 0; i < global.params.runargs_length; i++)
+	    printf(" %s", (char *)global.params.runargs[i]);
+	printf("\n");
+    }
+
+    // Build argv[]
+    Array argv;
+
+    argv.push((void *)global.params.exefile);
+    for (size_t i = 0; i < global.params.runargs_length; i++)
+    {	char *a = global.params.runargs[i];
+
+#if _WIN32
+	// BUG: what about " appearing in the string?
+	if (strchr(a, ' '))
+	{   char *b = (char *)mem.malloc(3 + strlen(a));
+	    sprintf(b, "\"%s\"", a);
+	    a = b;
+	}
+#endif
+	argv.push((void *)a);
+    }
+    argv.push(NULL);
+
+#if _WIN32
+    char *ex = FileName::name(global.params.exefile);
+    if (ex == global.params.exefile)
+	ex = FileName::combine(".", ex);
+    else
+	ex = global.params.exefile;
+    return spawnv(0,ex,(char **)argv.data);
+#elif linux
+    pid_t childpid;
+    int status;
+
+    childpid = fork();
+    if (childpid == 0)
+    {
+	char *fn = (char *)argv.data[0];
+	if (!FileName::absolute(fn))
+	{   // Make it "./fn"
+	    fn = FileName::combine(".", fn);
+	}
+	execv(fn, (char **)argv.data);
+	perror(fn);		// failed to execute
+	return -1;
+    }
+
+    waitpid(childpid, &status, 0);
+
+    status = WEXITSTATUS(status);
+    return status;
+#else
+    assert(0);
+#endif
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/lstring.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,59 @@
+// lstring.c
+
+// Copyright (c) 1999-2002 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdlib.h>
+
+#include "dchar.h"
+#include "mem.h"
+#include "lstring.h"
+
+Lstring Lstring::zero = LSTRING_EMPTY();
+
+Lstring *Lstring::ctor(const dchar *p, unsigned length)
+{
+    Lstring *s;
+
+    s = alloc(length);
+    memcpy(s->string, p, length * sizeof(dchar));
+    return s;
+}
+
+Lstring *Lstring::alloc(unsigned length)
+{
+    Lstring *s;
+
+    s = (Lstring *)mem.malloc(size(length));
+    s->length = length;
+    s->string[length] = 0;
+    return s;
+}
+
+Lstring *Lstring::append(const Lstring *s)
+{
+    Lstring *t;
+
+    if (!s->length)
+	return this;
+    t = alloc(length + s->length);
+    memcpy(t->string, string, length * sizeof(dchar));
+    memcpy(t->string + length, s->string, s->length * sizeof(dchar));
+    return t;
+}
+
+Lstring *Lstring::substring(int start, int end)
+{
+    Lstring *t;
+
+    if (start == end)
+	return &zero;
+    t = alloc(end - start);
+    memcpy(t->string, string + start, (end - start) * sizeof(dchar));
+    return t;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/lstring.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,72 @@
+
+// lstring.h
+// length-prefixed strings
+
+// Copyright (c) 1999-2002 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#ifndef LSTRING_H
+#define LSTRING_H 1
+
+#include "dchar.h"
+
+struct Lstring
+{
+    unsigned length;
+
+    // Disable warning about nonstandard extension
+    #pragma warning (disable : 4200)
+    dchar string[];
+
+    static Lstring zero;	// 0 length string
+
+    // No constructors because we want to be able to statically
+    // initialize Lstring's, and Lstrings are of variable size.
+
+    #if M_UNICODE
+    #define LSTRING(p,length) { length, L##p }
+    #else
+    #define LSTRING(p,length) { length, p }
+    #endif
+
+#if __GNUC__
+    #define LSTRING_EMPTY() { 0 }
+#else
+    #define LSTRING_EMPTY() LSTRING("", 0)
+#endif
+
+    static Lstring *ctor(const dchar *p) { return ctor(p, Dchar::len(p)); }
+    static Lstring *ctor(const dchar *p, unsigned length);
+    static unsigned size(unsigned length) { return sizeof(Lstring) + (length + 1) * sizeof(dchar); }
+    static Lstring *alloc(unsigned length);
+    Lstring *clone();
+
+    unsigned len() { return length; }
+
+    dchar *toDchars() { return string; }
+
+    hash_t hash() { return Dchar::calcHash(string, length); }
+    hash_t ihash() { return Dchar::icalcHash(string, length); }
+
+    static int cmp(const Lstring *s1, const Lstring *s2)
+    {
+	int c = s2->length - s1->length;
+	return c ? c : Dchar::memcmp(s1->string, s2->string, s1->length);
+    }
+
+    static int icmp(const Lstring *s1, const Lstring *s2)
+    {
+	int c = s2->length - s1->length;
+	return c ? c : Dchar::memicmp(s1->string, s2->string, s1->length);
+    }
+
+    Lstring *append(const Lstring *s);
+    Lstring *substring(int start, int end);
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/macro.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,459 @@
+
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+/* Simple macro text processor.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <ctype.h>
+#include <assert.h>
+
+#if IN_GCC || IN_LLVM
+#include "mem.h"
+#else
+#if _WIN32
+#include "..\root\mem.h"
+#elif linux
+#include "../root/mem.h"
+#else
+#error "fix this"
+#endif
+#endif
+
+#include "root.h"
+#include "macro.h"
+
+#define isidstart(c) (isalpha(c) || (c) == '_')
+#define isidchar(c)  (isalnum(c) || (c) == '_')
+
+unsigned char *memdup(unsigned char *p, size_t len)
+{
+    return (unsigned char *)memcpy(mem.malloc(len), p, len);
+}
+
+Macro::Macro(unsigned char *name, size_t namelen, unsigned char *text, size_t textlen)
+{
+    next = NULL;
+
+#if 1
+    this->name = name;
+    this->namelen = namelen;
+
+    this->text = text;
+    this->textlen = textlen;
+#else
+    this->name = name;
+    this->namelen = namelen;
+
+    this->text = text;
+    this->textlen = textlen;
+#endif
+    inuse = 0;
+}
+
+
+Macro *Macro::search(unsigned char *name, size_t namelen)
+{   Macro *table;
+
+    //printf("Macro::search(%.*s)\n", namelen, name);
+    for (table = this; table; table = table->next)
+    {
+	if (table->namelen == namelen &&
+	    memcmp(table->name, name, namelen) == 0)
+	{
+	    //printf("\tfound %d\n", table->textlen);
+	    break;
+	}
+    }
+    return table;
+}
+
+Macro *Macro::define(Macro **ptable, unsigned char *name, size_t namelen, unsigned char *text, size_t textlen)
+{
+    //printf("Macro::define('%.*s' = '%.*s')\n", namelen, name, textlen, text);
+
+    Macro *table;
+
+    //assert(ptable);
+    for (table = *ptable; table; table = table->next)
+    {
+	if (table->namelen == namelen &&
+	    memcmp(table->name, name, namelen) == 0)
+	{
+	    table->text = text;
+	    table->textlen = textlen;
+	    return table;
+	}
+    }
+    table = new Macro(name, namelen, text, textlen);
+    table->next = *ptable;
+    *ptable = table;
+    return table;
+}
+
+/**********************************************************
+ * Given buffer p[0..end], extract argument marg[0..marglen].
+ * Params:
+ *	n	0:	get entire argument
+ *		1..9:	get nth argument
+ *		-1:	get 2nd through end
+ */
+
+unsigned extractArgN(unsigned char *p, unsigned end, unsigned char **pmarg, unsigned *pmarglen, int n)
+{
+    /* Scan forward for matching right parenthesis.
+     * Nest parentheses.
+     * Skip over $( and $)
+     * Skip over "..." and '...' strings inside HTML tags.
+     * Skip over <!-- ... --> comments.
+     * Skip over previous macro insertions
+     * Set marglen.
+     */
+    unsigned parens = 1;
+    unsigned char instring = 0;
+    unsigned incomment = 0;
+    unsigned intag = 0;
+    unsigned inexp = 0;
+    unsigned argn = 0;
+
+    unsigned v = 0;
+
+  Largstart:
+#if 1
+    // Skip first space, if any, to find the start of the macro argument
+    if (v < end && isspace(p[v]))
+	v++;
+#else
+    // Skip past spaces to find the start of the macro argument
+    for (; v < end && isspace(p[v]); v++)
+	;
+#endif
+    *pmarg = p + v;
+
+    for (; v < end; v++)
+    {   unsigned char c = p[v];
+
+	switch (c)
+	{
+	    case ',':
+		if (!inexp && !instring && !incomment && parens == 1)
+		{
+		    argn++;
+		    if (argn == 1 && n == -1)
+		    {	v++;
+			goto Largstart;
+		    }
+		    if (argn == n)
+			break;
+		    if (argn + 1 == n)
+		    {	v++;
+			goto Largstart;
+		    }
+		}
+		continue;
+
+	    case '(':
+		if (!inexp && !instring && !incomment)
+		    parens++;
+		continue;
+
+	    case ')':
+		if (!inexp && !instring && !incomment && --parens == 0)
+		{
+		    break;
+		}
+		continue;
+
+	    case '"':
+	    case '\'':
+		if (!inexp && !incomment && intag)
+		{
+		    if (c == instring)
+			instring = 0;
+		    else if (!instring)
+			instring = c;
+		}
+		continue;
+
+	    case '<':
+		if (!inexp && !instring && !incomment)
+		{
+		    if (v + 6 < end &&
+			p[v + 1] == '!' &&
+			p[v + 2] == '-' &&
+			p[v + 3] == '-')
+		    {
+			incomment = 1;
+			v += 3;
+		    }
+		    else if (v + 2 < end &&
+			isalpha(p[v + 1]))
+			intag = 1;
+		}
+		continue;
+
+	    case '>':
+		if (!inexp)
+		    intag = 0;
+		continue;
+
+	    case '-':
+		if (!inexp &&
+		    !instring &&
+		    incomment &&
+		    v + 2 < end &&
+		    p[v + 1] == '-' &&
+		    p[v + 2] == '>')
+		{
+		    incomment = 0;
+		    v += 2;
+		}
+		continue;
+
+	    case 0xFF:
+		if (v + 1 < end)
+		{
+		    if (p[v + 1] == '{')
+			inexp++;
+		    else if (p[v + 1] == '}')
+			inexp--;
+		}
+		continue;
+
+	    default:
+		continue;
+	}
+	break;
+    }
+    if (argn == 0 && n == -1)
+	*pmarg = p + v;
+    *pmarglen = p + v - *pmarg;
+    //printf("extractArg%d('%.*s') = '%.*s'\n", n, end, p, *pmarglen, *pmarg);
+    return v;
+}
+
+
+/*****************************************************
+ * Expand macro in place in buf.
+ * Only look at the text in buf from start to end.
+ */
+
+void Macro::expand(OutBuffer *buf, unsigned start, unsigned *pend,
+	unsigned char *arg, unsigned arglen)
+{
+#if 0
+    printf("Macro::expand(buf[%d..%d], arg = '%.*s')\n", start, *pend, arglen, arg);
+    printf("Buf is: '%.*s'\n", *pend - start, buf->data + start);
+#endif
+
+    static int nest;
+    if (nest > 100)		// limit recursive expansion
+	return;
+    nest++;
+
+    unsigned end = *pend;
+    assert(start <= end);
+    assert(end <= buf->offset);
+
+    /* First pass - replace $0
+     */
+    arg = memdup(arg, arglen);
+    for (unsigned u = start; u + 1 < end; )
+    {
+	unsigned char *p = buf->data;	// buf->data is not loop invariant
+
+	/* Look for $0, but not $$0, and replace it with arg.
+	 */
+	if (p[u] == '$' && (isdigit(p[u + 1]) || p[u + 1] == '+'))
+	{
+	    if (u > start && p[u - 1] == '$')
+	    {   // Don't expand $$0, but replace it with $0
+		buf->remove(u - 1, 1);
+		end--;
+		u += 1;	// now u is one past the closing '1'
+		continue;
+	    }
+
+	    unsigned char c = p[u + 1];
+	    int n = (c == '+') ? -1 : c - '0';
+
+	    unsigned char *marg;
+	    unsigned marglen;
+	    extractArgN(arg, arglen, &marg, &marglen, n);
+	    if (marglen == 0)
+	    {	// Just remove macro invocation
+		//printf("Replacing '$%c' with '%.*s'\n", p[u + 1], marglen, marg);
+		buf->remove(u, 2);
+		end -= 2;
+	    }
+	    else if (c == '+')
+	    {
+		// Replace '$+' with 'arg'
+		//printf("Replacing '$%c' with '%.*s'\n", p[u + 1], marglen, marg);
+		buf->remove(u, 2);
+		buf->insert(u, marg, marglen);
+		end += marglen - 2;
+
+		// Scan replaced text for further expansion
+		unsigned mend = u + marglen;
+		expand(buf, u, &mend, NULL, 0);
+		end += mend - (u + marglen);
+		u = mend;
+	    }
+	    else
+	    {
+		// Replace '$1' with '\xFF{arg\xFF}'
+		//printf("Replacing '$%c' with '\xFF{%.*s\xFF}'\n", p[u + 1], marglen, marg);
+		buf->data[u] = 0xFF;
+		buf->data[u + 1] = '{';
+		buf->insert(u + 2, marg, marglen);
+		buf->insert(u + 2 + marglen, "\xFF}", 2);
+		end += -2 + 2 + marglen + 2;
+
+		// Scan replaced text for further expansion
+		unsigned mend = u + 2 + marglen;
+		expand(buf, u + 2, &mend, NULL, 0);
+		end += mend - (u + 2 + marglen);
+		u = mend;
+	    }
+	    //printf("u = %d, end = %d\n", u, end);
+	    //printf("#%.*s#\n", end, &buf->data[0]);
+	    continue;
+	}
+
+	u++;
+    }
+
+    /* Second pass - replace other macros
+     */
+    for (unsigned u = start; u + 4 < end; )
+    {
+	unsigned char *p = buf->data;	// buf->data is not loop invariant
+
+	/* A valid start of macro expansion is $(c, where c is
+	 * an id start character, and not $$(c.
+	 */
+	if (p[u] == '$' && p[u + 1] == '(' && isidstart(p[u + 2]))
+	{
+	    //printf("\tfound macro start '%c'\n", p[u + 2]);
+	    unsigned char *name = p + u + 2;
+	    unsigned namelen = 0;
+
+	    unsigned char *marg;
+	    unsigned marglen;
+
+	    unsigned v;
+	    /* Scan forward to find end of macro name and
+	     * beginning of macro argument (marg).
+	     */
+	    for (v = u + 2; v < end; v++)
+	    {	unsigned char c = p[v];
+
+		if (!isidchar(c))
+		{   // We've gone past the end of the macro name.
+		    namelen = v - (u + 2);
+		    break;
+		}
+	    }
+
+	    v += extractArgN(p + v, end - v, &marg, &marglen, 0);
+	    assert(v <= end);
+
+	    if (v < end)
+	    {	// v is on the closing ')'
+		if (u > start && p[u - 1] == '$')
+		{   // Don't expand $$(NAME), but replace it with $(NAME)
+		    buf->remove(u - 1, 1);
+		    end--;
+		    u = v;	// now u is one past the closing ')'
+		    continue;
+		}
+
+		Macro *m = search(name, namelen);
+		if (m)
+		{
+#if 0
+		    if (m->textlen && m->text[0] == ' ')
+		    {   m->text++;
+			m->textlen--;
+		    }
+#endif
+		    if (m->inuse && marglen == 0)
+		    {	// Remove macro invocation
+			buf->remove(u, v + 1 - u);
+			end -= v + 1 - u;
+		    }
+		    else if (m->inuse && arglen == marglen && memcmp(arg, marg, arglen) == 0)
+		    {	// Recursive expansion; just leave in place
+
+		    }
+		    else
+		    {
+			//printf("\tmacro '%.*s'(%.*s) = '%.*s'\n", m->namelen, m->name, marglen, marg, m->textlen, m->text);
+#if 1
+			marg = memdup(marg, marglen);
+			// Insert replacement text
+			buf->spread(v + 1, 2 + m->textlen + 2);
+			buf->data[v + 1] = 0xFF;
+			buf->data[v + 2] = '{';
+			memcpy(buf->data + v + 3, m->text, m->textlen);
+			buf->data[v + 3 + m->textlen] = 0xFF;
+			buf->data[v + 3 + m->textlen + 1] = '}';
+
+			end += 2 + m->textlen + 2;
+
+			// Scan replaced text for further expansion
+			m->inuse++;
+			unsigned mend = v + 1 + 2+m->textlen+2;
+			expand(buf, v + 1, &mend, marg, marglen);
+			end += mend - (v + 1 + 2+m->textlen+2);
+			m->inuse--;
+
+			buf->remove(u, v + 1 - u);
+			end -= v + 1 - u;
+			u += mend - (v + 1);
+#else
+			// Insert replacement text
+			buf->insert(v + 1, m->text, m->textlen);
+			end += m->textlen;
+
+			// Scan replaced text for further expansion
+			m->inuse++;
+			unsigned mend = v + 1 + m->textlen;
+			expand(buf, v + 1, &mend, marg, marglen);
+			end += mend - (v + 1 + m->textlen);
+			m->inuse--;
+
+			buf->remove(u, v + 1 - u);
+			end -= v + 1 - u;
+			u += mend - (v + 1);
+#endif
+			mem.free(marg);
+			//printf("u = %d, end = %d\n", u, end);
+			//printf("#%.*s#\n", end - u, &buf->data[u]);
+			continue;
+		    }
+		}
+		else
+		{
+		    // Replace $(NAME) with nothing
+		    buf->remove(u, v + 1 - u);
+		    end -= (v + 1 - u);
+		    continue;
+		}
+	    }
+	}
+	u++;
+    }
+    mem.free(arg);
+    *pend = end;
+    nest--;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/macro.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,44 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#ifndef DMD_MACRO_H
+#define DMD_MACRO_H 1
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <ctype.h>
+
+#include "root.h"
+
+
+class Macro
+{
+    Macro *next;		// next in list
+
+    unsigned char *name;	// macro name
+    size_t namelen;		// length of macro name
+
+    unsigned char *text;	// macro replacement text
+    size_t textlen;		// length of replacement text
+
+    int inuse;			// macro is in use (don't expand)
+
+    Macro(unsigned char *name, size_t namelen, unsigned char *text, size_t textlen);
+    Macro *search(unsigned char *name, size_t namelen);
+
+  public:
+    static Macro *define(Macro **ptable, unsigned char *name, size_t namelen, unsigned char *text, size_t textlen);
+
+    void expand(OutBuffer *buf, unsigned start, unsigned *pend,
+	unsigned char *arg, unsigned arglen);
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/mangle.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,249 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "root.h"
+
+#include "init.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "mtype.h"
+#include "attrib.h"
+#include "template.h"
+#include "id.h"
+#include "module.h"
+
+char *mangle(Declaration *sthis)
+{
+    OutBuffer buf;
+    char *id;
+    Dsymbol *s;
+
+    //printf("::mangle(%s)\n", sthis->toChars());
+    s = sthis;
+    do
+    {
+	//printf("mangle: s = %p, '%s', parent = %p\n", s, s->toChars(), s->parent);
+	if (s->ident)
+	{
+	    FuncDeclaration *fd = s->isFuncDeclaration();
+	    if (s != sthis && fd)
+	    {
+		id = mangle(fd);
+		buf.prependstring(id);
+		goto L1;
+	    }
+	    else
+	    {
+		id = s->ident->toChars();
+		int len = strlen(id);
+		char tmp[sizeof(len) * 3 + 1];
+		buf.prependstring(id);
+		sprintf(tmp, "%d", len);
+		buf.prependstring(tmp);
+	    }
+	}
+	else
+	    buf.prependstring("0");
+	s = s->parent;
+    } while (s);
+
+//    buf.prependstring("_D");
+L1:
+    //printf("deco = '%s'\n", sthis->type->deco ? sthis->type->deco : "null");
+    //printf("sthis->type = %s\n", sthis->type->toChars());
+    FuncDeclaration *fd = sthis->isFuncDeclaration();
+    if (fd && (fd->needThis() || fd->isNested()))
+	buf.writeByte(Type::needThisPrefix());
+    if (sthis->type->deco)
+	buf.writestring(sthis->type->deco);
+    else
+    {	assert(fd->inferRetType);
+    }
+
+    id = buf.toChars();
+    buf.data = NULL;
+    return id;
+}
+
+char *Declaration::mangle()
+#if __DMC__
+    __out(result)
+    {
+	int len = strlen(result);
+
+	assert(len > 0);
+	//printf("mangle: '%s' => '%s'\n", toChars(), result);
+	for (int i = 0; i < len; i++)
+	{
+	    assert(result[i] == '_' ||
+		   result[i] == '@' ||
+		   isalnum(result[i]) || result[i] & 0x80);
+	}
+    }
+    __body
+#endif
+    {
+	//printf("Declaration::mangle(this = %p, '%s', parent = '%s', linkage = %d)\n", this, toChars(), parent ? parent->toChars() : "null", linkage);
+	if (!parent || parent->isModule())	// if at global scope
+	{
+	    // If it's not a D declaration, no mangling
+	    switch (linkage)
+	    {
+		case LINKd:
+		    break;
+
+		case LINKc:
+		case LINKwindows:
+		case LINKpascal:
+		case LINKcpp:
+		    return ident->toChars();
+
+		case LINKdefault:
+		    error("forward declaration");
+		    return ident->toChars();
+
+		default:
+		    fprintf(stdmsg, "'%s', linkage = %d\n", toChars(), linkage);
+		    assert(0);
+	    }
+	}
+	char *p = ::mangle(this);
+	OutBuffer buf;
+	buf.writestring("_D");
+	buf.writestring(p);
+	p = buf.toChars();
+	buf.data = NULL;
+	//printf("Declaration::mangle(this = %p, '%s', parent = '%s', linkage = %d) = %s\n", this, toChars(), parent ? parent->toChars() : "null", linkage, p);
+	return p;
+    }
+
+char *FuncDeclaration::mangle()
+#if __DMC__
+    __out(result)
+    {
+	assert(strlen(result) > 0);
+    }
+    __body
+#endif
+    {
+	if (isMain())
+	    return "_Dmain";
+
+    assert(this);
+    
+    return Declaration::mangle();
+    }
+
+char *StructDeclaration::mangle()
+{
+    //printf("StructDeclaration::mangle() '%s'\n", toChars());
+    return Dsymbol::mangle();
+}
+
+
+char *TypedefDeclaration::mangle()
+{
+    //printf("TypedefDeclaration::mangle() '%s'\n", toChars());
+    return Dsymbol::mangle();
+}
+
+
+char *ClassDeclaration::mangle()
+{
+    Dsymbol *parentsave = parent;
+
+    //printf("ClassDeclaration::mangle() %s.%s\n", parent->toChars(), toChars());
+
+    /* These are reserved to the compiler, so keep simple
+     * names for them.
+     */
+    if (ident == Id::Exception)
+    {	if (parent->ident == Id::object)
+	    parent = NULL;
+    }
+    else if (ident == Id::TypeInfo   ||
+//	ident == Id::Exception ||
+	ident == Id::TypeInfo_Struct   ||
+	ident == Id::TypeInfo_Class    ||
+	ident == Id::TypeInfo_Typedef  ||
+	ident == Id::TypeInfo_Tuple ||
+	this == object     ||
+	this == classinfo  ||
+	this == Module::moduleinfo ||
+	memcmp(ident->toChars(), "TypeInfo_", 9) == 0
+       )
+	parent = NULL;
+
+    char *id = Dsymbol::mangle();
+    parent = parentsave;
+    return id;
+}
+
+
+char *TemplateInstance::mangle()
+{
+    OutBuffer buf;
+    char *id;
+
+#if 0
+    printf("TemplateInstance::mangle() %s", toChars());
+    if (parent)
+	printf("  parent = %s %s", parent->kind(), parent->toChars());
+    printf("\n");
+#endif
+    id = ident ? ident->toChars() : toChars();
+    if (tempdecl->parent)
+    {
+	char *p = tempdecl->parent->mangle();
+	if (p[0] == '_' && p[1] == 'D')
+	    p += 2;
+	buf.writestring(p);
+    }
+    buf.printf("%zu%s", strlen(id), id);
+    id = buf.toChars();
+    buf.data = NULL;
+    //printf("TemplateInstance::mangle() %s = %s\n", toChars(), id);
+    return id;
+}
+
+
+
+char *Dsymbol::mangle()
+{
+    OutBuffer buf;
+    char *id;
+
+#if 0
+    printf("Dsymbol::mangle() '%s'", toChars());
+    if (parent)
+	printf("  parent = %s %s", parent->kind(), parent->toChars());
+    printf("\n");
+#endif
+    id = ident ? ident->toChars() : toChars();
+    if (parent)
+    {
+	char *p = parent->mangle();
+	if (p[0] == '_' && p[1] == 'D')
+	    p += 2;
+	buf.writestring(p);
+    }
+    buf.printf("%zu%s", strlen(id), id);
+    id = buf.toChars();
+    buf.data = NULL;
+    //printf("Dsymbol::mangle() %s = %s\n", toChars(), id);
+    return id;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/mars.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,1164 @@
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include "llvm/Target/TargetMachineRegistry.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <assert.h>
+#include <limits.h>
+#include <string>
+
+#if _WIN32
+#include <windows.h>
+long __cdecl __ehfilter(LPEXCEPTION_POINTERS ep);
+#endif
+
+#if __DMC__
+#include <dos.h>
+#endif
+
+#if linux
+#include <errno.h>
+#endif
+
+#include "mem.h"
+#include "root.h"
+
+#include "mars.h"
+#include "module.h"
+#include "mtype.h"
+#include "id.h"
+#include "cond.h"
+#include "expression.h"
+#include "lexer.h"
+
+void getenv_setargv(const char *envvar, int *pargc, char** *pargv);
+
+Global global;
+
+Global::Global()
+{
+    mars_ext = "d";
+    sym_ext  = "d";
+    hdr_ext  = "di";
+    doc_ext  = "html";
+    ddoc_ext = "ddoc";
+
+#if IN_LLVM
+    obj_ext  = "bc";
+    ll_ext  = "ll";
+    bc_ext  = "bc";
+    nativeobj_ext = "o";
+#elif _WIN32
+    obj_ext  = "obj";
+#elif linux
+    obj_ext  = "o";
+#else
+#error "fix this"
+#endif
+
+    copyright = "Copyright (c) 1999-2007 by Digital Mars and Tomas Lindquist Olsen";
+    written = "written by Walter Bright and Tomas Lindquist Olsen";
+    llvmdc_version = "0.0.1";
+    version = "v1.020";
+    global.structalign = 8;
+
+    memset(&params, 0, sizeof(Param));
+}
+
+char *Loc::toChars()
+{
+    OutBuffer buf;
+    char *p;
+
+    if (filename)
+    {
+	buf.printf("%s", filename);
+    }
+
+    if (linnum)
+	buf.printf("(%d)", linnum);
+    buf.writeByte(0);
+    return (char *)buf.extractData();
+}
+
+Loc::Loc(Module *mod, unsigned linnum)
+{
+    this->linnum = linnum;
+    this->filename = mod ? mod->srcfile->toChars() : NULL;
+}
+
+/**************************************
+ * Print error message and exit.
+ */
+
+void error(Loc loc, const char *format, ...)
+{
+    va_list ap;
+    va_start(ap, format);
+    verror(loc, format, ap);
+    va_end( ap );
+}
+
+void verror(Loc loc, const char *format, va_list ap)
+{
+    if (!global.gag)
+    {
+	char *p = loc.toChars();
+
+	if (*p)
+	    fprintf(stdmsg, "%s: ", p);
+	mem.free(p);
+
+	fprintf(stdmsg, "Error: ");
+	vfprintf(stdmsg, format, ap);
+	fprintf(stdmsg, "\n");
+	fflush(stdmsg);
+    }
+    global.errors++;
+}
+
+/***************************************
+ * Call this after printing out fatal error messages to clean up and exit
+ * the compiler.
+ */
+
+void fatal()
+{
+#if 0
+    halt();
+#endif
+    exit(EXIT_FAILURE);
+}
+
+/**************************************
+ * Try to stop forgetting to remove the breakpoints from
+ * release builds.
+ */
+void halt()
+{
+#ifdef DEBUG
+    *(char*)0=0;
+#endif
+}
+
+extern void backend_init();
+extern void backend_term();
+
+void usage()
+{
+    printf("LLVM D Compiler %s (based on DMD %s)\n%s\n%s\n",
+    global.llvmdc_version, global.version, global.copyright, global.written);
+    printf("\
+Documentation: http://www.digitalmars.com/d/1.0/index.html\n\
+Usage:\n\
+  dmd files.d ... { -switch }\n\
+\n\
+  files.d        D source files\n%s\
+  -c             do not link\n\
+  -cov           do code coverage analysis\n\
+  -D             generate documentation\n\
+  -Dddocdir      write documentation file to docdir directory\n\
+  -Dffilename    write documentation file to filename\n\
+  -d             allow deprecated features\n\
+  -debug         compile in debug code\n\
+  -debug=level   compile in debug code <= level\n\
+  -debug=ident   compile in debug code identified by ident\n\
+  -g             add symbolic debug info\n\
+  -gc            add symbolic debug info, pretend to be C\n\
+  -H             generate 'header' file\n\
+  -Hdhdrdir      write 'header' file to hdrdir directory\n\
+  -Hffilename    write 'header' file to filename\n\
+  --help         print help\n\
+  -Ipath         where to look for imports\n\
+  -Epath         where to look for the core runtime\n\
+  -Jpath         where to look for string imports\n\
+  -inline        do function inlining\n\
+  -Llinkerflag   pass linkerflag to link\n\
+  -march         emit code specific to arch\n\
+                 x86 x86-64 ppc32 ppc64\n\
+  -nofloat       do not emit reference to floating point\n\
+  -noruntime     do not allow code that generates implicit runtime calls\n\
+  -O             optimize, same as -O2\n\
+  -On            optimize at level n (0-5)\n\
+  -o-            do not write object file\n\
+  -odobjdir      write object files to directory objdir\n\
+  -offilename	 name output file to filename\n\
+  -op            do not strip paths from source file\n\
+  -profile	 profile runtime performance of generated code\n\
+  -quiet         suppress unnecessary messages\n\
+  -release	 compile release version\n\
+  -run srcfile args...   run resulting program, passing args\n\
+  -unittest      compile in unit tests\n\
+  -v             verbose\n\
+  -v1            D language version 1\n\
+  -version=level compile in version code >= level\n\
+  -version=ident compile in version code identified by ident\n\
+  -w             enable warnings\n\
+",
+#if WIN32
+"  @cmdfile       read arguments from cmdfile\n"
+#else
+""
+#endif
+);
+}
+
+int main(int argc, char *argv[])
+{
+    int i;
+    Array files;
+    char *p;
+    Module *m;
+    int status = EXIT_SUCCESS;
+    int argcstart = argc;
+    char* tt_arch = 0;
+    char* tt_os = 0;
+    char* data_layout = 0;
+
+    // Check for malformed input
+    if (argc < 1 || !argv)
+    {
+      Largs:
+	error("missing or null command line arguments");
+	fatal();
+    }
+    for (i = 0; i < argc; i++)
+    {
+	if (!argv[i])
+	    goto Largs;
+    }
+
+#if __DMC__	// DMC unique support for response files
+    if (response_expand(&argc,&argv))	// expand response files
+	error("can't open response file");
+#endif
+
+    files.reserve(argc - 1);
+
+    // Set default values
+    global.params.argv0 = argv[0];
+    global.params.link = 1;
+    global.params.useAssert = 0;
+    global.params.useInvariants = 0;
+    global.params.useIn = 0;
+    global.params.useOut = 0;
+    global.params.useArrayBounds = 0;
+    global.params.useSwitchError = 0;
+    global.params.useInline = 0;
+    global.params.obj = 1;
+    global.params.Dversion = 2;
+
+    global.params.linkswitches = new Array();
+    global.params.libfiles = new Array();
+    global.params.objfiles = new Array();
+    global.params.ddocfiles = new Array();
+
+    global.params.is64bit = sizeof(void*) == 8 ? 1 : 0;
+
+    uint16_t endiantest = 0xFF00;
+    uint8_t endianres = ((uint8_t*)&endiantest)[0];
+    if (endianres == 0x00)
+        global.params.isLE = true;
+    else if (endianres == 0xFF)
+        global.params.isLE = false;
+    else {
+        error("Endian test is broken");
+        fatal();
+    }
+
+    global.params.llvmArch = 0;
+    global.params.forceBE = 0;
+    global.params.noruntime = 0;
+    global.params.optimizeLevel = 2;
+    global.params.runtimeImppath = 0;
+
+    // Predefine version identifiers
+#if IN_LLVM
+    VersionCondition::addPredefinedGlobalIdent("LLVM");
+#endif
+#if _WIN32
+    VersionCondition::addPredefinedGlobalIdent("Windows");
+    VersionCondition::addPredefinedGlobalIdent("Win32");
+    global.params.isWindows = 1;
+#elif linux
+    VersionCondition::addPredefinedGlobalIdent("linux");
+    global.params.isLinux = 1;
+    tt_os = "-unknown-linux-gnu";
+#else
+#error
+#endif /* linux */
+
+    //VersionCondition::addPredefinedGlobalIdent("D_Bits");
+    //VersionCondition::addPredefinedGlobalIdent("D_InlineAsm");
+    //VersionCondition::addPredefinedGlobalIdent("D_InlineAsm_X86");
+    VersionCondition::addPredefinedGlobalIdent("all");
+
+#if _WIN32
+    inifile(argv[0], "llvmdc.ini");
+#endif
+#if linux
+    inifile(argv[0], "llvmdc.conf");
+#else
+#error
+#endif
+    getenv_setargv("DFLAGS", &argc, &argv);
+
+#if 0
+    for (i = 0; i < argc; i++)
+    {
+	printf("argv[%d] = '%s'\n", i, argv[i]);
+    }
+#endif
+
+    for (i = 1; i < argc; i++)
+    {
+	p = argv[i];
+	if (*p == '-')
+	{
+	    if (strcmp(p + 1, "d") == 0)
+		global.params.useDeprecated = 1;
+	    else if (strcmp(p + 1, "c") == 0)
+		global.params.link = 0;
+	    else if (strcmp(p + 1, "cov") == 0)
+		global.params.cov = 1;
+	    else if (strcmp(p + 1, "fPIC") == 0)
+		global.params.pic = 1;
+	    else if (strcmp(p + 1, "g") == 0)
+		global.params.symdebug = 1;
+	    else if (strcmp(p + 1, "gc") == 0)
+		global.params.symdebug = 2;
+	    else if (strcmp(p + 1, "gt") == 0)
+	    {	error("use -profile instead of -gt\n");
+            global.params.trace = 1;
+	    }
+	    else if (strcmp(p + 1, "profile") == 0)
+		global.params.trace = 1;
+	    else if (strcmp(p + 1, "v") == 0)
+		global.params.verbose = 1;
+	    else if (strcmp(p + 1, "v1") == 0)
+		global.params.Dversion = 1;
+	    else if (strcmp(p + 1, "w") == 0)
+		global.params.warnings = 1;
+	    else if (strcmp(p + 1, "O") == 0)
+        {
+            global.params.optimize = 1;
+            if (p[2] != 0) {
+                int optlevel = atoi(p+2);
+                if (optlevel < 0 || optlevel > 5) {
+                    error("Optimization level must be between 0 and 5. Using default (%d)",
+                    global.params.optimizeLevel);
+                }
+                else {
+                    global.params.optimizeLevel = optlevel;
+                }
+            }
+        }
+        else if (strcmp(p + 1, "forcebe") == 0)
+		global.params.forceBE = 1;
+        else if (strcmp(p + 1, "noruntime") == 0)
+		global.params.noruntime = 1;
+	    else if (p[1] == 'o')
+	    {
+		switch (p[2])
+		{
+		    case '-':
+			global.params.obj = 0;
+			break;
+
+		    case 'd':
+			if (!p[3])
+			    goto Lnoarg;
+			global.params.objdir = p + 3;
+			break;
+
+		    case 'f':
+			if (!p[3])
+			    goto Lnoarg;
+			global.params.objname = p + 3;
+			break;
+
+		    case 'p':
+			if (p[3])
+			    goto Lerror;
+			global.params.preservePaths = 1;
+			break;
+
+		    case 0:
+			error("-o no longer supported, use -of or -od");
+			break;
+
+		    default:
+			goto Lerror;
+		}
+	    }
+	    else if (p[1] == 'D')
+	    {	global.params.doDocComments = 1;
+		switch (p[2])
+		{
+		    case 'd':
+			if (!p[3])
+			    goto Lnoarg;
+			global.params.docdir = p + 3;
+			break;
+		    case 'f':
+			if (!p[3])
+			    goto Lnoarg;
+			global.params.docname = p + 3;
+			break;
+
+		    case 0:
+			break;
+
+		    default:
+			goto Lerror;
+		}
+	    }
+#ifdef _DH
+	    else if (p[1] == 'H')
+	    {	global.params.doHdrGeneration = 1;
+		switch (p[2])
+		{
+		    case 'd':
+			if (!p[3])
+			    goto Lnoarg;
+			global.params.hdrdir = p + 3;
+			break;
+
+		    case 'f':
+			if (!p[3])
+			    goto Lnoarg;
+			global.params.hdrname = p + 3;
+			break;
+
+		    case 0:
+			break;
+
+		    default:
+			goto Lerror;
+		}
+	    }
+#endif
+	    else if (strcmp(p + 1, "inline") == 0)
+		global.params.useInline = 1;
+	    else if (strcmp(p + 1, "nofloat") == 0)
+		global.params.nofloat = 1;
+	    else if (strcmp(p + 1, "quiet") == 0)
+		global.params.quiet = 1;
+	    else if (strcmp(p + 1, "release") == 0)
+		global.params.release = 1;
+	    else if (strcmp(p + 1, "unittest") == 0)
+		global.params.useUnitTests = 1;
+	    else if (p[1] == 'I')
+	    {
+		if (!global.params.imppath)
+		    global.params.imppath = new Array();
+		global.params.imppath->push(p + 2);
+	    }
+	    else if (p[1] == 'J')
+	    {
+		if (!global.params.fileImppath)
+		    global.params.fileImppath = new Array();
+		global.params.fileImppath->push(p + 2);
+	    }
+        else if (p[1] == 'E')
+        {
+        global.params.runtimeImppath = p+2;
+        }
+	    else if (memcmp(p + 1, "debug", 5) == 0)
+	    {
+		// Parse:
+		//	-debug
+		//	-debug=number
+		//	-debug=identifier
+		if (p[6] == '=')
+		{
+		    if (isdigit(p[7]))
+		    {	long level;
+
+			errno = 0;
+			level = strtol(p + 7, &p, 10);
+			if (*p || errno || level > INT_MAX)
+			    goto Lerror;
+			DebugCondition::setGlobalLevel((int)level);
+		    }
+		    else if (Lexer::isValidIdentifier(p + 7))
+			DebugCondition::addGlobalIdent(p + 7);
+		    else
+			goto Lerror;
+		}
+		else if (p[6])
+		    goto Lerror;
+		else
+		    global.params.debuglevel = 1;
+	    }
+	    else if (memcmp(p + 1, "version", 5) == 0)
+	    {
+		// Parse:
+		//	-version=number
+		//	-version=identifier
+		if (p[8] == '=')
+		{
+		    if (isdigit(p[9]))
+		    {	long level;
+
+			errno = 0;
+			level = strtol(p + 9, &p, 10);
+			if (*p || errno || level > INT_MAX)
+			    goto Lerror;
+			VersionCondition::setGlobalLevel((int)level);
+		    }
+		    else if (Lexer::isValidIdentifier(p + 9))
+			VersionCondition::addGlobalIdent(p + 9);
+		    else
+			goto Lerror;
+		}
+		else
+		    goto Lerror;
+	    }
+	    else if (strcmp(p + 1, "-b") == 0)
+		global.params.debugb = 1;
+	    else if (strcmp(p + 1, "-c") == 0)
+		global.params.debugc = 1;
+	    else if (strcmp(p + 1, "-f") == 0)
+		global.params.debugf = 1;
+	    else if (strcmp(p + 1, "-help") == 0)
+	    {	usage();
+		exit(EXIT_SUCCESS);
+	    }
+	    else if (strcmp(p + 1, "-r") == 0)
+		global.params.debugr = 1;
+	    else if (strcmp(p + 1, "-x") == 0)
+		global.params.debugx = 1;
+	    else if (strcmp(p + 1, "-y") == 0)
+		global.params.debugy = 1;
+	    else if (p[1] == 'L')
+	    {
+		global.params.linkswitches->push(p + 2);
+	    }
+	    else if (strcmp(p + 1, "run") == 0)
+	    {	global.params.run = 1;
+		global.params.runargs_length = ((i >= argcstart) ? argc : argcstart) - i - 1;
+		if (global.params.runargs_length)
+		{
+		    files.push(argv[i + 1]);
+		    global.params.runargs = &argv[i + 2];
+		    i += global.params.runargs_length;
+		    global.params.runargs_length--;
+		}
+		else
+		{   global.params.run = 0;
+		    goto Lnoarg;
+		}
+	    }
+        else if (p[1] == 'm')
+        {
+            global.params.llvmArch = p+2;
+        }
+	    else
+	    {
+	     Lerror:
+		error("unrecognized switch '%s'", argv[i]);
+		continue;
+
+	     Lnoarg:
+		error("argument expected for switch '%s'", argv[i]);
+		continue;
+	    }
+	}
+	else
+	    files.push(p);
+    }
+    if (global.errors)
+    {
+	fatal();
+    }
+    if (files.dim == 0)
+    {	usage();
+	return EXIT_FAILURE;
+    }
+
+    if (global.params.release)
+    {	global.params.useInvariants = 0;
+	global.params.useIn = 0;
+	global.params.useOut = 0;
+	global.params.useAssert = 0;
+	global.params.useArrayBounds = 0;
+	global.params.useSwitchError = 0;
+    }
+
+    if (global.params.run)
+	global.params.quiet = 1;
+
+    if (global.params.useUnitTests)
+	global.params.useAssert = 1;
+
+    if (!global.params.obj)
+	global.params.link = 0;
+
+    if (global.params.link)
+    {
+	global.params.exefile = global.params.objname;
+	global.params.objname = NULL;
+    }
+    else if (global.params.run)
+    {
+	error("flags conflict with -run");
+	fatal();
+    }
+    else
+    {
+	if (global.params.objname && files.dim > 1)
+	{
+	    error("multiple source files, but only one .obj name");
+	    fatal();
+	}
+    }
+    if (global.params.cov)
+	VersionCondition::addPredefinedGlobalIdent("D_Coverage");
+
+    bool allowForceEndianness = false;
+
+    if (global.params.llvmArch == 0) {
+        std::string err_str;
+        const llvm::TargetMachineRegistry::Entry* e = llvm::TargetMachineRegistry::getClosestTargetForJIT(err_str);
+        if (e == 0) {
+            error("Failed to find a default target machine: %s", err_str.c_str());
+            fatal();
+        }
+        else {
+            global.params.llvmArch = const_cast<char*>(e->Name);
+            printf("Default target found: %s\n", global.params.llvmArch);
+        }
+    }
+
+    if (strcmp(global.params.llvmArch,"x86")==0) {
+        VersionCondition::addPredefinedGlobalIdent("X86");
+        global.params.isLE = true;
+        global.params.is64bit = false;
+        tt_arch = "i686";
+        data_layout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:8";
+    }
+    else if (strcmp(global.params.llvmArch,"x86-64")==0) {
+        VersionCondition::addPredefinedGlobalIdent("X86_64");
+        global.params.isLE = true;
+        global.params.is64bit = true;
+        tt_arch = "x86_64";
+        data_layout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:8";
+    }
+    else if (strcmp(global.params.llvmArch,"ppc32")==0) {
+        VersionCondition::addPredefinedGlobalIdent("PPC");
+        global.params.isLE = false;
+        global.params.is64bit = false;
+        tt_arch = "powerpc";
+        data_layout = "E-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:8";
+    }
+    else if (strcmp(global.params.llvmArch,"ppc64")==0) {
+        VersionCondition::addPredefinedGlobalIdent("PPC64");
+        global.params.isLE = false;
+        global.params.is64bit = true;
+        tt_arch = "powerpc64";
+        data_layout = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:8";
+    }
+    else {
+        assert(0 && "Invalid arch");
+    }
+
+    if (allowForceEndianness && global.params.forceBE) {
+        VersionCondition::addPredefinedGlobalIdent("BigEndian");
+        global.params.isLE = false;
+    }
+    else if (global.params.isLE) {
+        VersionCondition::addPredefinedGlobalIdent("LittleEndian");
+    }
+    else {
+        VersionCondition::addPredefinedGlobalIdent("BigEndian");
+    }
+
+    if (global.params.is64bit) {
+        VersionCondition::addPredefinedGlobalIdent("LLVM64");
+    }
+
+    assert(tt_arch != 0);
+    assert(tt_os != 0);
+    assert(data_layout != 0);
+    global.params.tt_arch = tt_arch;
+    global.params.tt_os = tt_os;
+    global.params.data_layout = data_layout;
+
+    // Initialization
+    Type::init();
+    Id::initialize();
+    Module::init();
+    initPrecedence();
+
+    backend_init();
+
+    //printf("%d source files\n",files.dim);
+
+    // Build import search path
+    if (global.params.imppath)
+    {
+	for (i = 0; i < global.params.imppath->dim; i++)
+	{
+	    char *path = (char *)global.params.imppath->data[i];
+	    Array *a = FileName::splitPath(path);
+
+	    if (a)
+	    {
+		if (!global.path)
+		    global.path = new Array();
+		global.path->append(a);
+	    }
+	}
+    }
+
+    // Build string import search path
+    if (global.params.fileImppath)
+    {
+	for (i = 0; i < global.params.fileImppath->dim; i++)
+	{
+	    char *path = (char *)global.params.fileImppath->data[i];
+	    Array *a = FileName::splitPath(path);
+
+	    if (a)
+	    {
+		if (!global.filePath)
+		    global.filePath = new Array();
+		global.filePath->append(a);
+	    }
+	}
+    }
+
+    // Create Modules
+    Array modules;
+    modules.reserve(files.dim);
+    for (i = 0; i < files.dim; i++)
+    {	Identifier *id;
+	char *ext;
+	char *name;
+
+	p = (char *) files.data[i];
+
+#if _WIN32
+	// Convert / to \ so linker will work
+	for (int i = 0; p[i]; i++)
+	{
+	    if (p[i] == '/')
+		p[i] = '\\';
+	}
+#endif
+
+	p = FileName::name(p);		// strip path
+	ext = FileName::ext(p);
+	if (ext)
+	{
+#if IN_LLVM
+        if (strcmp(ext, global.nativeobj_ext) == 0 ||
+            strcmp(ext, global.obj_ext) == 0)
+#elif TARGET_LINUX
+	    if (strcmp(ext, global.obj_ext) == 0)
+#else
+	    if (stricmp(ext, global.obj_ext) == 0)
+#endif
+	    {
+		global.params.objfiles->push(files.data[i]);
+		continue;
+	    }
+
+#if !IN_LLVM
+#if TARGET_LINUX
+	    if (strcmp(ext, "a") == 0)
+#else
+	    if (stricmp(ext, "lib") == 0)
+#endif
+	    {
+		global.params.libfiles->push(files.data[i]);
+		continue;
+	    }
+#endif
+
+	    if (strcmp(ext, global.ddoc_ext) == 0)
+	    {
+		global.params.ddocfiles->push(files.data[i]);
+		continue;
+	    }
+
+#if !TARGET_LINUX
+	    if (stricmp(ext, "res") == 0)
+	    {
+		global.params.resfile = (char *)files.data[i];
+		continue;
+	    }
+
+	    if (stricmp(ext, "def") == 0)
+	    {
+		global.params.deffile = (char *)files.data[i];
+		continue;
+	    }
+
+	    if (stricmp(ext, "exe") == 0)
+	    {
+		global.params.exefile = (char *)files.data[i];
+		continue;
+	    }
+#endif
+
+	    if (stricmp(ext, global.mars_ext) == 0 ||
+		stricmp(ext, "htm") == 0 ||
+		stricmp(ext, "html") == 0 ||
+		stricmp(ext, "xhtml") == 0)
+	    {
+		ext--;			// skip onto '.'
+		assert(*ext == '.');
+		name = (char *)mem.malloc((ext - p) + 1);
+		memcpy(name, p, ext - p);
+		name[ext - p] = 0;		// strip extension
+
+		if (name[0] == 0 ||
+		    strcmp(name, "..") == 0 ||
+		    strcmp(name, ".") == 0)
+		{
+		Linvalid:
+		    error("invalid file name '%s'", (char *)files.data[i]);
+		    fatal();
+		}
+	    }
+	    else
+	    {	error("unrecognized file extension %s\n", ext);
+		fatal();
+	    }
+	}
+	else
+	{   name = p;
+	    if (!*name)
+		goto Linvalid;
+	}
+
+	id = new Identifier(name, 0);
+	m = new Module((char *) files.data[i], id, global.params.doDocComments, global.params.doHdrGeneration);
+	modules.push(m);
+
+	global.params.objfiles->push(m->objfile->name->str);
+    }
+
+#if _WIN32
+  __try
+  {
+#endif
+    // Read files, parse them
+    for (i = 0; i < modules.dim; i++)
+    {
+	m = (Module *)modules.data[i];
+	if (global.params.verbose)
+	    printf("parse     %s\n", m->toChars());
+	if (!Module::rootModule)
+	    Module::rootModule = m;
+	m->importedFrom = m;
+	m->deleteObjFile();
+	m->read(0);
+	m->parse();
+	if (m->isDocFile)
+	{
+	    m->gendocfile();
+
+	    // Remove m from list of modules
+	    modules.remove(i);
+	    i--;
+
+	    // Remove m's object file from list of object files
+	    for (int j = 0; j < global.params.objfiles->dim; j++)
+	    {
+		if (m->objfile->name->str == global.params.objfiles->data[j])
+		{
+		    global.params.objfiles->remove(j);
+		    break;
+		}
+	    }
+
+	    if (global.params.objfiles->dim == 0)
+		global.params.link = 0;
+	}
+    }
+    if (global.errors)
+	fatal();
+#ifdef _DH
+    if (global.params.doHdrGeneration)
+    {
+	/* Generate 'header' import files.
+	 * Since 'header' import files must be independent of command
+	 * line switches and what else is imported, they are generated
+	 * before any semantic analysis.
+	 */
+	for (i = 0; i < modules.dim; i++)
+	{
+	    m = (Module *)modules.data[i];
+	    if (global.params.verbose)
+		printf("import    %s\n", m->toChars());
+	    m->genhdrfile();
+	}
+    }
+    if (global.errors)
+	fatal();
+#endif
+
+    // Do semantic analysis
+    for (i = 0; i < modules.dim; i++)
+    {
+	m = (Module *)modules.data[i];
+	if (global.params.verbose)
+	    printf("semantic  %s\n", m->toChars());
+	m->semantic();
+    }
+    if (global.errors)
+	fatal();
+
+    // Do pass 2 semantic analysis
+    for (i = 0; i < modules.dim; i++)
+    {
+	m = (Module *)modules.data[i];
+	if (global.params.verbose)
+	    printf("semantic2 %s\n", m->toChars());
+	m->semantic2();
+    }
+    if (global.errors)
+	fatal();
+
+    // Do pass 3 semantic analysis
+    for (i = 0; i < modules.dim; i++)
+    {
+	m = (Module *)modules.data[i];
+	if (global.params.verbose)
+	    printf("semantic3 %s\n", m->toChars());
+	m->semantic3();
+    }
+    if (global.errors)
+	fatal();
+
+    // Scan for functions to inline
+    if (global.params.useInline)
+    {
+	/* The problem with useArrayBounds and useAssert is that the
+	 * module being linked to may not have generated them, so if
+	 * we inline functions from those modules, the symbols for them will
+	 * not be found at link time.
+	 */
+	if (!global.params.useArrayBounds && !global.params.useAssert)
+	{
+	    // Do pass 3 semantic analysis on all imported modules,
+	    // since otherwise functions in them cannot be inlined
+	    for (i = 0; i < Module::amodules.dim; i++)
+	    {
+		m = (Module *)Module::amodules.data[i];
+		if (global.params.verbose)
+		    printf("semantic3 %s\n", m->toChars());
+		m->semantic3();
+	    }
+	    if (global.errors)
+		fatal();
+	}
+
+	for (i = 0; i < modules.dim; i++)
+	{
+	    m = (Module *)modules.data[i];
+	    if (global.params.verbose)
+		printf("inline scan %s\n", m->toChars());
+	    m->inlineScan();
+	}
+    }
+    if (global.errors)
+	fatal();
+
+    // Generate output files
+    for (i = 0; i < modules.dim; i++)
+    {
+	m = (Module *)modules.data[i];
+	if (global.params.verbose)
+	    printf("code      %s\n", m->toChars());
+	if (global.params.obj)
+	    m->genobjfile();
+	if (global.errors)
+	    m->deleteObjFile();
+	else
+	{
+	    if (global.params.doDocComments)
+		m->gendocfile();
+	}
+    }
+#if _WIN32
+  }
+  __except (__ehfilter(GetExceptionInformation()))
+  {
+    printf("Stack overflow\n");
+    fatal();
+  }
+#endif
+    backend_term();
+    if (global.errors)
+	fatal();
+
+    if (!global.params.objfiles->dim)
+    {
+	if (global.params.link)
+	    error("no object files to link");
+    }
+    else
+    {
+	if (global.params.link)
+	    status = runLINK();
+
+	if (global.params.run)
+	{
+	    if (!status)
+	    {
+		status = runProgram();
+
+		/* Delete .obj files and .exe file
+		 */
+		for (i = 0; i < modules.dim; i++)
+		{
+		    m = (Module *)modules.data[i];
+		    m->deleteObjFile();
+		}
+		deleteExeFile();
+	    }
+	}
+    }
+
+    return status;
+}
+
+
+
+/***********************************
+ * Parse and append contents of environment variable envvar
+ * to argc and argv[].
+ * The string is separated into arguments, processing \ and ".
+ */
+
+void getenv_setargv(const char *envvar, int *pargc, char** *pargv)
+{
+    char *env;
+    char *p;
+    Array *argv;
+    int argc;
+
+    int wildcard;		// do wildcard expansion
+    int instring;
+    int slash;
+    char c;
+    int j;
+
+    env = getenv(envvar);
+    if (!env)
+	return;
+
+    env = mem.strdup(env);	// create our own writable copy
+
+    argc = *pargc;
+    argv = new Array();
+    argv->setDim(argc);
+
+    for (int i = 0; i < argc; i++)
+	argv->data[i] = (void *)(*pargv)[i];
+
+    j = 1;			// leave argv[0] alone
+    while (1)
+    {
+	wildcard = 1;
+	switch (*env)
+	{
+	    case ' ':
+	    case '\t':
+		env++;
+		break;
+
+	    case 0:
+		goto Ldone;
+
+	    case '"':
+		wildcard = 0;
+	    default:
+		argv->push(env);		// append
+		//argv->insert(j, env);		// insert at position j
+		j++;
+		argc++;
+		p = env;
+		slash = 0;
+		instring = 0;
+		c = 0;
+
+		while (1)
+		{
+		    c = *env++;
+		    switch (c)
+		    {
+			case '"':
+			    p -= (slash >> 1);
+			    if (slash & 1)
+			    {	p--;
+				goto Laddc;
+			    }
+			    instring ^= 1;
+			    slash = 0;
+			    continue;
+
+			case ' ':
+			case '\t':
+			    if (instring)
+				goto Laddc;
+			    *p = 0;
+			    //if (wildcard)
+				//wildcardexpand();	// not implemented
+			    break;
+
+			case '\\':
+			    slash++;
+			    *p++ = c;
+			    continue;
+
+			case 0:
+			    *p = 0;
+			    //if (wildcard)
+				//wildcardexpand();	// not implemented
+			    goto Ldone;
+
+			default:
+			Laddc:
+			    slash = 0;
+			    *p++ = c;
+			    continue;
+		    }
+		    break;
+		}
+	}
+    }
+
+Ldone:
+    *pargc = argc;
+    *pargv = (char **)argv->data;
+}
+
+#if _WIN32
+
+long __cdecl __ehfilter(LPEXCEPTION_POINTERS ep)
+{
+    //printf("%x\n", ep->ExceptionRecord->ExceptionCode);
+    if (ep->ExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW)
+    {
+#ifndef DEBUG
+	return EXCEPTION_EXECUTE_HANDLER;
+#endif
+    }
+    return EXCEPTION_CONTINUE_SEARCH;
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/mars.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,297 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#ifndef DMD_MARS_H
+#define DMD_MARS_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include <stdint.h>
+#include <string>
+#include <cstdarg>
+
+#ifdef __DMC__
+#ifdef DEBUG
+#undef assert
+#define assert(e) (static_cast<void>((e) || (printf("assert %s(%d) %s\n", __FILE__, __LINE__, #e), halt())))
+#endif
+#endif
+
+#ifdef IN_GCC
+/* Changes for the GDC compiler by David Friedman */
+#endif
+
+#define V2	0	// Version 2.0 features
+#define BREAKABI 1	// 0 if not ready to break the ABI just yet
+
+struct Array;
+
+// Put command line switches in here
+struct Param
+{
+    char obj;		// write object file
+    char link;		// perform link
+    char trace;		// insert profiling hooks
+    char quiet;		// suppress non-error messages
+    char verbose;	// verbose compile
+    char symdebug;	// insert debug symbolic information
+    char optimize;	// run optimizer
+    char optimizeLevel; // optimization level
+    char cpu;		// target CPU
+    char is64bit;	// generate 64 bit code
+    char isLE;      // generate little endian code
+    char isLinux;	// generate code for linux
+    char isWindows;	// generate code for Windows
+    char scheduler;	// which scheduler to use
+    char useDeprecated;	// allow use of deprecated features
+    char useAssert;	// generate runtime code for assert()'s
+    char useInvariants;	// generate class invariant checks
+    char useIn;		// generate precondition checks
+    char useOut;	// generate postcondition checks
+    char useArrayBounds; // generate array bounds checks
+    char useSwitchError; // check for switches without a default
+    char useUnitTests;	// generate unittest code
+    char useInline;	// inline expand functions
+    char release;	// build release version
+    char preservePaths;	// !=0 means don't strip path from source file
+    char warnings;	// enable warnings
+    char pic;		// generate position-independent-code for shared libs
+    char cov;		// generate code coverage data
+    char nofloat;	// code should not pull in floating point support
+    char noruntime;	// code is not allowed to make implicit calls to the runtime
+    char Dversion;	// D version number
+
+    char *argv0;	// program name
+    Array *imppath;	// array of char*'s of where to look for import modules
+    Array *fileImppath;	// array of char*'s of where to look for file import modules
+    char *runtimeImppath; // char* of where to look for the core runtime
+    char *objdir;	// .obj file output directory
+    char *objname;	// .obj file output name
+
+    char doDocComments;	// process embedded documentation comments
+    char *docdir;	// write documentation file to docdir directory
+    char *docname;	// write documentation file to docname
+    Array *ddocfiles;	// macro include files for Ddoc
+
+    char doHdrGeneration;	// process embedded documentation comments
+    char *hdrdir;		// write 'header' file to docdir directory
+    char *hdrname;		// write 'header' file to docname
+
+    unsigned debuglevel;	// debug level
+    Array *debugids;		// debug identifiers
+
+    unsigned versionlevel;	// version level
+    Array *versionids;		// version identifiers
+
+    bool dump_source;
+
+    // Hidden debug switches
+    char debuga;
+    char debugb;
+    char debugc;
+    char debugf;
+    char debugr;
+    char debugw;
+    char debugx;
+    char debugy;
+
+    char run;		// run resulting executable
+    size_t runargs_length;
+    char** runargs;	// arguments for executable
+
+    // Linker stuff
+    Array *objfiles;
+    Array *linkswitches;
+    Array *libfiles;
+    char *deffile;
+    char *resfile;
+    char *exefile;
+
+    // LLVM stuff
+    char *llvmArch;
+    char forceBE;
+    char *tt_arch;
+    char *tt_os;
+    char *data_layout;
+};
+
+struct Global
+{
+    char *mars_ext;
+    char *sym_ext;
+    char *obj_ext;
+    char *ll_ext;
+    char *bc_ext;
+    char *nativeobj_ext;
+    char *doc_ext;	// for Ddoc generated files
+    char *ddoc_ext;	// for Ddoc macro include files
+    char *hdr_ext;	// for D 'header' import files
+    char *copyright;
+    char *written;
+    Array *path;	// Array of char*'s which form the import lookup path
+    Array *filePath;	// Array of char*'s which form the file import lookup path
+    int structalign;
+    char *version;
+    char *llvmdc_version;
+
+    Param params;
+    unsigned errors;	// number of errors reported so far
+    unsigned gag;	// !=0 means gag reporting of errors
+
+    Global();
+};
+
+extern Global global;
+
+#if __GNUC__
+//#define memicmp strncasecmp
+//#define stricmp strcasecmp
+#endif
+
+#ifdef __DMC__
+ typedef _Complex long double complex_t;
+#else
+ #ifndef IN_GCC
+  #include "complex_t.h"
+ #endif
+ #ifdef __APPLE__
+  //#include "complex.h"//This causes problems with include the c++ <complex> and not the C "complex.h"
+  #define integer_t dmd_integer_t
+ #endif
+#endif
+
+// Be careful not to care about sign when using integer_t
+typedef uint64_t integer_t;
+
+// Signed and unsigned variants
+typedef int64_t sinteger_t;
+typedef uint64_t uinteger_t;
+
+typedef int8_t			d_int8;
+typedef uint8_t			d_uns8;
+typedef int16_t			d_int16;
+typedef uint16_t		d_uns16;
+typedef int32_t			d_int32;
+typedef uint32_t		d_uns32;
+typedef int64_t			d_int64;
+typedef uint64_t		d_uns64;
+
+typedef float			d_float32;
+typedef double			d_float64;
+typedef long double		d_float80;
+
+typedef d_uns8			d_char;
+typedef d_uns16			d_wchar;
+typedef d_uns32			d_dchar;
+
+#ifdef IN_GCC
+#include "d-gcc-real.h"
+#else
+typedef long double real_t;
+#endif
+
+// Modify OutBuffer::writewchar to write the correct size of wchar
+#if _WIN32
+#define writewchar writeword
+#else
+// This needs a configuration test...
+#define writewchar write4
+#endif
+
+#ifdef IN_GCC
+#include "d-gcc-complex_t.h"
+#endif
+
+struct Module;
+
+//typedef unsigned Loc;		// file location
+struct Loc
+{
+    char *filename;
+    unsigned linnum;
+
+    Loc()
+    {
+	linnum = 0;
+	filename = NULL;
+    }
+
+    Loc(int x)
+    {
+	linnum = x;
+	filename = NULL;
+    }
+
+    Loc(Module *mod, unsigned linnum);
+
+    char *toChars();
+};
+
+#ifndef GCC_SAFE_DMD
+#define TRUE	1
+#define FALSE	0
+#endif
+
+#define INTERFACE_OFFSET	0	// if 1, put classinfo as first entry
+					// in interface vtbl[]'s
+#define INTERFACE_VIRTUAL	0	// 1 means if an interface appears
+					// in the inheritance graph multiple
+					// times, only one is used
+
+enum LINK
+{
+    LINKdefault,
+    LINKd,
+    LINKc,
+    LINKcpp,
+    LINKwindows,
+    LINKpascal,
+};
+
+enum DYNCAST
+{
+    DYNCAST_OBJECT,
+    DYNCAST_EXPRESSION,
+    DYNCAST_DSYMBOL,
+    DYNCAST_TYPE,
+    DYNCAST_IDENTIFIER,
+    DYNCAST_TUPLE,
+};
+
+enum MATCH
+{
+    MATCHnomatch,	// no match
+    MATCHconvert,	// match with conversions
+#if V2
+    MATCHconst,		// match with conversion to const
+#endif
+    MATCHexact		// exact match
+};
+
+void error(Loc loc, const char *format, ...);
+void verror(Loc loc, const char *format, va_list);
+void fatal();
+void err_nomem();
+int runLINK();
+void deleteExeFile();
+int runProgram();
+void inifile(char *argv0, char *inifile);
+void halt();
+
+/*** Where to send error messages ***/
+#if IN_GCC
+#define stdmsg stderr
+#else
+#define stdmsg stdout
+#endif
+
+#endif /* DMD_MARS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/mem.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,144 @@
+
+/* Copyright (c) 2000 Digital Mars	*/
+/* All Rights Reserved 			*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gc.h"
+
+#include "mem.h"
+
+/* This implementation of the storage allocator uses the standard C allocation package.
+ */
+
+Mem mem;
+
+void Mem::init()
+{
+    GC_init();
+}
+
+char *Mem::strdup(const char *s)
+{
+    char *p;
+
+    if (s)
+    {
+	p = GC_strdup(s);
+	if (p)
+	    return p;
+	error();
+    }
+    return NULL;
+}
+
+void *Mem::malloc(size_t size)
+{   void *p;
+
+    if (!size)
+	p = NULL;
+    else
+    {
+	p = GC_malloc(size);
+	if (!p)
+	    error();
+    }
+    return p;
+}
+
+void *Mem::calloc(size_t size, size_t n)
+{   void *p;
+
+    if (!size || !n)
+	p = NULL;
+    else
+    {
+	p = GC_malloc(size * n);
+	if (!p)
+	    error();
+        memset(p, 0, size * n);
+    }
+    return p;
+}
+
+void *Mem::realloc(void *p, size_t size)
+{
+    if (!size)
+    {	if (p)
+	{   GC_free(p);
+	    p = NULL;
+	}
+    }
+    else if (!p)
+    {
+	p = GC_malloc(size);
+	if (!p)
+	    error();
+    }
+    else
+    {
+	p = GC_realloc(p, size);
+	if (!p)
+	    error();
+    }
+    return p;
+}
+
+void Mem::free(void *p)
+{
+    if (p)
+	GC_free(p);
+}
+
+void *Mem::mallocdup(void *o, size_t size)
+{   void *p;
+
+    if (!size)
+	p = NULL;
+    else
+    {
+	p = GC_malloc(size);
+	if (!p)
+	    error();
+	else
+	    memcpy(p,o,size);
+    }
+    return p;
+}
+
+void Mem::error()
+{
+    printf("Error: out of memory\n");
+    exit(EXIT_FAILURE);
+}
+
+void Mem::fullcollect()
+{
+    GC_gcollect();
+}
+
+void Mem::mark(void *pointer)
+{
+    (void) pointer;		// necessary for VC /W4
+}
+
+/* =================================================== */
+
+void * operator new(size_t m_size)
+{   
+    void *p = GC_malloc(m_size);
+    if (p)
+	return p;
+    printf("Error: out of memory\n");
+    exit(EXIT_FAILURE);
+    return p;
+}
+
+void operator delete(void *p)
+{
+    GC_free(p);
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/mem.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,51 @@
+// Copyright (C) 2000-2001 by Chromium Communications
+// All Rights Reserved
+
+#ifndef ROOT_MEM_H
+#define ROOT_MEM_H
+
+#include <stddef.h>	// for size_t
+
+typedef void (*FINALIZERPROC)(void* pObj, void* pClientData);
+
+struct GC;			// thread specific allocator
+
+struct Mem
+{
+    GC *gc;			// pointer to our thread specific allocator
+    Mem() { gc = NULL; }
+
+    void init();
+
+    // Derive from Mem to get these storage allocators instead of global new/delete
+    void * operator new(size_t m_size);
+    void * operator new(size_t m_size, Mem *mem);
+    void * operator new(size_t m_size, GC *gc);
+    void operator delete(void *p);
+
+    void * operator new[](size_t m_size);
+    void operator delete[](void *p);
+
+    char *strdup(const char *s);
+    void *malloc(size_t size);
+    void *malloc_uncollectable(size_t size);
+    void *calloc(size_t size, size_t n);
+    void *realloc(void *p, size_t size);
+    void free(void *p);
+    void free_uncollectable(void *p);
+    void *mallocdup(void *o, size_t size);
+    void error();
+    void check(void *p);	// validate pointer
+    void fullcollect();		// do full garbage collection
+    void fullcollectNoStack();	// do full garbage collection, no scan stack
+    void mark(void *pointer);
+    void addroots(char* pStart, char* pEnd);
+    void removeroots(char* pStart);
+    void setFinalizer(void* pObj, FINALIZERPROC pFn, void* pClientData);
+    void setStackBottom(void *bottom);
+    GC *getThreadGC();		// get apartment allocator for this thread
+};
+
+extern Mem mem;
+
+#endif /* ROOT_MEM_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/module.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,981 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#ifdef _MSC_VER
+#include <malloc.h>
+#endif
+
+#if IN_GCC
+#include "gdc_alloca.h"
+#endif
+
+#include "mem.h"
+
+#include "mars.h"
+#include "module.h"
+#include "parse.h"
+#include "scope.h"
+#include "identifier.h"
+#include "id.h"
+#include "import.h"
+#include "dsymbol.h"
+#include "hdrgen.h"
+#include "lexer.h"
+
+#define MARS 1
+#include "html.h"
+
+#ifdef IN_GCC
+#include "d-dmd-gcc.h"
+#endif
+
+ClassDeclaration *Module::moduleinfo;
+
+Module *Module::rootModule;
+DsymbolTable *Module::modules;
+Array Module::amodules;
+
+Array Module::deferred;	// deferred Dsymbol's needing semantic() run on them
+unsigned Module::dprogress;
+
+void Module::init()
+{
+    modules = new DsymbolTable();
+}
+
+Module::Module(char *filename, Identifier *ident, int doDocComment, int doHdrGen)
+	: Package(ident)
+{
+    FileName *srcfilename;
+    FileName *cfilename;
+    FileName *hfilename;
+    FileName *objfilename;
+    FileName *llfilename;
+    FileName *bcfilename;
+    FileName *symfilename;
+
+//    printf("Module::Module(filename = '%s', ident = '%s')\n", filename, ident->toChars());
+    this->arg = filename;
+    md = NULL;
+    errors = 0;
+    numlines = 0;
+    members = NULL;
+    isHtml = 0;
+    isDocFile = 0;
+    needmoduleinfo = 0;
+#ifdef IN_GCC
+    strictlyneedmoduleinfo = 0;
+#endif
+    insearch = 0;
+    searchCacheIdent = NULL;
+    searchCacheSymbol = NULL;
+    searchCacheFlags = 0;
+    semanticstarted = 0;
+    semanticdone = 0;
+    decldefs = NULL;
+    vmoduleinfo = NULL;
+    massert = NULL;
+    marray = NULL;
+    sctor = NULL;
+    sdtor = NULL;
+    stest = NULL;
+    sfilename = NULL;
+    root = 0;
+    importedFrom = NULL;
+    srcfile = NULL;
+    docfile = NULL;
+
+    debuglevel = 0;
+    debugids = NULL;
+    debugidsNot = NULL;
+    versionlevel = 0;
+    versionids = NULL;
+    versionidsNot = NULL;
+
+    macrotable = NULL;
+    escapetable = NULL;
+    cov = NULL;
+    covb = NULL;
+
+    srcfilename = FileName::defaultExt(filename, global.mars_ext);
+    if (!srcfilename->equalsExt(global.mars_ext))
+    {
+	if (srcfilename->equalsExt("html") ||
+	    srcfilename->equalsExt("htm")  ||
+	    srcfilename->equalsExt("xhtml"))
+	    isHtml = 1;
+	else
+	{   error("source file name '%s' must have .%s extension", srcfilename->toChars(), global.mars_ext);
+	    fatal();
+	}
+    }
+
+    char *argobj;
+    if (global.params.objname)
+	argobj = global.params.objname;
+    else if (global.params.preservePaths)
+	argobj = filename;
+    else
+	argobj = FileName::name(filename);
+    if (!FileName::absolute(argobj))
+    {
+	argobj = FileName::combine(global.params.objdir, argobj);
+    }
+
+    if (global.params.objname)
+	objfilename = new FileName(argobj, 0);
+    else
+    objfilename = FileName::forceExt(argobj, global.obj_ext);
+
+    llfilename = FileName::forceExt(argobj, global.ll_ext);
+    bcfilename = FileName::forceExt(argobj, global.bc_ext);
+
+    symfilename = FileName::forceExt(filename, global.sym_ext);
+
+    srcfile = new File(srcfilename);
+
+    if (doDocComment)
+    {
+	setDocfile();
+    }
+
+    if (doHdrGen)
+    {
+	setHdrfile();
+    }
+
+    objfile = new File(objfilename);
+    bcfile = new File(bcfilename);
+    symfile = new File(symfilename);
+}
+
+void Module::setDocfile()
+{
+    FileName *docfilename;
+    char *argdoc;
+
+    if (global.params.docname)
+	argdoc = global.params.docname;
+    else if (global.params.preservePaths)
+	argdoc = (char *)arg;
+    else
+	argdoc = FileName::name((char *)arg);
+    if (!FileName::absolute(argdoc))
+    {	//FileName::ensurePathExists(global.params.docdir);
+	argdoc = FileName::combine(global.params.docdir, argdoc);
+    }
+    if (global.params.docname)
+	docfilename = new FileName(argdoc, 0);
+    else
+	docfilename = FileName::forceExt(argdoc, global.doc_ext);
+
+    if (docfilename->equals(srcfile->name))
+    {   error("Source file and documentation file have same name '%s'", srcfile->name->str);
+	fatal();
+    }
+
+    docfile = new File(docfilename);
+}
+
+void Module::setHdrfile()
+{
+    FileName *hdrfilename;
+    char *arghdr;
+
+    if (global.params.hdrname)
+	arghdr = global.params.hdrname;
+    else if (global.params.preservePaths)
+	arghdr = (char *)arg;
+    else
+	arghdr = FileName::name((char *)arg);
+    if (!FileName::absolute(arghdr))
+    {	//FileName::ensurePathExists(global.params.hdrdir);
+	arghdr = FileName::combine(global.params.hdrdir, arghdr);
+    }
+    if (global.params.hdrname)
+	hdrfilename = new FileName(arghdr, 0);
+    else
+	hdrfilename = FileName::forceExt(arghdr, global.hdr_ext);
+
+    if (hdrfilename->equals(srcfile->name))
+    {   error("Source file and 'header' file have same name '%s'", srcfile->name->str);
+	fatal();
+    }
+
+    hdrfile = new File(hdrfilename);
+}
+
+void Module::deleteObjFile()
+{
+    if (global.params.obj)
+	objfile->remove();
+    //if (global.params.llvmBC)
+    bcfile->remove();
+    if (docfile)
+	docfile->remove();
+}
+
+Module::~Module()
+{
+}
+
+char *Module::kind()
+{
+    return "module";
+}
+
+Module *Module::load(Loc loc, Array *packages, Identifier *ident)
+{   Module *m;
+    char *filename;
+
+    //printf("Module::load(ident = '%s')\n", ident->toChars());
+
+    // Build module filename by turning:
+    //	foo.bar.baz
+    // into:
+    //	foo\bar\baz
+    filename = ident->toChars();
+    if (packages && packages->dim)
+    {
+	OutBuffer buf;
+	int i;
+
+	for (i = 0; i < packages->dim; i++)
+	{   Identifier *pid = (Identifier *)packages->data[i];
+
+	    buf.writestring(pid->toChars());
+#if _WIN32
+	    buf.writeByte('\\');
+#else
+	    buf.writeByte('/');
+#endif
+	}
+	buf.writestring(filename);
+	buf.writeByte(0);
+	filename = (char *)buf.extractData();
+    }
+
+    m = new Module(filename, ident, 0, 0);
+    m->loc = loc;
+
+    /* Search along global.path for .di file, then .d file.
+     */
+    char *result = NULL;
+    FileName *fdi = FileName::forceExt(filename, global.hdr_ext);
+    FileName *fd  = FileName::forceExt(filename, global.mars_ext);
+    char *sdi = fdi->toChars();
+    char *sd  = fd->toChars();
+
+    if (FileName::exists(sdi))
+	result = sdi;
+    else if (FileName::exists(sd))
+	result = sd;
+    else if (FileName::absolute(filename))
+	;
+    else if (!global.path)
+	;
+    else
+    {
+	for (size_t i = 0; i < global.path->dim; i++)
+	{
+	    char *p = (char *)global.path->data[i];
+	    char *n = FileName::combine(p, sdi);
+	    if (FileName::exists(n))
+	    {	result = n;
+		break;
+	    }
+	    mem.free(n);
+	    n = FileName::combine(p, sd);
+	    if (FileName::exists(n))
+	    {	result = n;
+		break;
+	    }
+	    mem.free(n);
+	}
+    }
+    if (result)
+	m->srcfile = new File(result);
+
+    if (global.params.verbose)
+    {
+	printf("import    ");
+	if (packages)
+	{
+	    for (size_t i = 0; i < packages->dim; i++)
+	    {   Identifier *pid = (Identifier *)packages->data[i];
+		printf("%s.", pid->toChars());
+	    }
+	}
+	printf("%s\t(%s)\n", ident->toChars(), m->srcfile->toChars());
+    }
+
+    m->read(loc);
+    m->parse();
+
+#ifdef IN_GCC
+    d_gcc_magic_module(m);
+#endif
+
+    return m;
+}
+
+void Module::read(Loc loc)
+{
+    //printf("Module::read('%s') file '%s'\n", toChars(), srcfile->toChars());
+    if (srcfile->read())
+    {	error(loc, "cannot read file '%s'", srcfile->toChars());
+	fatal();
+    }
+}
+
+inline unsigned readwordLE(unsigned short *p)
+{
+#if __I86__
+    return *p;
+#else
+    return (((unsigned char *)p)[1] << 8) | ((unsigned char *)p)[0];
+#endif
+}
+
+inline unsigned readwordBE(unsigned short *p)
+{
+    return (((unsigned char *)p)[0] << 8) | ((unsigned char *)p)[1];
+}
+
+inline unsigned readlongLE(unsigned *p)
+{
+#if __I86__
+    return *p;
+#else
+    return ((unsigned char *)p)[0] |
+	(((unsigned char *)p)[1] << 8) |
+	(((unsigned char *)p)[2] << 16) |
+	(((unsigned char *)p)[3] << 24);
+#endif
+}
+
+inline unsigned readlongBE(unsigned *p)
+{
+    return ((unsigned char *)p)[3] |
+	(((unsigned char *)p)[2] << 8) |
+	(((unsigned char *)p)[1] << 16) |
+	(((unsigned char *)p)[0] << 24);
+}
+
+#if IN_GCC
+void Module::parse(bool dump_source)
+#else
+void Module::parse()
+#endif
+{   char *srcname;
+    unsigned char *buf;
+    unsigned buflen;
+    unsigned le;
+    unsigned bom;
+
+    //printf("Module::parse()\n");
+
+    srcname = srcfile->name->toChars();
+    //printf("Module::parse(srcname = '%s')\n", srcname);
+
+    buf = srcfile->buffer;
+    buflen = srcfile->len;
+
+    if (buflen >= 2)
+    {
+	/* Convert all non-UTF-8 formats to UTF-8.
+	 * BOM : http://www.unicode.org/faq/utf_bom.html
+	 * 00 00 FE FF	UTF-32BE, big-endian
+	 * FF FE 00 00	UTF-32LE, little-endian
+	 * FE FF	UTF-16BE, big-endian
+	 * FF FE	UTF-16LE, little-endian
+	 * EF BB BF	UTF-8
+	 */
+
+	bom = 1;		// assume there's a BOM
+	if (buf[0] == 0xFF && buf[1] == 0xFE)
+	{
+	    if (buflen >= 4 && buf[2] == 0 && buf[3] == 0)
+	    {	// UTF-32LE
+		le = 1;
+
+	    Lutf32:
+		OutBuffer dbuf;
+		unsigned *pu = (unsigned *)(buf);
+		unsigned *pumax = &pu[buflen / 4];
+
+		if (buflen & 3)
+		{   error("odd length of UTF-32 char source %u", buflen);
+		    fatal();
+		}
+
+		dbuf.reserve(buflen / 4);
+		for (pu += bom; pu < pumax; pu++)
+		{   unsigned u;
+
+		    u = le ? readlongLE(pu) : readlongBE(pu);
+		    if (u & ~0x7F)
+		    {
+			if (u > 0x10FFFF)
+			{   error("UTF-32 value %08x greater than 0x10FFFF", u);
+			    fatal();
+			}
+			dbuf.writeUTF8(u);
+		    }
+		    else
+			dbuf.writeByte(u);
+		}
+		dbuf.writeByte(0);		// add 0 as sentinel for scanner
+		buflen = dbuf.offset - 1;	// don't include sentinel in count
+		buf = (unsigned char *) dbuf.extractData();
+	    }
+	    else
+	    {   // UTF-16LE (X86)
+		// Convert it to UTF-8
+		le = 1;
+
+	    Lutf16:
+		OutBuffer dbuf;
+		unsigned short *pu = (unsigned short *)(buf);
+		unsigned short *pumax = &pu[buflen / 2];
+
+		if (buflen & 1)
+		{   error("odd length of UTF-16 char source %u", buflen);
+		    fatal();
+		}
+
+		dbuf.reserve(buflen / 2);
+		for (pu += bom; pu < pumax; pu++)
+		{   unsigned u;
+
+		    u = le ? readwordLE(pu) : readwordBE(pu);
+		    if (u & ~0x7F)
+		    {	if (u >= 0xD800 && u <= 0xDBFF)
+			{   unsigned u2;
+
+			    if (++pu > pumax)
+			    {   error("surrogate UTF-16 high value %04x at EOF", u);
+				fatal();
+			    }
+			    u2 = le ? readwordLE(pu) : readwordBE(pu);
+			    if (u2 < 0xDC00 || u2 > 0xDFFF)
+			    {   error("surrogate UTF-16 low value %04x out of range", u2);
+				fatal();
+			    }
+			    u = (u - 0xD7C0) << 10;
+			    u |= (u2 - 0xDC00);
+			}
+			else if (u >= 0xDC00 && u <= 0xDFFF)
+			{   error("unpaired surrogate UTF-16 value %04x", u);
+			    fatal();
+			}
+			else if (u == 0xFFFE || u == 0xFFFF)
+			{   error("illegal UTF-16 value %04x", u);
+			    fatal();
+			}
+			dbuf.writeUTF8(u);
+		    }
+		    else
+			dbuf.writeByte(u);
+		}
+		dbuf.writeByte(0);		// add 0 as sentinel for scanner
+		buflen = dbuf.offset - 1;	// don't include sentinel in count
+		buf = (unsigned char *) dbuf.extractData();
+	    }
+	}
+	else if (buf[0] == 0xFE && buf[1] == 0xFF)
+	{   // UTF-16BE
+	    le = 0;
+	    goto Lutf16;
+	}
+	else if (buflen >= 4 && buf[0] == 0 && buf[1] == 0 && buf[2] == 0xFE && buf[3] == 0xFF)
+	{   // UTF-32BE
+	    le = 0;
+	    goto Lutf32;
+	}
+	else if (buflen >= 3 && buf[0] == 0xEF && buf[1] == 0xBB && buf[2] == 0xBF)
+	{   // UTF-8
+
+	    buf += 3;
+	    buflen -= 3;
+	}
+	else
+	{
+	    /* There is no BOM. Make use of Arcane Jill's insight that
+	     * the first char of D source must be ASCII to
+	     * figure out the encoding.
+	     */
+
+	    bom = 0;
+	    if (buflen >= 4)
+	    {   if (buf[1] == 0 && buf[2] == 0 && buf[3] == 0)
+		{   // UTF-32LE
+		    le = 1;
+		    goto Lutf32;
+		}
+		else if (buf[0] == 0 && buf[1] == 0 && buf[2] == 0)
+		{   // UTF-32BE
+		    le = 0;
+		    goto Lutf32;
+		}
+	    }
+	    if (buflen >= 2)
+	    {
+		if (buf[1] == 0)
+		{   // UTF-16LE
+		    le = 1;
+		    goto Lutf16;
+		}
+		else if (buf[0] == 0)
+		{   // UTF-16BE
+		    le = 0;
+		    goto Lutf16;
+		}
+	    }
+
+	    // It's UTF-8
+	    if (buf[0] >= 0x80)
+	    {	error("source file must start with BOM or ASCII character, not \\x%02X", buf[0]);
+		fatal();
+	    }
+	}
+    }
+
+#ifdef IN_GCC
+    // dump utf-8 encoded source
+    if (dump_source)
+    {	// %% srcname could contain a path ...
+	d_gcc_dump_source(srcname, "utf-8", buf, buflen);
+    }
+#endif
+
+    /* If it starts with the string "Ddoc", then it's a documentation
+     * source file.
+     */
+    if (buflen >= 4 && memcmp(buf, "Ddoc", 4) == 0)
+    {
+	comment = buf + 4;
+	isDocFile = 1;
+	if (!docfile)
+	    setDocfile();
+	return;
+    }
+    if (isHtml)
+    {
+	OutBuffer *dbuf = new OutBuffer();
+	Html h(srcname, buf, buflen);
+	h.extractCode(dbuf);
+	buf = dbuf->data;
+	buflen = dbuf->offset;
+#ifdef IN_GCC
+	// dump extracted source
+	if (dump_source)
+	    d_gcc_dump_source(srcname, "d.utf-8", buf, buflen);
+#endif
+    }
+    Parser p(this, buf, buflen, docfile != NULL);
+    p.nextToken();
+    members = p.parseModule();
+    md = p.md;
+    numlines = p.loc.linnum;
+
+    DsymbolTable *dst;
+
+    if (md)
+    {	this->ident = md->id;
+	dst = Package::resolve(md->packages, &this->parent, NULL);
+    }
+    else
+    {
+	dst = modules;
+
+	/* Check to see if module name is a valid identifier
+	 */
+	if (!Lexer::isValidIdentifier(this->ident->toChars()))
+	    error("has non-identifier characters in filename, use module declaration instead");
+    }
+
+    // Update global list of modules
+    if (!dst->insert(this))
+    {
+	if (md)
+	    error(loc, "is in multiple packages %s", md->toChars());
+	else
+	    error(loc, "is in multiple defined");
+    }
+    else
+    {
+	amodules.push(this);
+    }
+}
+
+void Module::semantic()
+{   int i;
+
+    if (semanticstarted)
+	return;
+
+    //printf("+Module::semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent);
+    semanticstarted = 1;
+
+    // Note that modules get their own scope, from scratch.
+    // This is so regardless of where in the syntax a module
+    // gets imported, it is unaffected by context.
+    Scope *sc = Scope::createGlobal(this);	// create root scope
+
+    //printf("Module = %p, linkage = %d\n", sc->scopesym, sc->linkage);
+
+    // Add import of "object" if this module isn't "object"
+    if (ident != Id::object)
+    {
+	Import *im = new Import(0, NULL, Id::object, NULL, 0);
+	members->shift(im);
+    }
+
+    // Add all symbols into module's symbol table
+    symtab = new DsymbolTable();
+    for (i = 0; i < members->dim; i++)
+    {	Dsymbol *s;
+
+	s = (Dsymbol *)members->data[i];
+	s->addMember(NULL, sc->scopesym, 1);
+    }
+
+    // Pass 1 semantic routines: do public side of the definition
+    for (i = 0; i < members->dim; i++)
+    {	Dsymbol *s;
+
+	s = (Dsymbol *)members->data[i];
+	//printf("\tModule('%s'): '%s'.semantic()\n", toChars(), s->toChars());
+	s->semantic(sc);
+	runDeferredSemantic();
+    }
+
+    sc = sc->pop();
+    sc->pop();
+    semanticdone = semanticstarted;
+    //printf("-Module::semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent);
+}
+
+void Module::semantic2()
+{   int i;
+
+    if (deferred.dim)
+    {
+	for (int i = 0; i < deferred.dim; i++)
+	{
+	    Dsymbol *sd = (Dsymbol *)deferred.data[i];
+
+	    sd->error("unable to resolve forward reference in definition");
+	}
+	return;
+    }
+    //printf("Module::semantic2('%s'): parent = %p\n", toChars(), parent);
+    if (semanticstarted >= 2)
+	return;
+    assert(semanticstarted == 1);
+    semanticstarted = 2;
+
+    // Note that modules get their own scope, from scratch.
+    // This is so regardless of where in the syntax a module
+    // gets imported, it is unaffected by context.
+    Scope *sc = Scope::createGlobal(this);	// create root scope
+    //printf("Module = %p\n", sc.scopesym);
+
+    // Pass 2 semantic routines: do initializers and function bodies
+    for (i = 0; i < members->dim; i++)
+    {	Dsymbol *s;
+
+	s = (Dsymbol *)members->data[i];
+	s->semantic2(sc);
+    }
+
+    sc = sc->pop();
+    sc->pop();
+    semanticdone = semanticstarted;
+    //printf("-Module::semantic2('%s'): parent = %p\n", toChars(), parent);
+}
+
+void Module::semantic3()
+{   int i;
+
+    //printf("Module::semantic3('%s'): parent = %p\n", toChars(), parent);
+    if (semanticstarted >= 3)
+	return;
+    assert(semanticstarted == 2);
+    semanticstarted = 3;
+
+    // Note that modules get their own scope, from scratch.
+    // This is so regardless of where in the syntax a module
+    // gets imported, it is unaffected by context.
+    Scope *sc = Scope::createGlobal(this);	// create root scope
+    //printf("Module = %p\n", sc.scopesym);
+
+    // Pass 3 semantic routines: do initializers and function bodies
+    for (i = 0; i < members->dim; i++)
+    {	Dsymbol *s;
+
+	s = (Dsymbol *)members->data[i];
+	//printf("Module %s: %s.semantic3()\n", toChars(), s->toChars());
+	s->semantic3(sc);
+    }
+
+    sc = sc->pop();
+    sc->pop();
+    semanticdone = semanticstarted;
+}
+
+void Module::inlineScan()
+{   int i;
+
+    if (semanticstarted >= 4)
+	return;
+    assert(semanticstarted == 3);
+    semanticstarted = 4;
+
+    // Note that modules get their own scope, from scratch.
+    // This is so regardless of where in the syntax a module
+    // gets imported, it is unaffected by context.
+    //printf("Module = %p\n", sc.scopesym);
+
+    for (i = 0; i < members->dim; i++)
+    {	Dsymbol *s;
+
+	s = (Dsymbol *)members->data[i];
+	//if (global.params.verbose)
+	    //printf("inline scan symbol %s\n", s->toChars());
+
+	s->inlineScan();
+    }
+    semanticdone = semanticstarted;
+}
+
+/****************************************************
+ */
+
+void Module::gensymfile()
+{
+    OutBuffer buf;
+    HdrGenState hgs;
+    int i;
+
+    //printf("Module::gensymfile()\n");
+
+    buf.printf("// Sym file generated from '%s'", srcfile->toChars());
+    buf.writenl();
+
+    for (i = 0; i < members->dim; i++)
+    {
+	Dsymbol *s;
+
+	s = (Dsymbol *)members->data[i];
+	s->toCBuffer(&buf, &hgs);
+    }
+
+    // Transfer image to file
+    symfile->setbuffer(buf.data, buf.offset);
+    buf.data = NULL;
+
+    symfile->writev();
+}
+
+/**********************************
+ * Determine if we need to generate an instance of ModuleInfo
+ * for this Module.
+ */
+
+int Module::needModuleInfo()
+{
+    return needmoduleinfo || global.params.cov;
+}
+
+Dsymbol *Module::search(Loc loc, Identifier *ident, int flags)
+{
+    /* Since modules can be circularly referenced,
+     * need to stop infinite recursive searches.
+     */
+
+    //printf("%s Module::search('%s', flags = %d) insearch = %d\n", toChars(), ident->toChars(), flags, insearch);
+    Dsymbol *s;
+    if (insearch)
+	s = NULL;
+    else if (searchCacheIdent == ident && searchCacheFlags == flags)
+	s = searchCacheSymbol;
+    else
+    {
+	insearch = 1;
+	s = ScopeDsymbol::search(loc, ident, flags);
+	insearch = 0;
+
+	searchCacheIdent = ident;
+	searchCacheSymbol = s;
+	searchCacheFlags = flags;
+    }
+    return s;
+}
+
+/*******************************************
+ * Can't run semantic on s now, try again later.
+ */
+
+void Module::addDeferredSemantic(Dsymbol *s)
+{
+    // Don't add it if it is already there
+    for (int i = 0; i < deferred.dim; i++)
+    {
+	Dsymbol *sd = (Dsymbol *)deferred.data[i];
+
+	if (sd == s)
+	    return;
+    }
+
+    //printf("Module::addDeferredSemantic('%s')\n", s->toChars());
+    deferred.push(s);
+}
+
+
+/******************************************
+ * Run semantic() on deferred symbols.
+ */
+
+void Module::runDeferredSemantic()
+{
+    size_t len;
+
+    static int nested;
+    if (nested)
+	return;
+    //if (deferred.dim) printf("+Module::runDeferredSemantic('%s'), len = %d\n", toChars(), deferred.dim);
+    nested++;
+
+    do
+    {
+	dprogress = 0;
+	len = deferred.dim;
+	if (!len)
+	    break;
+
+	Dsymbol **todo;
+	Dsymbol *tmp;
+	if (len == 1)
+	{
+	    todo = &tmp;
+	}
+	else
+	{
+	    todo = (Dsymbol **)alloca(len * sizeof(Dsymbol *));
+	    assert(todo);
+	}
+	memcpy(todo, deferred.data, len * sizeof(Dsymbol *));
+	deferred.setDim(0);
+
+	for (int i = 0; i < len; i++)
+	{
+	    Dsymbol *s = todo[i];
+
+	    s->semantic(NULL);
+	    //printf("deferred: %s, parent = %s\n", s->toChars(), s->parent->toChars());
+	}
+	//printf("\tdeferred.dim = %d, len = %d, dprogress = %d\n", deferred.dim, len, dprogress);
+    } while (deferred.dim < len || dprogress);	// while making progress
+    nested--;
+    //printf("-Module::runDeferredSemantic('%s'), len = %d\n", toChars(), deferred.dim);
+}
+
+/* =========================== ModuleDeclaration ===================== */
+
+ModuleDeclaration::ModuleDeclaration(Array *packages, Identifier *id)
+{
+    this->packages = packages;
+    this->id = id;
+}
+
+char *ModuleDeclaration::toChars()
+{
+    OutBuffer buf;
+    int i;
+
+    if (packages && packages->dim)
+    {
+	for (i = 0; i < packages->dim; i++)
+	{   Identifier *pid = (Identifier *)packages->data[i];
+
+	    buf.writestring(pid->toChars());
+	    buf.writeByte('.');
+	}
+    }
+    buf.writestring(id->toChars());
+    buf.writeByte(0);
+    return (char *)buf.extractData();
+}
+
+/* =========================== Package ===================== */
+
+Package::Package(Identifier *ident)
+	: ScopeDsymbol(ident)
+{
+}
+
+
+char *Package::kind()
+{
+    return "package";
+}
+
+
+DsymbolTable *Package::resolve(Array *packages, Dsymbol **pparent, Package **ppkg)
+{
+    DsymbolTable *dst = Module::modules;
+    Dsymbol *parent = NULL;
+
+    //printf("Package::resolve()\n");
+    if (ppkg)
+	*ppkg = NULL;
+
+    if (packages)
+    {   int i;
+
+	for (i = 0; i < packages->dim; i++)
+	{   Identifier *pid = (Identifier *)packages->data[i];
+	    Dsymbol *p;
+
+	    p = dst->lookup(pid);
+	    if (!p)
+	    {
+		p = new Package(pid);
+		dst->insert(p);
+		p->parent = parent;
+		((ScopeDsymbol *)p)->symtab = new DsymbolTable();
+	    }
+	    else
+	    {
+		assert(p->isPackage());
+		if (p->isModule())
+		{   p->error("module and package have the same name");
+		    fatal();
+		    break;
+		}
+	    }
+	    parent = p;
+	    dst = ((Package *)p)->symtab;
+	    if (ppkg && !*ppkg)
+		*ppkg = (Package *)p;
+	}
+	if (pparent)
+	{
+	    *pparent = parent;
+	}
+    }
+    return dst;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/module.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,177 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2005 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#ifndef DMD_MODULE_H
+#define DMD_MODULE_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include "root.h"
+#include "dsymbol.h"
+
+struct ModuleInfoDeclaration;
+struct ClassDeclaration;
+struct ModuleDeclaration;
+struct Macro;
+struct Escape;
+struct VarDeclaration;
+
+// Back end
+#if IN_GCC
+union tree_node; typedef union tree_node elem;
+#else
+struct elem;
+#endif
+
+struct Package : ScopeDsymbol
+{
+    Package(Identifier *ident);
+    char *kind();
+
+    static DsymbolTable *resolve(Array *packages, Dsymbol **pparent, Package **ppkg);
+
+    Package *isPackage() { return this; }
+
+    virtual void semantic(Scope *sc) { }
+};
+
+struct Module : Package
+{
+    static Module *rootModule;
+    static DsymbolTable *modules;	// symbol table of all modules
+    static Array amodules;		// array of all modules
+    static Array deferred;	// deferred Dsymbol's needing semantic() run on them
+    static unsigned dprogress;	// progress resolving the deferred list
+    static void init();
+
+    static ClassDeclaration *moduleinfo;
+
+
+    const char *arg;	// original argument name
+    ModuleDeclaration *md; // if !NULL, the contents of the ModuleDeclaration declaration
+    File *srcfile;	// input source file
+    File *objfile;	// output .obj file
+    File *bcfile;  // output .bc file
+    File *hdrfile;	// 'header' file
+    File *symfile;	// output symbol file
+    File *docfile;	// output documentation file
+    unsigned errors;	// if any errors in file
+    unsigned numlines;	// number of lines in source file
+    int isHtml;		// if it is an HTML file
+    int isDocFile;	// if it is a documentation input file, not D source
+    int needmoduleinfo;
+#ifdef IN_GCC
+    int strictlyneedmoduleinfo;
+#endif
+
+    int insearch;
+    Identifier *searchCacheIdent;
+    Dsymbol *searchCacheSymbol;	// cached value of search
+    int searchCacheFlags;	// cached flags
+
+    int semanticstarted;	// has semantic() been started?
+    int semanticdone;		// has semantic() been done?
+    int root;			// != 0 if this is a 'root' module,
+				// i.e. a module that will be taken all the
+				// way to an object file
+    Module *importedFrom;	// module from command line we're imported from,
+				// i.e. a module that will be taken all the
+				// way to an object file
+
+    Array *decldefs;		// top level declarations for this Module
+
+    Array aimports;		// all imported modules
+
+    ModuleInfoDeclaration *vmoduleinfo;
+
+    unsigned debuglevel;	// debug level
+    Array *debugids;		// debug identifiers
+    Array *debugidsNot;		// forward referenced debug identifiers
+
+    unsigned versionlevel;	// version level
+    Array *versionids;		// version identifiers
+    Array *versionidsNot;	// forward referenced version identifiers
+
+    Macro *macrotable;		// document comment macros
+    Escape *escapetable;	// document comment escapes
+
+    Module(char *arg, Identifier *ident, int doDocComment, int doHdrGen);
+    ~Module();
+
+    static Module *load(Loc loc, Array *packages, Identifier *ident);
+
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    char *kind();
+    void setDocfile();	// set docfile member
+    void read(Loc loc);	// read file
+#if IN_GCC
+    void parse(bool dump_source = false);	// syntactic parse
+#else
+    void parse();	// syntactic parse
+#endif
+    void semantic();	// semantic analysis
+    void semantic2();	// pass 2 semantic analysis
+    void semantic3();	// pass 3 semantic analysis
+    void inlineScan();	// scan for functions to inline
+    void setHdrfile();	// set hdrfile member
+#ifdef _DH
+    void genhdrfile();  // generate D import file
+#endif
+    void genobjfile();
+    void gensymfile();
+    void gendocfile();
+    int needModuleInfo();
+    Dsymbol *search(Loc loc, Identifier *ident, int flags);
+    void deleteObjFile();
+    void addDeferredSemantic(Dsymbol *s);
+    void runDeferredSemantic();
+
+    // Back end
+
+    Symbol *cov;		// private uint[] __coverage;
+    unsigned *covb;		// bit array of valid code line numbers
+
+    Symbol *sctor;		// module constructor
+    Symbol *sdtor;		// module destructor
+    Symbol *stest;		// module unit test
+
+    Symbol *sfilename;		// symbol for filename
+
+    Symbol *massert;		// module assert function
+    Symbol *toModuleAssert();	// get module assert function
+
+    Symbol *marray;		// module array bounds function
+    Symbol *toModuleArray();	// get module array bounds function
+
+
+    static Symbol *gencritsec();
+    elem *toEfilename();
+    elem *toEmodulename();
+
+    Symbol *toSymbol();
+    void genmoduleinfo();
+
+    Module *isModule() { return this; }
+};
+
+
+struct ModuleDeclaration
+{
+    Identifier *id;
+    Array *packages;		// array of Identifier's representing packages
+
+    ModuleDeclaration(Array *packages, Identifier *id);
+
+    char *toChars();
+};
+
+#endif /* DMD_MODULE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/mtype.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,5216 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#define __USE_ISOC99 1		// so signbit() gets defined
+#include <math.h>
+
+#include <stdio.h>
+#include <assert.h>
+#include <float.h>
+
+#ifdef __DMC__
+#include <fp.h>
+#endif
+
+#if _MSC_VER
+#include <malloc.h>
+#include <complex>
+#include <limits>
+#elif __DMC__
+#include <complex.h>
+#else
+//#define signbit 56
+#endif
+
+#if __APPLE__
+#include <math.h>
+static double zero = 0;
+#elif __GNUC__
+#include <math.h>
+#include <bits/nan.h>
+#include <bits/mathdef.h>
+static double zero = 0;
+#endif
+
+#include "mem.h"
+
+#include "dsymbol.h"
+#include "mtype.h"
+#include "scope.h"
+#include "init.h"
+#include "expression.h"
+#include "attrib.h"
+#include "declaration.h"
+#include "template.h"
+#include "id.h"
+#include "enum.h"
+#include "import.h"
+#include "aggregate.h"
+#include "hdrgen.h"
+
+FuncDeclaration *hasThis(Scope *sc);
+
+
+#define LOGDOTEXP	0	// log ::dotExp()
+#define LOGDEFAULTINIT	0	// log ::defaultInit()
+
+// Allow implicit conversion of T[] to T*
+#define IMPLICIT_ARRAY_TO_PTR	global.params.useDeprecated
+
+/* These have default values for 32 bit code, they get
+ * adjusted for 64 bit code.
+ */
+
+int PTRSIZE = 4;
+#if IN_LLVM
+int REALSIZE = 8;
+int REALPAD = 0;
+#elif TARGET_LINUX
+int REALSIZE = 12;
+int REALPAD = 2;
+#else
+int REALSIZE = 10;
+int REALPAD = 0;
+#endif
+int Tsize_t = Tuns32;
+int Tptrdiff_t = Tint32;
+
+/***************************** Type *****************************/
+
+ClassDeclaration *Type::typeinfo;
+ClassDeclaration *Type::typeinfoclass;
+ClassDeclaration *Type::typeinfointerface;
+ClassDeclaration *Type::typeinfostruct;
+ClassDeclaration *Type::typeinfotypedef;
+ClassDeclaration *Type::typeinfopointer;
+ClassDeclaration *Type::typeinfoarray;
+ClassDeclaration *Type::typeinfostaticarray;
+ClassDeclaration *Type::typeinfoassociativearray;
+ClassDeclaration *Type::typeinfoenum;
+ClassDeclaration *Type::typeinfofunction;
+ClassDeclaration *Type::typeinfodelegate;
+ClassDeclaration *Type::typeinfotypelist;
+
+Type *Type::tvoidptr;
+Type *Type::basic[TMAX];
+unsigned char Type::mangleChar[TMAX];
+StringTable Type::stringtable;
+
+
+Type::Type(TY ty, Type *next)
+{
+    this->ty = ty;
+    this->next = next;
+    this->deco = NULL;
+    this->pto = NULL;
+    this->rto = NULL;
+    this->arrayof = NULL;
+    this->vtinfo = NULL;
+    this->ctype = NULL;
+    this->llvmType = 0;
+}
+
+Type *Type::syntaxCopy()
+{
+    print();
+    fprintf(stdmsg, "ty = %d\n", ty);
+    assert(0);
+    return this;
+}
+
+int Type::equals(Object *o)
+{   Type *t;
+
+    t = (Type *)o;
+    //printf("Type::equals(%s, %s)\n", toChars(), t->toChars());
+    if (this == o ||
+	(t && deco == t->deco) &&		// deco strings are unique
+	 deco != NULL)				// and semantic() has been run
+    {
+	//printf("deco = '%s', t->deco = '%s'\n", deco, t->deco);
+	return 1;
+    }
+    //if (deco && t && t->deco) printf("deco = '%s', t->deco = '%s'\n", deco, t->deco);
+    return 0;
+}
+
+char Type::needThisPrefix()
+{
+    return 'M';		// name mangling prefix for functions needing 'this'
+}
+
+void Type::init()
+{   int i;
+    int j;
+
+    Lexer::initKeywords();
+
+    mangleChar[Tarray] = 'A';
+    mangleChar[Tsarray] = 'G';
+    mangleChar[Taarray] = 'H';
+    mangleChar[Tpointer] = 'P';
+    mangleChar[Treference] = 'R';
+    mangleChar[Tfunction] = 'F';
+    mangleChar[Tident] = 'I';
+    mangleChar[Tclass] = 'C';
+    mangleChar[Tstruct] = 'S';
+    mangleChar[Tenum] = 'E';
+    mangleChar[Ttypedef] = 'T';
+    mangleChar[Tdelegate] = 'D';
+
+    mangleChar[Tnone] = 'n';
+    mangleChar[Tvoid] = 'v';
+    mangleChar[Tint8] = 'g';
+    mangleChar[Tuns8] = 'h';
+    mangleChar[Tint16] = 's';
+    mangleChar[Tuns16] = 't';
+    mangleChar[Tint32] = 'i';
+    mangleChar[Tuns32] = 'k';
+    mangleChar[Tint64] = 'l';
+    mangleChar[Tuns64] = 'm';
+    mangleChar[Tfloat32] = 'f';
+    mangleChar[Tfloat64] = 'd';
+    mangleChar[Tfloat80] = 'e';
+
+    mangleChar[Timaginary32] = 'o';
+    mangleChar[Timaginary64] = 'p';
+    mangleChar[Timaginary80] = 'j';
+    mangleChar[Tcomplex32] = 'q';
+    mangleChar[Tcomplex64] = 'r';
+    mangleChar[Tcomplex80] = 'c';
+
+    mangleChar[Tbool] = 'b';
+    mangleChar[Tascii] = 'a';
+    mangleChar[Twchar] = 'u';
+    mangleChar[Tdchar] = 'w';
+
+    mangleChar[Tbit] = '@';
+    mangleChar[Tinstance] = '@';
+    mangleChar[Terror] = '@';
+    mangleChar[Ttypeof] = '@';
+    mangleChar[Ttuple] = 'B';
+    mangleChar[Tslice] = '@';
+
+    for (i = 0; i < TMAX; i++)
+    {	if (!mangleChar[i])
+	    fprintf(stdmsg, "ty = %d\n", i);
+	assert(mangleChar[i]);
+    }
+
+    // Set basic types
+    static TY basetab[] =
+	{ Tvoid, Tint8, Tuns8, Tint16, Tuns16, Tint32, Tuns32, Tint64, Tuns64,
+	  Tfloat32, Tfloat64, Tfloat80,
+	  Timaginary32, Timaginary64, Timaginary80,
+	  Tcomplex32, Tcomplex64, Tcomplex80,
+	  Tbit, Tbool,
+	  Tascii, Twchar, Tdchar };
+
+    for (i = 0; i < sizeof(basetab) / sizeof(basetab[0]); i++)
+	basic[basetab[i]] = new TypeBasic(basetab[i]);
+    basic[Terror] = basic[Tint32];
+
+    tvoidptr = tvoid->pointerTo();
+
+    if (global.params.is64bit)
+    {
+	PTRSIZE = 8;
+#if !IN_LLVM
+	if (global.params.isLinux)
+	    REALSIZE = 10;
+	else
+	    REALSIZE = 8;
+#else
+    REALSIZE = 8;
+    REALPAD = 0;
+#endif
+	Tsize_t = Tuns64;
+	Tptrdiff_t = Tint64;
+    }
+    else
+    {
+	PTRSIZE = 4;
+#if IN_LLVM
+    REALSIZE = 8;
+    REALPAD = 0;
+#elif TARGET_LINUX
+	REALSIZE = 12;
+	REALPAD = 2;
+#else
+	REALSIZE = 10;
+	REALPAD = 0;
+#endif
+	Tsize_t = Tuns32;
+	Tptrdiff_t = Tint32;
+    }
+}
+
+d_uns64 Type::size()
+{
+    return size(0);
+}
+
+d_uns64 Type::size(Loc loc)
+{
+    error(loc, "no size for type %s", toChars());
+    return 1;
+}
+
+unsigned Type::alignsize()
+{
+    return size(0);
+}
+
+Type *Type::semantic(Loc loc, Scope *sc)
+{
+    if (next)
+	next = next->semantic(loc,sc);
+    return merge();
+}
+
+Type *Type::pointerTo()
+{
+    if (!pto)
+    {	Type *t;
+
+	t = new TypePointer(this);
+	pto = t->merge();
+    }
+    return pto;
+}
+
+Type *Type::referenceTo()
+{
+    if (!rto)
+    {	Type *t;
+
+	t = new TypeReference(this);
+	rto = t->merge();
+    }
+    return rto;
+}
+
+Type *Type::arrayOf()
+{
+    if (!arrayof)
+    {	Type *t;
+
+	t = new TypeDArray(this);
+	arrayof = t->merge();
+    }
+    return arrayof;
+}
+
+Dsymbol *Type::toDsymbol(Scope *sc)
+{
+    return NULL;
+}
+
+/*******************************
+ * If this is a shell around another type,
+ * get that other type.
+ */
+
+Type *Type::toBasetype()
+{
+    return this;
+}
+
+/********************************
+ * Name mangling.
+ */
+
+void Type::toDecoBuffer(OutBuffer *buf)
+{
+    buf->writeByte(mangleChar[ty]);
+    if (next)
+    {
+	assert(next != this);
+	//printf("this = %p, ty = %d, next = %p, ty = %d\n", this, this->ty, next, next->ty);
+	next->toDecoBuffer(buf);
+    }
+}
+
+/********************************
+ * Name mangling.
+ */
+
+void Type::toTypeInfoBuffer(OutBuffer *buf)
+{
+    assert(0);
+    buf->writeByte(mangleChar[ty]);
+}
+
+/********************************
+ * For pretty-printing a type.
+ */
+
+char *Type::toChars()
+{   OutBuffer *buf;
+    HdrGenState hgs;
+
+    buf = new OutBuffer();
+    toCBuffer2(buf, NULL, &hgs);
+    return buf->toChars();
+}
+
+void Type::toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs)
+{
+    OutBuffer tbuf;
+
+    toCBuffer2(&tbuf, ident, hgs);
+    buf->write(&tbuf);
+}
+
+void Type::toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs)
+{
+    buf->prependstring(toChars());
+    if (ident)
+    {	buf->writeByte(' ');
+	buf->writestring(ident->toChars());
+    }
+}
+
+/************************************
+ */
+
+Type *Type::merge()
+{   Type *t;
+
+    //printf("merge(%s)\n", toChars());
+    t = this;
+    assert(t);
+    if (!deco)
+    {
+	OutBuffer buf;
+	StringValue *sv;
+
+	if (next)
+	    next = next->merge();
+	toDecoBuffer(&buf);
+	sv = stringtable.update((char *)buf.data, buf.offset);
+	if (sv->ptrvalue)
+	{   t = (Type *) sv->ptrvalue;
+	    assert(t->deco);
+	    //printf("old value, deco = '%s' %p\n", t->deco, t->deco);
+	}
+	else
+	{
+	    sv->ptrvalue = this;
+	    deco = sv->lstring.string;
+	    //printf("new value, deco = '%s' %p\n", t->deco, t->deco);
+	}
+    }
+    return t;
+}
+
+int Type::isbit()
+{
+    return FALSE;
+}
+
+int Type::isintegral()
+{
+    return FALSE;
+}
+
+int Type::isfloating()
+{
+    return FALSE;
+}
+
+int Type::isreal()
+{
+    return FALSE;
+}
+
+int Type::isimaginary()
+{
+    return FALSE;
+}
+
+int Type::iscomplex()
+{
+    return FALSE;
+}
+
+int Type::isscalar()
+{
+    return FALSE;
+}
+
+int Type::isunsigned()
+{
+    return FALSE;
+}
+
+ClassDeclaration *Type::isClassHandle()
+{
+    return NULL;
+}
+
+int Type::isauto()
+{
+    return FALSE;
+}
+
+int Type::isString()
+{
+    return FALSE;
+}
+
+int Type::checkBoolean()
+{
+    return isscalar();
+}
+
+/*********************************
+ * Check type to see if it is based on a deprecated symbol.
+ */
+
+void Type::checkDeprecated(Loc loc, Scope *sc)
+{
+    Type *t;
+    Dsymbol *s;
+
+    for (t = this; t; t = t->next)
+    {
+	s = t->toDsymbol(sc);
+	if (s)
+	    s->checkDeprecated(loc, sc);
+    }
+}
+
+
+Expression *Type::defaultInit()
+{
+#if LOGDEFAULTINIT
+    printf("Type::defaultInit() '%s'\n", toChars());
+#endif
+    return NULL;
+}
+
+int Type::isZeroInit()
+{
+    return 0;		// assume not
+}
+
+int Type::isBaseOf(Type *t, int *poffset)
+{
+    return 0;		// assume not
+}
+
+/********************************
+ * Determine if 'this' can be implicitly converted
+ * to type 'to'.
+ * Returns:
+ *	0	can't convert
+ *	1	can convert using implicit conversions
+ *	2	this and to are the same type
+ */
+
+MATCH Type::implicitConvTo(Type *to)
+{
+    //printf("Type::implicitConvTo(this=%p, to=%p)\n", this, to);
+    //printf("\tthis->next=%p, to->next=%p\n", this->next, to->next);
+    if (this == to)
+	return MATCHexact;
+//    if (to->ty == Tvoid)
+//	return 1;
+    return MATCHnomatch;
+}
+
+Expression *Type::getProperty(Loc loc, Identifier *ident)
+{   Expression *e;
+
+#if LOGDOTEXP
+    printf("Type::getProperty(type = '%s', ident = '%s')\n", toChars(), ident->toChars());
+#endif
+    if (ident == Id::__sizeof)
+    {
+	e = new IntegerExp(loc, size(loc), Type::tsize_t);
+    }
+    else if (ident == Id::size)
+    {
+	error(loc, ".size property should be replaced with .sizeof");
+	e = new IntegerExp(loc, size(loc), Type::tsize_t);
+    }
+    else if (ident == Id::alignof)
+    {
+	e = new IntegerExp(loc, alignsize(), Type::tsize_t);
+    }
+    else if (ident == Id::typeinfo)
+    {
+	if (!global.params.useDeprecated)
+	    error(loc, ".typeinfo deprecated, use typeid(type)");
+	e = getTypeInfo(NULL);
+    }
+    else if (ident == Id::init)
+    {
+	e = defaultInit();
+	e->loc = loc;
+    }
+    else if (ident == Id::mangleof)
+    {
+	assert(deco);
+	e = new StringExp(loc, deco, strlen(deco), 'c');
+	Scope sc;
+	e = e->semantic(&sc);
+    }
+    else if (ident == Id::stringof)
+    {	char *s = toChars();
+	e = new StringExp(loc, s, strlen(s), 'c');
+	Scope sc;
+	e = e->semantic(&sc);
+    }
+    else
+    {
+	error(loc, "no property '%s' for type '%s'", ident->toChars(), toChars());
+	e = new IntegerExp(loc, 1, Type::tint32);
+    }
+    return e;
+}
+
+Expression *Type::dotExp(Scope *sc, Expression *e, Identifier *ident)
+{   VarDeclaration *v = NULL;
+
+#if LOGDOTEXP
+    printf("Type::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
+#endif
+    if (e->op == TOKdotvar)
+    {
+	DotVarExp *dv = (DotVarExp *)e;
+	v = dv->var->isVarDeclaration();
+    }
+    else if (e->op == TOKvar)
+    {
+	VarExp *ve = (VarExp *)e;
+	v = ve->var->isVarDeclaration();
+    }
+    if (v)
+    {
+	if (ident == Id::offset)
+	{
+	    if (!global.params.useDeprecated)
+		error(e->loc, ".offset deprecated, use .offsetof");
+	    goto Loffset;
+	}
+	else if (ident == Id::offsetof)
+	{
+	  Loffset:
+	    if (v->storage_class & STCfield)
+	    {
+		e = new IntegerExp(e->loc, v->offset, Type::tsize_t);
+		return e;
+	    }
+	}
+	else if (ident == Id::init)
+	{
+#if 0
+	    if (v->init)
+	    {
+		if (v->init->isVoidInitializer())
+		    error(e->loc, "%s.init is void", v->toChars());
+		else
+		{   Loc loc = e->loc;
+		    e = v->init->toExpression();
+		    if (e->op == TOKassign || e->op == TOKconstruct)
+		    {
+			e = ((AssignExp *)e)->e2;
+
+			/* Take care of case where we used a 0
+			 * to initialize the struct.
+			 */
+			if (e->type == Type::tint32 &&
+			    e->isBool(0) &&
+			    v->type->toBasetype()->ty == Tstruct)
+			{
+			    e = v->type->defaultInit();
+			}
+		    }
+		    e = e->optimize(WANTvalue | WANTinterpret);
+//		    if (!e->isConst())
+//			error(loc, ".init cannot be evaluated at compile time");
+		}
+		return e;
+	    }
+#endif
+	    return defaultInit();
+	}
+    }
+    if (ident == Id::typeinfo)
+    {
+	if (!global.params.useDeprecated)
+	    error(e->loc, ".typeinfo deprecated, use typeid(type)");
+	e = getTypeInfo(sc);
+	return e;
+    }
+    if (ident == Id::stringof)
+    {	char *s = e->toChars();
+	e = new StringExp(e->loc, s, strlen(s), 'c');
+	Scope sc;
+	e = e->semantic(&sc);
+	return e;
+    }
+    return getProperty(e->loc, ident);
+}
+
+unsigned Type::memalign(unsigned salign)
+{
+    return salign;
+}
+
+void Type::error(Loc loc, const char *format, ...)
+{
+    va_list ap;
+    va_start(ap, format);
+    ::verror(loc, format, ap);
+    va_end( ap );
+}
+
+Identifier *Type::getTypeInfoIdent(int internal)
+{
+    // _init_10TypeInfo_%s
+    OutBuffer buf;
+    Identifier *id;
+    char *name;
+    int len;
+
+    //toTypeInfoBuffer(&buf);
+    if (internal)
+    {	buf.writeByte(mangleChar[ty]);
+	if (ty == Tarray)
+	    buf.writeByte(mangleChar[next->ty]);
+    }
+    else
+	toDecoBuffer(&buf);
+    len = buf.offset;
+    name = (char *)alloca(19 + sizeof(len) * 3 + len + 1);
+    buf.writeByte(0);
+    sprintf(name, "_D%dTypeInfo_%s6__initZ", 9 + len, buf.data);
+    if (global.params.isWindows)
+	name++;			// C mangling will add it back in
+    //printf("name = %s\n", name);
+    id = Lexer::idPool(name);
+    return id;
+}
+
+TypeBasic *Type::isTypeBasic()
+{
+    return NULL;
+}
+
+
+void Type::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps)
+{
+    Type *t;
+
+    t = semantic(loc, sc);
+    *pt = t;
+    *pe = NULL;
+    *ps = NULL;
+}
+
+/*******************************
+ * If one of the subtypes of this type is a TypeIdentifier,
+ * i.e. it's an unresolved type, return that type.
+ */
+
+Type *Type::reliesOnTident()
+{
+    if (!next)
+	return NULL;
+    else
+	return next->reliesOnTident();
+}
+
+/********************************
+ * We've mistakenly parsed this as a type.
+ * Redo it as an Expression.
+ * NULL if cannot.
+ */
+
+Expression *Type::toExpression()
+{
+    return NULL;
+}
+
+/***************************************
+ * Return !=0 if type has pointers that need to
+ * be scanned by the GC during a collection cycle.
+ */
+
+int Type::hasPointers()
+{
+    return FALSE;
+}
+
+/* ============================= TypeBasic =========================== */
+
+TypeBasic::TypeBasic(TY ty)
+	: Type(ty, NULL)
+{   char *c;
+    char *d;
+    unsigned flags;
+
+#define TFLAGSintegral	1
+#define TFLAGSfloating	2
+#define TFLAGSunsigned	4
+#define TFLAGSreal	8
+#define TFLAGSimaginary	0x10
+#define TFLAGScomplex	0x20
+
+    flags = 0;
+    switch (ty)
+    {
+	case Tvoid:	d = Token::toChars(TOKvoid);
+			c = "void";
+			break;
+
+	case Tint8:	d = Token::toChars(TOKint8);
+			c = "byte";
+			flags |= TFLAGSintegral;
+			break;
+
+	case Tuns8:	d = Token::toChars(TOKuns8);
+			c = "ubyte";
+			flags |= TFLAGSintegral | TFLAGSunsigned;
+			break;
+
+	case Tint16:	d = Token::toChars(TOKint16);
+			c = "short";
+			flags |= TFLAGSintegral;
+			break;
+
+	case Tuns16:	d = Token::toChars(TOKuns16);
+			c = "ushort";
+			flags |= TFLAGSintegral | TFLAGSunsigned;
+			break;
+
+	case Tint32:	d = Token::toChars(TOKint32);
+			c = "int";
+			flags |= TFLAGSintegral;
+			break;
+
+	case Tuns32:	d = Token::toChars(TOKuns32);
+			c = "uint";
+			flags |= TFLAGSintegral | TFLAGSunsigned;
+			break;
+
+	case Tfloat32:	d = Token::toChars(TOKfloat32);
+			c = "float";
+			flags |= TFLAGSfloating | TFLAGSreal;
+			break;
+
+	case Tint64:	d = Token::toChars(TOKint64);
+			c = "long";
+			flags |= TFLAGSintegral;
+			break;
+
+	case Tuns64:	d = Token::toChars(TOKuns64);
+			c = "ulong";
+			flags |= TFLAGSintegral | TFLAGSunsigned;
+			break;
+
+	case Tfloat64:	d = Token::toChars(TOKfloat64);
+			c = "double";
+			flags |= TFLAGSfloating | TFLAGSreal;
+			break;
+
+	case Tfloat80:	d = Token::toChars(TOKfloat80);
+			c = "real";
+			flags |= TFLAGSfloating | TFLAGSreal;
+			break;
+
+	case Timaginary32: d = Token::toChars(TOKimaginary32);
+			c = "ifloat";
+			flags |= TFLAGSfloating | TFLAGSimaginary;
+			break;
+
+	case Timaginary64: d = Token::toChars(TOKimaginary64);
+			c = "idouble";
+			flags |= TFLAGSfloating | TFLAGSimaginary;
+			break;
+
+	case Timaginary80: d = Token::toChars(TOKimaginary80);
+			c = "ireal";
+			flags |= TFLAGSfloating | TFLAGSimaginary;
+			break;
+
+	case Tcomplex32: d = Token::toChars(TOKcomplex32);
+			c = "cfloat";
+			flags |= TFLAGSfloating | TFLAGScomplex;
+			break;
+
+	case Tcomplex64: d = Token::toChars(TOKcomplex64);
+			c = "cdouble";
+			flags |= TFLAGSfloating | TFLAGScomplex;
+			break;
+
+	case Tcomplex80: d = Token::toChars(TOKcomplex80);
+			c = "creal";
+			flags |= TFLAGSfloating | TFLAGScomplex;
+			break;
+
+
+	case Tbit:	d = Token::toChars(TOKbit);
+			c = "bit";
+			flags |= TFLAGSintegral | TFLAGSunsigned;
+			break;
+
+	case Tbool:	d = "bool";
+			c = d;
+			flags |= TFLAGSintegral | TFLAGSunsigned;
+			break;
+
+	case Tascii:	d = Token::toChars(TOKchar);
+			c = "char";
+			flags |= TFLAGSintegral | TFLAGSunsigned;
+			break;
+
+	case Twchar:	d = Token::toChars(TOKwchar);
+			c = "wchar";
+			flags |= TFLAGSintegral | TFLAGSunsigned;
+			break;
+
+	case Tdchar:	d = Token::toChars(TOKdchar);
+			c = "dchar";
+			flags |= TFLAGSintegral | TFLAGSunsigned;
+			break;
+
+	default:	assert(0);
+    }
+    this->dstring = d;
+    this->cstring = c;
+    this->flags = flags;
+    merge();
+}
+
+Type *TypeBasic::syntaxCopy()
+{
+    // No semantic analysis done on basic types, no need to copy
+    return this;
+}
+
+
+char *TypeBasic::toChars()
+{
+    return dstring;
+}
+
+void TypeBasic::toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs)
+{
+    buf->prependstring(cstring);
+    if (ident)
+    {	buf->writeByte(' ');
+	buf->writestring(ident->toChars());
+    }
+}
+
+d_uns64 TypeBasic::size(Loc loc)
+{   unsigned size;
+
+    //printf("TypeBasic::size()\n");
+    switch (ty)
+    {
+	case Tint8:
+	case Tuns8:	size = 1;	break;
+	case Tint16:
+	case Tuns16:	size = 2;	break;
+	case Tint32:
+	case Tuns32:
+	case Tfloat32:
+	case Timaginary32:
+			size = 4;	break;
+	case Tint64:
+	case Tuns64:
+	case Tfloat64:
+	case Timaginary64:
+			size = 8;	break;
+	case Tfloat80:
+	case Timaginary80:
+			size = REALSIZE;	break;
+	case Tcomplex32:
+			size = 8;		break;
+	case Tcomplex64:
+			size = 16;		break;
+	case Tcomplex80:
+			size = REALSIZE * 2;	break;
+
+	case Tvoid:
+	    //size = Type::size();	// error message
+	    size = 1;
+	    break;
+
+	case Tbit:	size = 1;		break;
+	case Tbool:	size = 1;		break;
+	case Tascii:	size = 1;		break;
+	case Twchar:	size = 2;		break;
+	case Tdchar:	size = 4;		break;
+
+	default:
+	    assert(0);
+	    break;
+    }
+    //printf("TypeBasic::size() = %d\n", size);
+    return size;
+}
+
+unsigned TypeBasic::alignsize()
+{   unsigned sz;
+
+    switch (ty)
+    {
+	case Tfloat80:
+	case Timaginary80:
+	case Tcomplex80:
+	    sz = REALSIZE;
+	    break;
+
+	default:
+	    sz = size(0);
+	    break;
+    }
+    return sz;
+}
+
+
+Expression *TypeBasic::getProperty(Loc loc, Identifier *ident)
+{
+    Expression *e;
+    d_int64 ivalue;
+#ifdef IN_GCC
+    real_t    fvalue;
+#else
+    d_float80 fvalue;
+#endif
+
+    //printf("TypeBasic::getProperty('%s')\n", ident->toChars());
+    if (ident == Id::max)
+    {
+	switch (ty)
+	{
+	    case Tint8:		ivalue = 0x7F;		goto Livalue;
+	    case Tuns8:		ivalue = 0xFF;		goto Livalue;
+	    case Tint16:	ivalue = 0x7FFFUL;	goto Livalue;
+	    case Tuns16:	ivalue = 0xFFFFUL;	goto Livalue;
+	    case Tint32:	ivalue = 0x7FFFFFFFUL;	goto Livalue;
+	    case Tuns32:	ivalue = 0xFFFFFFFFUL;	goto Livalue;
+	    case Tint64:	ivalue = 0x7FFFFFFFFFFFFFFFLL;	goto Livalue;
+	    case Tuns64:	ivalue = 0xFFFFFFFFFFFFFFFFULL;	goto Livalue;
+	    case Tbit:		ivalue = 1;		goto Livalue;
+	    case Tbool:		ivalue = 1;		goto Livalue;
+	    case Tchar:		ivalue = 0xFF;		goto Livalue;
+	    case Twchar:	ivalue = 0xFFFFUL;	goto Livalue;
+	    case Tdchar:	ivalue = 0x10FFFFUL;	goto Livalue;
+
+	    case Tcomplex32:
+	    case Timaginary32:
+	    case Tfloat32:	fvalue = FLT_MAX;	goto Lfvalue;
+	    case Tcomplex64:
+	    case Timaginary64:
+	    case Tfloat64:	fvalue = DBL_MAX;	goto Lfvalue;
+	    case Tcomplex80:
+	    case Timaginary80:
+	    case Tfloat80:	fvalue = LDBL_MAX;	goto Lfvalue;
+	}
+    }
+    else if (ident == Id::min)
+    {
+	switch (ty)
+	{
+	    case Tint8:		ivalue = -128;		goto Livalue;
+	    case Tuns8:		ivalue = 0;		goto Livalue;
+	    case Tint16:	ivalue = -32768;	goto Livalue;
+	    case Tuns16:	ivalue = 0;		goto Livalue;
+	    case Tint32:	ivalue = -2147483647L - 1;	goto Livalue;
+	    case Tuns32:	ivalue = 0;			goto Livalue;
+	    case Tint64:	ivalue = (-9223372036854775807LL-1LL);	goto Livalue;
+	    case Tuns64:	ivalue = 0;		goto Livalue;
+	    case Tbit:		ivalue = 0;		goto Livalue;
+	    case Tbool:		ivalue = 0;		goto Livalue;
+	    case Tchar:		ivalue = 0;		goto Livalue;
+	    case Twchar:	ivalue = 0;		goto Livalue;
+	    case Tdchar:	ivalue = 0;		goto Livalue;
+
+	    case Tcomplex32:
+	    case Timaginary32:
+	    case Tfloat32:	fvalue = FLT_MIN;	goto Lfvalue;
+	    case Tcomplex64:
+	    case Timaginary64:
+	    case Tfloat64:	fvalue = DBL_MIN;	goto Lfvalue;
+	    case Tcomplex80:
+	    case Timaginary80:
+	    case Tfloat80:	fvalue = LDBL_MIN;	goto Lfvalue;
+	}
+    }
+    else if (ident == Id::nan)
+    {
+	switch (ty)
+	{
+	    case Tcomplex32:
+	    case Tcomplex64:
+	    case Tcomplex80:
+	    case Timaginary32:
+	    case Timaginary64:
+	    case Timaginary80:
+	    case Tfloat32:
+	    case Tfloat64:
+	    case Tfloat80:
+	    {
+#if IN_GCC
+		// mode doesn't matter, will be converted in RealExp anyway
+		fvalue = real_t::getnan(real_t::LongDouble);
+#elif __GNUC__
+		// gcc nan's have the sign bit set by default, so turn it off
+		// Need the volatile to prevent gcc from doing incorrect
+		// constant folding.
+		volatile d_float80 foo;
+		foo = NAN;
+		if (signbit(foo))	// signbit sometimes, not always, set
+		    foo = -foo;		// turn off sign bit
+		fvalue = foo;
+#elif _MSC_VER
+		unsigned long nan[2]= { 0xFFFFFFFF, 0x7FFFFFFF };
+		fvalue = *(double*)nan;
+#else
+		fvalue = NAN;
+#endif
+		goto Lfvalue;
+	    }
+	}
+    }
+    else if (ident == Id::infinity)
+    {
+	switch (ty)
+	{
+	    case Tcomplex32:
+	    case Tcomplex64:
+	    case Tcomplex80:
+	    case Timaginary32:
+	    case Timaginary64:
+	    case Timaginary80:
+	    case Tfloat32:
+	    case Tfloat64:
+	    case Tfloat80:
+#if IN_GCC
+		fvalue = real_t::getinfinity();
+#elif __GNUC__
+		fvalue = 1 / zero;
+#elif _MSC_VER
+		fvalue = std::numeric_limits<long double>::infinity();
+#else
+		fvalue = INFINITY;
+#endif
+		goto Lfvalue;
+	}
+    }
+    else if (ident == Id::dig)
+    {
+	switch (ty)
+	{
+	    case Tcomplex32:
+	    case Timaginary32:
+	    case Tfloat32:	ivalue = FLT_DIG;	goto Lint;
+	    case Tcomplex64:
+	    case Timaginary64:
+	    case Tfloat64:	ivalue = DBL_DIG;	goto Lint;
+	    case Tcomplex80:
+	    case Timaginary80:
+	    case Tfloat80:	ivalue = LDBL_DIG;	goto Lint;
+	}
+    }
+    else if (ident == Id::epsilon)
+    {
+	switch (ty)
+	{
+	    case Tcomplex32:
+	    case Timaginary32:
+	    case Tfloat32:	fvalue = FLT_EPSILON;	goto Lfvalue;
+	    case Tcomplex64:
+	    case Timaginary64:
+	    case Tfloat64:	fvalue = DBL_EPSILON;	goto Lfvalue;
+	    case Tcomplex80:
+	    case Timaginary80:
+	    case Tfloat80:	fvalue = LDBL_EPSILON;	goto Lfvalue;
+	}
+    }
+    else if (ident == Id::mant_dig)
+    {
+	switch (ty)
+	{
+	    case Tcomplex32:
+	    case Timaginary32:
+	    case Tfloat32:	ivalue = FLT_MANT_DIG;	goto Lint;
+	    case Tcomplex64:
+	    case Timaginary64:
+	    case Tfloat64:	ivalue = DBL_MANT_DIG;	goto Lint;
+	    case Tcomplex80:
+	    case Timaginary80:
+	    case Tfloat80:	ivalue = LDBL_MANT_DIG; goto Lint;
+	}
+    }
+    else if (ident == Id::max_10_exp)
+    {
+	switch (ty)
+	{
+	    case Tcomplex32:
+	    case Timaginary32:
+	    case Tfloat32:	ivalue = FLT_MAX_10_EXP;	goto Lint;
+	    case Tcomplex64:
+	    case Timaginary64:
+	    case Tfloat64:	ivalue = DBL_MAX_10_EXP;	goto Lint;
+	    case Tcomplex80:
+	    case Timaginary80:
+	    case Tfloat80:	ivalue = LDBL_MAX_10_EXP;	goto Lint;
+	}
+    }
+    else if (ident == Id::max_exp)
+    {
+	switch (ty)
+	{
+	    case Tcomplex32:
+	    case Timaginary32:
+	    case Tfloat32:	ivalue = FLT_MAX_EXP;	goto Lint;
+	    case Tcomplex64:
+	    case Timaginary64:
+	    case Tfloat64:	ivalue = DBL_MAX_EXP;	goto Lint;
+	    case Tcomplex80:
+	    case Timaginary80:
+	    case Tfloat80:	ivalue = LDBL_MAX_EXP;	goto Lint;
+	}
+    }
+    else if (ident == Id::min_10_exp)
+    {
+	switch (ty)
+	{
+	    case Tcomplex32:
+	    case Timaginary32:
+	    case Tfloat32:	ivalue = FLT_MIN_10_EXP;	goto Lint;
+	    case Tcomplex64:
+	    case Timaginary64:
+	    case Tfloat64:	ivalue = DBL_MIN_10_EXP;	goto Lint;
+	    case Tcomplex80:
+	    case Timaginary80:
+	    case Tfloat80:	ivalue = LDBL_MIN_10_EXP;	goto Lint;
+	}
+    }
+    else if (ident == Id::min_exp)
+    {
+	switch (ty)
+	{
+	    case Tcomplex32:
+	    case Timaginary32:
+	    case Tfloat32:	ivalue = FLT_MIN_EXP;	goto Lint;
+	    case Tcomplex64:
+	    case Timaginary64:
+	    case Tfloat64:	ivalue = DBL_MIN_EXP;	goto Lint;
+	    case Tcomplex80:
+	    case Timaginary80:
+	    case Tfloat80:	ivalue = LDBL_MIN_EXP;	goto Lint;
+	}
+    }
+
+Ldefault:
+    return Type::getProperty(loc, ident);
+
+Livalue:
+    e = new IntegerExp(loc, ivalue, this);
+    return e;
+
+Lfvalue:
+    if (isreal() || isimaginary())
+	e = new RealExp(loc, fvalue, this);
+    else
+    {
+	complex_t cvalue;
+
+#if __DMC__
+	//((real_t *)&cvalue)[0] = fvalue;
+	//((real_t *)&cvalue)[1] = fvalue;
+	cvalue = fvalue + fvalue * I;
+#else
+	cvalue.re = fvalue;
+	cvalue.im = fvalue;
+#endif
+	//for (int i = 0; i < 20; i++)
+	//    printf("%02x ", ((unsigned char *)&cvalue)[i]);
+	//printf("\n");
+	e = new ComplexExp(loc, cvalue, this);
+    }
+    return e;
+
+Lint:
+    e = new IntegerExp(loc, ivalue, Type::tint32);
+    return e;
+}
+
+Expression *TypeBasic::dotExp(Scope *sc, Expression *e, Identifier *ident)
+{
+#if LOGDOTEXP
+    printf("TypeBasic::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
+#endif
+    Type *t;
+
+    if (ident == Id::re)
+    {
+	switch (ty)
+	{
+	    case Tcomplex32:	t = tfloat32;		goto L1;
+	    case Tcomplex64:	t = tfloat64;		goto L1;
+	    case Tcomplex80:	t = tfloat80;		goto L1;
+	    L1:
+		e = e->castTo(sc, t);
+		break;
+
+	    case Tfloat32:
+	    case Tfloat64:
+	    case Tfloat80:
+		break;
+
+	    case Timaginary32:	t = tfloat32;		goto L2;
+	    case Timaginary64:	t = tfloat64;		goto L2;
+	    case Timaginary80:	t = tfloat80;		goto L2;
+	    L2:
+		e = new RealExp(0, 0.0, t);
+		break;
+
+	    default:
+		return Type::getProperty(e->loc, ident);
+	}
+    }
+    else if (ident == Id::im)
+    {	Type *t2;
+
+	switch (ty)
+	{
+	    case Tcomplex32:	t = timaginary32;	t2 = tfloat32;	goto L3;
+	    case Tcomplex64:	t = timaginary64;	t2 = tfloat64;	goto L3;
+	    case Tcomplex80:	t = timaginary80;	t2 = tfloat80;	goto L3;
+	    L3:
+		e = e->castTo(sc, t);
+		e->type = t2;
+		break;
+
+	    case Timaginary32:	t = tfloat32;	goto L4;
+	    case Timaginary64:	t = tfloat64;	goto L4;
+	    case Timaginary80:	t = tfloat80;	goto L4;
+	    L4:
+		e->type = t;
+		break;
+
+	    case Tfloat32:
+	    case Tfloat64:
+	    case Tfloat80:
+		e = new RealExp(0, 0.0, this);
+		break;
+
+	    default:
+		return Type::getProperty(e->loc, ident);
+	}
+    }
+    else
+    {
+	return Type::dotExp(sc, e, ident);
+    }
+    return e;
+}
+
+Expression *TypeBasic::defaultInit()
+{   integer_t value = 0;
+
+#if LOGDEFAULTINIT
+    printf("TypeBasic::defaultInit() '%s'\n", toChars());
+#endif
+    switch (ty)
+    {
+	case Tchar:
+	    value = 0xFF;
+	    break;
+
+	case Twchar:
+	case Tdchar:
+	    value = 0xFFFF;
+	    break;
+
+	case Timaginary32:
+	case Timaginary64:
+	case Timaginary80:
+	case Tfloat32:
+	case Tfloat64:
+	case Tfloat80:
+	case Tcomplex32:
+	case Tcomplex64:
+	case Tcomplex80:
+	    return getProperty(0, Id::nan);
+    }
+    return new IntegerExp(0, value, this);
+}
+
+int TypeBasic::isZeroInit()
+{
+    switch (ty)
+    {
+	case Tchar:
+	case Twchar:
+	case Tdchar:
+	case Timaginary32:
+	case Timaginary64:
+	case Timaginary80:
+	case Tfloat32:
+	case Tfloat64:
+	case Tfloat80:
+	case Tcomplex32:
+	case Tcomplex64:
+	case Tcomplex80:
+	    return 0;		// no
+    }
+    return 1;			// yes
+}
+
+int TypeBasic::isbit()
+{
+    return (ty == Tbit);
+}
+
+int TypeBasic::isintegral()
+{
+    //printf("TypeBasic::isintegral('%s') x%x\n", toChars(), flags);
+    return flags & TFLAGSintegral;
+}
+
+int TypeBasic::isfloating()
+{
+    return flags & TFLAGSfloating;
+}
+
+int TypeBasic::isreal()
+{
+    return flags & TFLAGSreal;
+}
+
+int TypeBasic::isimaginary()
+{
+    return flags & TFLAGSimaginary;
+}
+
+int TypeBasic::iscomplex()
+{
+    return flags & TFLAGScomplex;
+}
+
+int TypeBasic::isunsigned()
+{
+    return flags & TFLAGSunsigned;
+}
+
+int TypeBasic::isscalar()
+{
+    return flags & (TFLAGSintegral | TFLAGSfloating);
+}
+
+MATCH TypeBasic::implicitConvTo(Type *to)
+{
+    //printf("TypeBasic::implicitConvTo(%s) from %s\n", to->toChars(), toChars());
+    if (this == to)
+	return MATCHexact;
+
+    if (ty == Tvoid || to->ty == Tvoid)
+	return MATCHnomatch;
+    if (1 || global.params.Dversion == 1)
+    {
+	if (to->ty == Tbool)
+	    return MATCHnomatch;
+    }
+    else
+    {
+	if (ty == Tbool || to->ty == Tbool)
+	    return MATCHnomatch;
+    }
+    if (!to->isTypeBasic())
+	return MATCHnomatch;
+
+    TypeBasic *tob = (TypeBasic *)to;
+    if (flags & TFLAGSintegral)
+    {
+	// Disallow implicit conversion of integers to imaginary or complex
+	if (tob->flags & (TFLAGSimaginary | TFLAGScomplex))
+	    return MATCHnomatch;
+
+	// If converting to integral
+	if (0 && global.params.Dversion > 1 && tob->flags & TFLAGSintegral)
+	{   d_uns64 sz = size(0);
+	    d_uns64 tosz = tob->size(0);
+
+	    /* Can't convert to smaller size or, if same size, change sign
+	     */
+	    if (sz > tosz)
+		return MATCHnomatch;
+
+	    /*if (sz == tosz && (flags ^ tob->flags) & TFLAGSunsigned)
+		return MATCHnomatch;*/
+	}
+    }
+    else if (flags & TFLAGSfloating)
+    {
+	// Disallow implicit conversion of floating point to integer
+	if (tob->flags & TFLAGSintegral)
+	    return MATCHnomatch;
+
+	assert(tob->flags & TFLAGSfloating);
+
+	// Disallow implicit conversion from complex to non-complex
+	if (flags & TFLAGScomplex && !(tob->flags & TFLAGScomplex))
+	    return MATCHnomatch;
+
+	// Disallow implicit conversion of real or imaginary to complex
+	if (flags & (TFLAGSreal | TFLAGSimaginary) &&
+	    tob->flags & TFLAGScomplex)
+	    return MATCHnomatch;
+
+	// Disallow implicit conversion to-from real and imaginary
+	if ((flags & (TFLAGSreal | TFLAGSimaginary)) !=
+	    (tob->flags & (TFLAGSreal | TFLAGSimaginary)))
+	    return MATCHnomatch;
+    }
+    return MATCHconvert;
+}
+
+TypeBasic *TypeBasic::isTypeBasic()
+{
+    return (TypeBasic *)this;
+}
+
+/***************************** TypeArray *****************************/
+
+TypeArray::TypeArray(TY ty, Type *next)
+    : Type(ty, next)
+{
+}
+
+Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident)
+{
+    Type *n = this->next->toBasetype();		// uncover any typedef's
+
+#if LOGDOTEXP
+    printf("TypeArray::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
+#endif
+    if (ident == Id::reverse && (n->ty == Tchar || n->ty == Twchar))
+    {
+	Expression *ec;
+	FuncDeclaration *fd;
+	Expressions *arguments;
+	char *nm;
+	static char *name[2] = { "_adReverseChar", "_adReverseWchar" };
+
+	nm = name[n->ty == Twchar];
+	fd = FuncDeclaration::genCfunc(Type::tindex, nm);
+	ec = new VarExp(0, fd);
+	e = e->castTo(sc, n->arrayOf());	// convert to dynamic array
+	arguments = new Expressions();
+	arguments->push(e);
+	e = new CallExp(e->loc, ec, arguments);
+	e->type = next->arrayOf();
+    }
+    else if (ident == Id::sort && (n->ty == Tchar || n->ty == Twchar))
+    {
+	Expression *ec;
+	FuncDeclaration *fd;
+	Expressions *arguments;
+	char *nm;
+	static char *name[2] = { "_adSortChar", "_adSortWchar" };
+
+	nm = name[n->ty == Twchar];
+	fd = FuncDeclaration::genCfunc(Type::tindex, nm);
+	ec = new VarExp(0, fd);
+	e = e->castTo(sc, n->arrayOf());	// convert to dynamic array
+	arguments = new Expressions();
+	arguments->push(e);
+	e = new CallExp(e->loc, ec, arguments);
+	e->type = next->arrayOf();
+    }
+    else if (ident == Id::reverse || ident == Id::dup)
+    {
+	Expression *ec;
+	FuncDeclaration *fd;
+	Expressions *arguments;
+	int size = next->size(e->loc);
+	int dup;
+
+	assert(size);
+	dup = (ident == Id::dup);
+	fd = FuncDeclaration::genCfunc(Type::tindex, dup ? Id::adDup : Id::adReverse);
+	ec = new VarExp(0, fd);
+	e = e->castTo(sc, n->arrayOf());	// convert to dynamic array
+	arguments = new Expressions();
+	if (dup)
+	    arguments->push(getTypeInfo(sc));
+	arguments->push(e);
+	if (!dup)
+	    arguments->push(new IntegerExp(0, size, Type::tint32));
+	e = new CallExp(e->loc, ec, arguments);
+	e->type = next->arrayOf();
+    }
+    else if (ident == Id::sort)
+    {
+	Expression *ec;
+	FuncDeclaration *fd;
+	Expressions *arguments;
+
+	fd = FuncDeclaration::genCfunc(tint32->arrayOf(),
+		(char*)(n->ty == Tbit ? "_adSortBit" : "_adSort"));
+	ec = new VarExp(0, fd);
+	e = e->castTo(sc, n->arrayOf());	// convert to dynamic array
+	arguments = new Expressions();
+	arguments->push(e);
+	if (next->ty != Tbit)
+	    arguments->push(n->ty == Tsarray
+			? n->getTypeInfo(sc)	// don't convert to dynamic array
+			: n->getInternalTypeInfo(sc));
+	e = new CallExp(e->loc, ec, arguments);
+	e->type = next->arrayOf();
+    }
+    else
+    {
+	e = Type::dotExp(sc, e, ident);
+    }
+    return e;
+}
+
+void TypeArray::toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs)
+{
+#if 1
+    OutBuffer buf2;
+    toPrettyBracket(&buf2, hgs);
+    buf->prependstring(buf2.toChars());
+    if (ident)
+    {
+	buf->writeByte(' ');
+	buf->writestring(ident->toChars());
+    }
+    next->toCBuffer2(buf, NULL, hgs);
+#elif 1
+    // The D way
+    Type *t;
+    OutBuffer buf2;
+    for (t = this; 1; t = t->next)
+    {	TypeArray *ta;
+
+	ta = dynamic_cast<TypeArray *>(t);
+	if (!ta)
+	    break;
+	ta->toPrettyBracket(&buf2, hgs);
+    }
+    buf->prependstring(buf2.toChars());
+    if (ident)
+    {
+	buf2.writestring(ident->toChars());
+    }
+    t->toCBuffer2(buf, NULL, hgs);
+#else
+    // The C way
+    if (buf->offset)
+    {	buf->bracket('(', ')');
+	assert(!ident);
+    }
+    else if (ident)
+	buf->writestring(ident->toChars());
+    Type *t = this;
+    do
+    {	Expression *dim;
+	buf->writeByte('[');
+	dim = ((TypeSArray *)t)->dim;
+	if (dim)
+	    buf->printf("%lld", dim->toInteger());
+	buf->writeByte(']');
+	t = t->next;
+    } while (t->ty == Tsarray);
+    t->toCBuffer2(buf, NULL, hgs);
+#endif
+}
+
+
+/***************************** TypeSArray *****************************/
+
+TypeSArray::TypeSArray(Type *t, Expression *dim)
+    : TypeArray(Tsarray, t)
+{
+    //printf("TypeSArray(%s)\n", dim->toChars());
+    this->dim = dim;
+}
+
+Type *TypeSArray::syntaxCopy()
+{
+    Type *t = next->syntaxCopy();
+    Expression *e = dim->syntaxCopy();
+    t = new TypeSArray(t, e);
+    return t;
+}
+
+d_uns64 TypeSArray::size(Loc loc)
+{   integer_t sz;
+
+    if (!dim)
+	return Type::size(loc);
+    sz = dim->toInteger();
+    if (next->toBasetype()->ty == Tbit)		// if array of bits
+    {
+	if (sz + 31 < sz)
+	    goto Loverflow;
+	sz = ((sz + 31) & ~31) / 8;	// size in bytes, rounded up to 32 bit dwords
+    }
+    else
+    {	integer_t n, n2;
+
+	n = next->size();
+	n2 = n * sz;
+	if (n && (n2 / n) != sz)
+	    goto Loverflow;
+	sz = n2;
+    }
+    return sz;
+
+Loverflow:
+    error(loc, "index %jd overflow for static array", sz);
+    return 1;
+}
+
+unsigned TypeSArray::alignsize()
+{
+    return next->alignsize();
+}
+
+/**************************
+ * This evaluates exp while setting length to be the number
+ * of elements in the tuple t.
+ */
+Expression *semanticLength(Scope *sc, Type *t, Expression *exp)
+{
+    if (t->ty == Ttuple)
+    {	ScopeDsymbol *sym = new ArrayScopeSymbol((TypeTuple *)t);
+	sym->parent = sc->scopesym;
+	sc = sc->push(sym);
+
+	exp = exp->semantic(sc);
+
+	sc->pop();
+    }
+    else
+	exp = exp->semantic(sc);
+    return exp;
+}
+
+Expression *semanticLength(Scope *sc, TupleDeclaration *s, Expression *exp)
+{
+    ScopeDsymbol *sym = new ArrayScopeSymbol(s);
+    sym->parent = sc->scopesym;
+    sc = sc->push(sym);
+
+    exp = exp->semantic(sc);
+
+    sc->pop();
+    return exp;
+}
+
+void TypeSArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps)
+{
+    //printf("TypeSArray::resolve() %s\n", toChars());
+    next->resolve(loc, sc, pe, pt, ps);
+    //printf("s = %p, e = %p, t = %p\n", *ps, *pe, *pt);
+    if (*pe)
+    {	// It's really an index expression
+	Expression *e;
+	e = new IndexExp(loc, *pe, dim);
+	*pe = e;
+    }
+    else if (*ps)
+    {	Dsymbol *s = *ps;
+	TupleDeclaration *td = s->isTupleDeclaration();
+	if (td)
+	{
+	    ScopeDsymbol *sym = new ArrayScopeSymbol(td);
+	    sym->parent = sc->scopesym;
+	    sc = sc->push(sym);
+
+	    dim = dim->semantic(sc);
+	    dim = dim->optimize(WANTvalue | WANTinterpret);
+	    uinteger_t d = dim->toUInteger();
+
+	    sc = sc->pop();
+
+	    if (d >= td->objects->dim)
+	    {	error(loc, "tuple index %ju exceeds %u", d, td->objects->dim);
+		goto Ldefault;
+	    }
+	    Object *o = (Object *)td->objects->data[(size_t)d];
+	    if (o->dyncast() == DYNCAST_DSYMBOL)
+	    {
+		*ps = (Dsymbol *)o;
+		return;
+	    }
+	    if (o->dyncast() == DYNCAST_EXPRESSION)
+	    {
+		*ps = NULL;
+		*pe = (Expression *)o;
+		return;
+	    }
+
+	    /* Create a new TupleDeclaration which
+	     * is a slice [d..d+1] out of the old one.
+	     * Do it this way because TemplateInstance::semanticTiargs()
+	     * can handle unresolved Objects this way.
+	     */
+	    Objects *objects = new Objects;
+	    objects->setDim(1);
+	    objects->data[0] = o;
+
+	    TupleDeclaration *tds = new TupleDeclaration(loc, td->ident, objects);
+	    *ps = tds;
+	}
+	else
+	    goto Ldefault;
+    }
+    else
+    {
+     Ldefault:
+	Type::resolve(loc, sc, pe, pt, ps);
+    }
+}
+
+Type *TypeSArray::semantic(Loc loc, Scope *sc)
+{
+    //printf("TypeSArray::semantic() %s\n", toChars());
+
+    Type *t;
+    Expression *e;
+    Dsymbol *s;
+    next->resolve(loc, sc, &e, &t, &s);
+    if (dim && s && s->isTupleDeclaration())
+    {	TupleDeclaration *sd = s->isTupleDeclaration();
+
+	dim = semanticLength(sc, sd, dim);
+	dim = dim->optimize(WANTvalue | WANTinterpret);
+	uinteger_t d = dim->toUInteger();
+
+	if (d >= sd->objects->dim)
+	{   error(loc, "tuple index %ju exceeds %u", d, sd->objects->dim);
+	    return Type::terror;
+	}
+	Object *o = (Object *)sd->objects->data[(size_t)d];
+	if (o->dyncast() != DYNCAST_TYPE)
+	{   error(loc, "%s is not a type", toChars());
+	    return Type::terror;
+	}
+	t = (Type *)o;
+	return t;
+    }
+
+    next = next->semantic(loc,sc);
+    Type *tbn = next->toBasetype();
+
+    if (dim)
+    {	integer_t n, n2;
+
+	dim = semanticLength(sc, tbn, dim);
+
+	dim = dim->optimize(WANTvalue | WANTinterpret);
+	integer_t d1 = dim->toInteger();
+	dim = dim->castTo(sc, tsize_t);
+	dim = dim->optimize(WANTvalue);
+	integer_t d2 = dim->toInteger();
+
+	if (d1 != d2)
+	    goto Loverflow;
+
+	if (tbn->isintegral() ||
+		 tbn->isfloating() ||
+		 tbn->ty == Tpointer ||
+		 tbn->ty == Tarray ||
+		 tbn->ty == Tsarray ||
+		 tbn->ty == Taarray ||
+		 tbn->ty == Tclass)
+	{
+	    /* Only do this for types that don't need to have semantic()
+	     * run on them for the size, since they may be forward referenced.
+	     */
+	    n = tbn->size(loc);
+	    n2 = n * d2;
+	    if ((int)n2 < 0)
+		goto Loverflow;
+	    if (n2 >= 0x1000000)	// put a 'reasonable' limit on it
+		goto Loverflow;
+	    if (n && n2 / n != d2)
+	    {
+	      Loverflow:
+		error(loc, "index %jd overflow for static array", d1);
+		dim = new IntegerExp(0, 1, tsize_t);
+	    }
+	}
+    }
+    switch (tbn->ty)
+    {
+	case Ttuple:
+	{   // Index the tuple to get the type
+	    assert(dim);
+	    TypeTuple *tt = (TypeTuple *)tbn;
+	    uinteger_t d = dim->toUInteger();
+
+	    if (d >= tt->arguments->dim)
+	    {	error(loc, "tuple index %ju exceeds %u", d, tt->arguments->dim);
+		return Type::terror;
+	    }
+	    Argument *arg = (Argument *)tt->arguments->data[(size_t)d];
+	    return arg->type;
+	}
+	case Tfunction:
+	case Tnone:
+	    error(loc, "can't have array of %s", tbn->toChars());
+	    tbn = next = tint32;
+	    break;
+    }
+    if (tbn->isauto())
+	error(loc, "cannot have array of auto %s", tbn->toChars());
+    return merge();
+}
+
+void TypeSArray::toDecoBuffer(OutBuffer *buf)
+{
+    buf->writeByte(mangleChar[ty]);
+    if (dim)
+	buf->printf("%ju", dim->toInteger());
+    if (next)
+	next->toDecoBuffer(buf);
+}
+
+void TypeSArray::toTypeInfoBuffer(OutBuffer *buf)
+{
+    buf->writeByte(mangleChar[Tarray]);
+    if (next)
+	next->toTypeInfoBuffer(buf);
+}
+
+void TypeSArray::toPrettyBracket(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->printf("[%s]", dim->toChars());
+}
+
+Expression *TypeSArray::dotExp(Scope *sc, Expression *e, Identifier *ident)
+{
+#if LOGDOTEXP
+    printf("TypeSArray::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
+#endif
+    if (ident == Id::length)
+    {
+	e = dim;
+    }
+    else if (ident == Id::ptr)
+    {
+	e = e->castTo(sc, next->pointerTo());
+    }
+    else
+    {
+	e = TypeArray::dotExp(sc, e, ident);
+    }
+    return e;
+}
+
+int TypeSArray::isString()
+{
+    TY nty = next->toBasetype()->ty;
+    return nty == Tchar || nty == Twchar || nty == Tdchar;
+}
+
+unsigned TypeSArray::memalign(unsigned salign)
+{
+    return next->memalign(salign);
+}
+
+MATCH TypeSArray::implicitConvTo(Type *to)
+{
+    //printf("TypeSArray::implicitConvTo()\n");
+
+    // Allow implicit conversion of static array to pointer or dynamic array
+    if ((IMPLICIT_ARRAY_TO_PTR && to->ty == Tpointer) &&
+	(to->next->ty == Tvoid || next->equals(to->next)
+	 /*|| to->next->isBaseOf(next)*/))
+    {
+	return MATCHconvert;
+    }
+    if (to->ty == Tarray)
+    {	int offset = 0;
+
+	if (next->equals(to->next) ||
+	    (to->next->isBaseOf(next, &offset) && offset == 0) ||
+	    to->next->ty == Tvoid)
+	    return MATCHconvert;
+    }
+#if 0
+    if (to->ty == Tsarray)
+    {
+	TypeSArray *tsa = (TypeSArray *)to;
+
+	if (next->equals(tsa->next) && dim->equals(tsa->dim))
+	{
+	    return MATCHconvert;
+	}
+    }
+#endif
+    return Type::implicitConvTo(to);
+}
+
+Expression *TypeSArray::defaultInit()
+{
+#if LOGDEFAULTINIT
+    printf("TypeSArray::defaultInit() '%s'\n", toChars());
+#endif
+    return next->defaultInit();
+}
+
+int TypeSArray::isZeroInit()
+{
+    return next->isZeroInit();
+}
+
+
+Expression *TypeSArray::toExpression()
+{
+    Expression *e = next->toExpression();
+    if (e)
+    {	Expressions *arguments = new Expressions();
+	arguments->push(dim);
+	e = new ArrayExp(dim->loc, e, arguments);
+    }
+    return e;
+}
+
+int TypeSArray::hasPointers()
+{
+    return next->hasPointers();
+}
+
+/***************************** TypeDArray *****************************/
+
+TypeDArray::TypeDArray(Type *t)
+    : TypeArray(Tarray, t)
+{
+    //printf("TypeDArray(t = %p)\n", t);
+}
+
+Type *TypeDArray::syntaxCopy()
+{
+    Type *t = next->syntaxCopy();
+    if (t == next)
+	t = this;
+    else
+	t = new TypeDArray(t);
+    return t;
+}
+
+d_uns64 TypeDArray::size(Loc loc)
+{
+    //printf("TypeDArray::size()\n");
+    return PTRSIZE * 2;
+}
+
+unsigned TypeDArray::alignsize()
+{
+    // A DArray consists of two ptr-sized values, so align it on pointer size
+    // boundary
+    return PTRSIZE;
+}
+
+Type *TypeDArray::semantic(Loc loc, Scope *sc)
+{   Type *tn = next;
+
+    tn = next->semantic(loc,sc);
+    Type *tbn = tn->toBasetype();
+    switch (tbn->ty)
+    {
+	case Tfunction:
+	case Tnone:
+	case Ttuple:
+	    error(loc, "can't have array of %s", tbn->toChars());
+	    tn = next = tint32;
+	    break;
+    }
+    if (tn->isauto())
+	error(loc, "cannot have array of auto %s", tn->toChars());
+    if (next != tn)
+	//deco = NULL;			// redo
+	return tn->arrayOf();
+    return merge();
+}
+
+void TypeDArray::toDecoBuffer(OutBuffer *buf)
+{
+    buf->writeByte(mangleChar[ty]);
+    if (next)
+	next->toDecoBuffer(buf);
+}
+
+void TypeDArray::toTypeInfoBuffer(OutBuffer *buf)
+{
+    buf->writeByte(mangleChar[ty]);
+    if (next)
+	next->toTypeInfoBuffer(buf);
+}
+
+void TypeDArray::toPrettyBracket(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("[]");
+}
+
+Expression *TypeDArray::dotExp(Scope *sc, Expression *e, Identifier *ident)
+{
+#if LOGDOTEXP
+    printf("TypeDArray::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
+#endif
+    if (ident == Id::length)
+    {
+	if (e->op == TOKstring)
+	{   StringExp *se = (StringExp *)e;
+
+	    return new IntegerExp(se->loc, se->len, Type::tindex);
+	}
+	e = new ArrayLengthExp(e->loc, e);
+	e->type = Type::tsize_t;
+	return e;
+    }
+    else if (ident == Id::ptr)
+    {
+	e = e->castTo(sc, next->pointerTo());
+	return e;
+    }
+    else
+    {
+	e = TypeArray::dotExp(sc, e, ident);
+    }
+    return e;
+}
+
+int TypeDArray::isString()
+{
+    TY nty = next->toBasetype()->ty;
+    return nty == Tchar || nty == Twchar || nty == Tdchar;
+}
+
+MATCH TypeDArray::implicitConvTo(Type *to)
+{
+    //printf("TypeDArray::implicitConvTo()\n");
+
+    // Allow implicit conversion of array to pointer
+    if (IMPLICIT_ARRAY_TO_PTR &&
+	to->ty == Tpointer &&
+	(to->next->ty == Tvoid || next->equals(to->next) /*|| to->next->isBaseOf(next)*/))
+    {
+	return MATCHconvert;
+    }
+
+    if (to->ty == Tarray)
+    {	int offset = 0;
+
+	if ((to->next->isBaseOf(next, &offset) && offset == 0) ||
+	    to->next->ty == Tvoid)
+	    return MATCHconvert;
+    }
+    return Type::implicitConvTo(to);
+}
+
+Expression *TypeDArray::defaultInit()
+{
+#if LOGDEFAULTINIT
+    printf("TypeDArray::defaultInit() '%s'\n", toChars());
+#endif
+    Expression *e;
+    e = new NullExp(0);
+    e->type = this;
+    return e;
+}
+
+int TypeDArray::isZeroInit()
+{
+    return 1;
+}
+
+int TypeDArray::checkBoolean()
+{
+    return TRUE;
+}
+
+int TypeDArray::hasPointers()
+{
+    return TRUE;
+}
+
+/***************************** TypeAArray *****************************/
+
+TypeAArray::TypeAArray(Type *t, Type *index)
+    : TypeArray(Taarray, t)
+{
+    this->index = index;
+    this->key = NULL;
+}
+
+Type *TypeAArray::syntaxCopy()
+{
+    Type *t = next->syntaxCopy();
+    Type *ti = index->syntaxCopy();
+    if (t == next && ti == index)
+	t = this;
+    else
+	t = new TypeAArray(t, ti);
+    return t;
+}
+
+d_uns64 TypeAArray::size(Loc loc)
+{
+    return PTRSIZE /* * 2*/;
+}
+
+
+Type *TypeAArray::semantic(Loc loc, Scope *sc)
+{
+    //printf("TypeAArray::semantic() %s index->ty = %d\n", toChars(), index->ty);
+
+    // Deal with the case where we thought the index was a type, but
+    // in reality it was an expression.
+    if (index->ty == Tident || index->ty == Tinstance || index->ty == Tsarray)
+    {
+	Expression *e;
+	Type *t;
+	Dsymbol *s;
+
+	index->resolve(loc, sc, &e, &t, &s);
+	if (e)
+	{   // It was an expression -
+	    // Rewrite as a static array
+	    TypeSArray *tsa;
+
+	    tsa = new TypeSArray(next, e);
+	    return tsa->semantic(loc,sc);
+	}
+	else if (t)
+	    index = t;
+	else
+	    index->error(loc, "index is not a type or an expression");
+    }
+    else
+	index = index->semantic(loc,sc);
+
+    // Compute key type; the purpose of the key type is to
+    // minimize the permutations of runtime library
+    // routines as much as possible.
+    key = index->toBasetype();
+    switch (key->ty)
+    {
+#if 0
+	case Tint8:
+	case Tuns8:
+	case Tint16:
+	case Tuns16:
+	    key = tint32;
+	    break;
+#endif
+
+	case Tsarray:
+#if 0
+	    // Convert to Tarray
+	    key = key->next->arrayOf();
+#endif
+	    break;
+	case Tbit:
+	case Tbool:
+	case Tfunction:
+	case Tvoid:
+	case Tnone:
+	    error(loc, "can't have associative array key of %s", key->toChars());
+	    break;
+    }
+    next = next->semantic(loc,sc);
+    switch (next->toBasetype()->ty)
+    {
+	case Tfunction:
+	case Tnone:
+	    error(loc, "can't have associative array of %s", next->toChars());
+	    break;
+    }
+    if (next->isauto())
+	error(loc, "cannot have array of auto %s", next->toChars());
+
+    return merge();
+}
+
+Expression *TypeAArray::dotExp(Scope *sc, Expression *e, Identifier *ident)
+{
+#if LOGDOTEXP
+    printf("TypeAArray::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
+#endif
+    if (ident == Id::length)
+    {
+	Expression *ec;
+	FuncDeclaration *fd;
+	Expressions *arguments;
+
+	fd = FuncDeclaration::genCfunc(Type::tsize_t, Id::aaLen);
+	ec = new VarExp(0, fd);
+	arguments = new Expressions();
+	arguments->push(e);
+	e = new CallExp(e->loc, ec, arguments);
+	e->type = fd->type->next;
+    }
+    else if (ident == Id::keys)
+    {
+	Expression *ec;
+	FuncDeclaration *fd;
+	Expressions *arguments;
+	int size = key->size(e->loc);
+
+	assert(size);
+	fd = FuncDeclaration::genCfunc(Type::tindex, Id::aaKeys);
+	ec = new VarExp(0, fd);
+	arguments = new Expressions();
+	arguments->push(e);
+	arguments->push(new IntegerExp(0, size, Type::tsize_t));
+	e = new CallExp(e->loc, ec, arguments);
+	e->type = index->arrayOf();
+    }
+    else if (ident == Id::values)
+    {
+	Expression *ec;
+	FuncDeclaration *fd;
+	Expressions *arguments;
+
+	fd = FuncDeclaration::genCfunc(Type::tindex, Id::aaValues);
+	ec = new VarExp(0, fd);
+	arguments = new Expressions();
+	arguments->push(e);
+	size_t keysize = key->size(e->loc);
+	keysize = (keysize + 3) & ~3;	// BUG: 64 bit pointers?
+	arguments->push(new IntegerExp(0, keysize, Type::tsize_t));
+	arguments->push(new IntegerExp(0, next->size(e->loc), Type::tsize_t));
+	e = new CallExp(e->loc, ec, arguments);
+	e->type = next->arrayOf();
+    }
+    else if (ident == Id::rehash)
+    {
+	Expression *ec;
+	FuncDeclaration *fd;
+	Expressions *arguments;
+
+	fd = FuncDeclaration::genCfunc(Type::tint64, Id::aaRehash);
+	ec = new VarExp(0, fd);
+	arguments = new Expressions();
+	arguments->push(e->addressOf(sc));
+	arguments->push(key->getInternalTypeInfo(sc));
+	e = new CallExp(e->loc, ec, arguments);
+	e->type = this;
+    }
+    else
+    {
+	e = Type::dotExp(sc, e, ident);
+    }
+    return e;
+}
+
+void TypeAArray::toDecoBuffer(OutBuffer *buf)
+{
+    buf->writeByte(mangleChar[ty]);
+    index->toDecoBuffer(buf);
+    next->toDecoBuffer(buf);
+}
+
+void TypeAArray::toPrettyBracket(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writeByte('[');
+    {	OutBuffer ibuf;
+
+	index->toCBuffer2(&ibuf, NULL, hgs);
+	buf->write(&ibuf);
+    }
+    buf->writeByte(']');
+}
+
+Expression *TypeAArray::defaultInit()
+{
+#if LOGDEFAULTINIT
+    printf("TypeAArray::defaultInit() '%s'\n", toChars());
+#endif
+    Expression *e;
+    e = new NullExp(0);
+    e->type = this;
+    return e;
+}
+
+int TypeAArray::checkBoolean()
+{
+    return TRUE;
+}
+
+int TypeAArray::hasPointers()
+{
+    return TRUE;
+}
+
+/***************************** TypePointer *****************************/
+
+TypePointer::TypePointer(Type *t)
+    : Type(Tpointer, t)
+{
+}
+
+Type *TypePointer::syntaxCopy()
+{
+    Type *t = next->syntaxCopy();
+    if (t == next)
+	t = this;
+    else
+	t = new TypePointer(t);
+    return t;
+}
+
+Type *TypePointer::semantic(Loc loc, Scope *sc)
+{
+    //printf("TypePointer::semantic()\n");
+    Type *n = next->semantic(loc, sc);
+    switch (n->toBasetype()->ty)
+    {
+	case Ttuple:
+	    error(loc, "can't have pointer to %s", n->toChars());
+	    n = tint32;
+	    break;
+    }
+    if (n != next)
+	deco = NULL;
+    next = n;
+    return merge();
+}
+
+
+d_uns64 TypePointer::size(Loc loc)
+{
+    return PTRSIZE;
+}
+
+void TypePointer::toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs)
+{
+    //printf("TypePointer::toCBuffer2() next = %d\n", next->ty);
+    buf->prependstring("*");
+    if (ident)
+    {
+	buf->writeByte(' ');
+	buf->writestring(ident->toChars());
+    }
+    next->toCBuffer2(buf, NULL, hgs);
+}
+
+MATCH TypePointer::implicitConvTo(Type *to)
+{
+    //printf("TypePointer::implicitConvTo()\n");
+
+    if (this == to)
+	return MATCHexact;
+    if (to->ty == Tpointer && to->next)
+    {
+	if (to->next->ty == Tvoid)
+	    return MATCHconvert;
+
+#if 0
+	if (to->next->isBaseOf(next))
+	    return MATCHconvert;
+#endif
+
+	if (next->ty == Tfunction && to->next->ty == Tfunction)
+	{   TypeFunction *tf;
+	    TypeFunction *tfto;
+
+	    tf   = (TypeFunction *)(next);
+	    tfto = (TypeFunction *)(to->next);
+	    return tfto->equals(tf) ? MATCHexact : MATCHnomatch;
+	}
+    }
+//    if (to->ty == Tvoid)
+//	return MATCHconvert;
+    return MATCHnomatch;
+}
+
+int TypePointer::isscalar()
+{
+    return TRUE;
+}
+
+Expression *TypePointer::defaultInit()
+{
+#if LOGDEFAULTINIT
+    printf("TypePointer::defaultInit() '%s'\n", toChars());
+#endif
+    Expression *e;
+    e = new NullExp(0);
+    e->type = this;
+    return e;
+}
+
+int TypePointer::isZeroInit()
+{
+    return 1;
+}
+
+int TypePointer::hasPointers()
+{
+    return TRUE;
+}
+
+
+/***************************** TypeReference *****************************/
+
+TypeReference::TypeReference(Type *t)
+    : Type(Treference, t)
+{
+    if (t->ty == Tbit)
+	error(0,"cannot make reference to a bit");
+    // BUG: what about references to static arrays?
+}
+
+Type *TypeReference::syntaxCopy()
+{
+    Type *t = next->syntaxCopy();
+    if (t == next)
+	t = this;
+    else
+	t = new TypeReference(t);
+    return t;
+}
+
+d_uns64 TypeReference::size(Loc loc)
+{
+    return PTRSIZE;
+}
+
+void TypeReference::toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs)
+{
+    buf->prependstring("&");
+    if (ident)
+    {
+	buf->writestring(ident->toChars());
+    }
+    next->toCBuffer2(buf, NULL, hgs);
+}
+
+Expression *TypeReference::dotExp(Scope *sc, Expression *e, Identifier *ident)
+{
+#if LOGDOTEXP
+    printf("TypeReference::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
+#endif
+
+    // References just forward things along
+    return next->dotExp(sc, e, ident);
+}
+
+Expression *TypeReference::defaultInit()
+{
+#if LOGDEFAULTINIT
+    printf("TypeReference::defaultInit() '%s'\n", toChars());
+#endif
+    Expression *e;
+    e = new NullExp(0);
+    e->type = this;
+    return e;
+}
+
+int TypeReference::isZeroInit()
+{
+    return 1;
+}
+
+
+/***************************** TypeFunction *****************************/
+
+TypeFunction::TypeFunction(Arguments *parameters, Type *treturn, int varargs, enum LINK linkage)
+    : Type(Tfunction, treturn)
+{
+//if (!treturn) *(char*)0=0;
+//    assert(treturn);
+    this->parameters = parameters;
+    this->varargs = varargs;
+    this->linkage = linkage;
+    this->inuse = 0;
+    this->llvmRetInPtr = false;
+    this->llvmRetArg = 0;
+    this->llvmAllocaPoint = 0;
+}
+
+Type *TypeFunction::syntaxCopy()
+{
+    Type *treturn = next ? next->syntaxCopy() : NULL;
+    Arguments *params = Argument::arraySyntaxCopy(parameters);
+    Type *t = new TypeFunction(params, treturn, varargs, linkage);
+    return t;
+}
+
+/*******************************
+ * Returns:
+ *	0	types are distinct
+ *	1	this is covariant with t
+ *	2	arguments match as far as overloading goes,
+ *		but types are not covariant
+ *	3	cannot determine covariance because of forward references
+ */
+
+int Type::covariant(Type *t)
+{
+#if 0
+    printf("Type::covariant(t = %s) %s\n", t->toChars(), toChars());
+    printf("deco = %p, %p\n", deco, t->deco);
+    printf("ty = %d\n", next->ty);
+#endif
+
+    int inoutmismatch = 0;
+
+    if (equals(t))
+	goto Lcovariant;
+    if (ty != Tfunction || t->ty != Tfunction)
+	goto Ldistinct;
+
+    {
+    TypeFunction *t1 = (TypeFunction *)this;
+    TypeFunction *t2 = (TypeFunction *)t;
+
+    if (t1->varargs != t2->varargs)
+	goto Ldistinct;
+
+    if (t1->parameters && t2->parameters)
+    {
+	size_t dim = Argument::dim(t1->parameters);
+	if (dim != Argument::dim(t2->parameters))
+	    goto Ldistinct;
+
+	for (size_t i = 0; i < dim; i++)
+	{   Argument *arg1 = Argument::getNth(t1->parameters, i);
+	    Argument *arg2 = Argument::getNth(t2->parameters, i);
+
+	    if (!arg1->type->equals(arg2->type))
+		goto Ldistinct;
+	    if (arg1->storageClass != arg2->storageClass)
+		inoutmismatch = 1;
+	}
+    }
+    else if (t1->parameters != t2->parameters)
+	goto Ldistinct;
+
+    // The argument lists match
+    if (inoutmismatch)
+	goto Lnotcovariant;
+    if (t1->linkage != t2->linkage)
+	goto Lnotcovariant;
+
+    Type *t1n = t1->next;
+    Type *t2n = t2->next;
+
+    if (t1n->equals(t2n))
+	goto Lcovariant;
+    if (t1n->ty != Tclass || t2n->ty != Tclass)
+	goto Lnotcovariant;
+
+    // If t1n is forward referenced:
+    ClassDeclaration *cd = ((TypeClass *)t1n)->sym;
+    if (!cd->baseClass && cd->baseclasses.dim && !cd->isInterfaceDeclaration())
+    {
+	return 3;
+    }
+
+    if (t1n->implicitConvTo(t2n))
+	goto Lcovariant;
+    goto Lnotcovariant;
+    }
+
+Lcovariant:
+    //printf("\tcovaraint: 1\n");
+    return 1;
+
+Ldistinct:
+    //printf("\tcovaraint: 0\n");
+    return 0;
+
+Lnotcovariant:
+    //printf("\tcovaraint: 2\n");
+    return 2;
+}
+
+void TypeFunction::toDecoBuffer(OutBuffer *buf)
+{   unsigned char mc;
+
+    //printf("TypeFunction::toDecoBuffer() this = %p %s\n", this, toChars());
+    //static int nest; if (++nest == 50) *(char*)0=0;
+    if (inuse)
+    {	inuse = 2;		// flag error to caller
+	return;
+    }
+    inuse++;
+    switch (linkage)
+    {
+	case LINKd:		mc = 'F';	break;
+	case LINKc:		mc = 'U';	break;
+	case LINKwindows:	mc = 'W';	break;
+	case LINKpascal:	mc = 'V';	break;
+	case LINKcpp:		mc = 'R';	break;
+	default:
+	    assert(0);
+    }
+    buf->writeByte(mc);
+    // Write argument types
+    Argument::argsToDecoBuffer(buf, parameters);
+    //if (buf->data[buf->offset - 1] == '@') halt();
+    buf->writeByte('Z' - varargs);	// mark end of arg list
+    next->toDecoBuffer(buf);
+    inuse--;
+}
+
+void TypeFunction::toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs)
+{
+    char *p = NULL;
+
+    if (inuse)
+    {	inuse = 2;		// flag error to caller
+	return;
+    }
+    inuse++;
+    if (hgs->ddoc != 1)
+    {
+	switch (linkage)
+	{
+	    case LINKd:		p = NULL;	break;
+	    case LINKc:		p = "C ";	break;
+	    case LINKwindows:	p = "Windows ";	break;
+	    case LINKpascal:	p = "Pascal ";	break;
+	    case LINKcpp:	p = "C++ ";	break;
+	    default:
+		assert(0);
+	}
+    }
+
+    if (buf->offset)
+    {
+	if (!hgs->hdrgen && p)
+	    buf->prependstring(p);
+	buf->bracket('(', ')');
+	assert(!ident);
+    }
+    else
+    {
+	if (!hgs->hdrgen && p)
+	    buf->writestring(p);
+	if (ident)
+	{   buf->writeByte(' ');
+	    buf->writestring(ident->toHChars2());
+	}
+    }
+    Argument::argsToCBuffer(buf, hgs, parameters, varargs);
+    if (next && (!ident || ident->toHChars2() == ident->toChars()))
+	next->toCBuffer2(buf, NULL, hgs);
+    inuse--;
+}
+
+Type *TypeFunction::semantic(Loc loc, Scope *sc)
+{
+    if (deco)			// if semantic() already run
+    {
+	//printf("already done\n");
+	return this;
+    }
+    //printf("TypeFunction::semantic() this = %p\n", this);
+
+    linkage = sc->linkage;
+    if (!next)
+    {
+	assert(global.errors);
+	next = tvoid;
+    }
+    next = next->semantic(loc,sc);
+    if (next->toBasetype()->ty == Tsarray)
+    {	error(loc, "functions cannot return static array %s", next->toChars());
+	next = Type::terror;
+    }
+    if (next->toBasetype()->ty == Tfunction)
+    {	error(loc, "functions cannot return a function");
+	next = Type::terror;
+    }
+    if (next->toBasetype()->ty == Ttuple)
+    {	error(loc, "functions cannot return a tuple");
+	next = Type::terror;
+    }
+    if (next->isauto() && !(sc->flags & SCOPEctor))
+	error(loc, "functions cannot return auto %s", next->toChars());
+
+    if (parameters)
+    {	size_t dim = Argument::dim(parameters);
+
+	for (size_t i = 0; i < dim; i++)
+	{   Argument *arg = Argument::getNth(parameters, i);
+	    Type *t;
+
+	    inuse++;
+	    arg->type = arg->type->semantic(loc,sc);
+	    if (inuse == 1) inuse--;
+	    t = arg->type->toBasetype();
+
+	    if (arg->storageClass & (STCout | STCref | STClazy))
+	    {
+		if (t->ty == Tsarray)
+		    error(loc, "cannot have out or ref parameter of type %s", t->toChars());
+	    }
+	    if (!(arg->storageClass & STClazy) && t->ty == Tvoid)
+		error(loc, "cannot have parameter of type %s", arg->type->toChars());
+
+	    if (arg->defaultArg)
+	    {
+		arg->defaultArg = arg->defaultArg->semantic(sc);
+		arg->defaultArg = resolveProperties(sc, arg->defaultArg);
+		arg->defaultArg = arg->defaultArg->implicitCastTo(sc, arg->type);
+	    }
+
+	    /* If arg turns out to be a tuple, the number of parameters may
+	     * change.
+	     */
+	    if (t->ty == Ttuple)
+	    {	dim = Argument::dim(parameters);
+		i--;
+	    }
+	}
+    }
+    deco = merge()->deco;
+
+    if (inuse)
+    {	error(loc, "recursive type");
+	inuse = 0;
+	return terror;
+    }
+
+    if (varargs == 1 && linkage != LINKd && Argument::dim(parameters) == 0)
+	error(loc, "variadic functions with non-D linkage must have at least one parameter");
+
+    /* Don't return merge(), because arg identifiers and default args
+     * can be different
+     * even though the types match
+     */
+    return this;
+}
+
+/********************************
+ * 'args' are being matched to function 'this'
+ * Determine match level.
+ * Returns:
+ *	MATCHxxxx
+ */
+
+int TypeFunction::callMatch(Expressions *args)
+{
+    //printf("TypeFunction::callMatch()\n");
+    int match = MATCHexact;		// assume exact match
+
+    size_t nparams = Argument::dim(parameters);
+    size_t nargs = args ? args->dim : 0;
+    if (nparams == nargs)
+	;
+    else if (nargs > nparams)
+    {
+	if (varargs == 0)
+	    goto Nomatch;		// too many args; no match
+	match = MATCHconvert;		// match ... with a "conversion" match level
+    }
+
+    for (size_t u = 0; u < nparams; u++)
+    {	int m;
+	Expression *arg;
+
+	// BUG: what about out and ref?
+
+	Argument *p = Argument::getNth(parameters, u);
+	assert(p);
+	if (u >= nargs)
+	{
+	    if (p->defaultArg)
+		continue;
+	    if (varargs == 2 && u + 1 == nparams)
+		goto L1;
+	    goto Nomatch;		// not enough arguments
+	}
+	arg = (Expression *)args->data[u];
+	assert(arg);
+	if (p->storageClass & STClazy && p->type->ty == Tvoid && arg->type->ty != Tvoid)
+	    m = MATCHconvert;
+	else
+	    m = arg->implicitConvTo(p->type);
+	//printf("\tm = %d\n", m);
+	if (m == MATCHnomatch)			// if no match
+	{
+	  L1:
+	    if (varargs == 2 && u + 1 == nparams)	// if last varargs param
+	    {	Type *tb = p->type->toBasetype();
+		TypeSArray *tsa;
+		integer_t sz;
+
+		switch (tb->ty)
+		{
+		    case Tsarray:
+			tsa = (TypeSArray *)tb;
+			sz = tsa->dim->toInteger();
+			if (sz != nargs - u)
+			    goto Nomatch;
+		    case Tarray:
+			for (; u < nargs; u++)
+			{
+			    arg = (Expression *)args->data[u];
+			    assert(arg);
+#if 1
+			    /* If lazy array of delegates,
+			     * convert arg(s) to delegate(s)
+			     */
+			    Type *tret = p->isLazyArray();
+			    if (tret)
+			    {
+				if (tb->next->equals(arg->type))
+				{   m = MATCHexact;
+				}
+				else
+				{
+				    m = arg->implicitConvTo(tret);
+				    if (m == MATCHnomatch)
+				    {
+					if (tret->toBasetype()->ty == Tvoid)
+					    m = MATCHconvert;
+				    }
+				}
+			    }
+			    else
+				m = arg->implicitConvTo(tb->next);
+#else
+			    m = arg->implicitConvTo(tb->next);
+#endif
+			    if (m == 0)
+				goto Nomatch;
+			    if (m < match)
+				match = m;
+			}
+			goto Ldone;
+
+		    case Tclass:
+			// Should see if there's a constructor match?
+			// Or just leave it ambiguous?
+			goto Ldone;
+
+		    default:
+			goto Nomatch;
+		}
+	    }
+	    goto Nomatch;
+	}
+	if (m < match)
+	    match = m;			// pick worst match
+    }
+
+Ldone:
+    //printf("match = %d\n", match);
+    return match;
+
+Nomatch:
+    //printf("no match\n");
+    return MATCHnomatch;
+}
+
+Type *TypeFunction::reliesOnTident()
+{
+    if (parameters)
+    {
+	for (size_t i = 0; i < parameters->dim; i++)
+	{   Argument *arg = (Argument *)parameters->data[i];
+	    Type *t = arg->type->reliesOnTident();
+	    if (t)
+		return t;
+	}
+    }
+    return next->reliesOnTident();
+}
+
+/***************************** TypeDelegate *****************************/
+
+TypeDelegate::TypeDelegate(Type *t)
+    : Type(Tfunction, t)
+{
+    ty = Tdelegate;
+}
+
+Type *TypeDelegate::syntaxCopy()
+{
+    Type *t = next->syntaxCopy();
+    if (t == next)
+	t = this;
+    else
+	t = new TypeDelegate(t);
+    return t;
+}
+
+Type *TypeDelegate::semantic(Loc loc, Scope *sc)
+{
+    if (deco)			// if semantic() already run
+    {
+	//printf("already done\n");
+	return this;
+    }
+    next = next->semantic(loc,sc);
+    return merge();
+}
+
+d_uns64 TypeDelegate::size(Loc loc)
+{
+    return PTRSIZE * 2;
+}
+
+void TypeDelegate::toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs)
+{
+#if 1
+    OutBuffer args;
+    TypeFunction *tf = (TypeFunction *)next;
+
+    Argument::argsToCBuffer(&args, hgs, tf->parameters, tf->varargs);
+    buf->prependstring(args.toChars());
+    buf->prependstring(" delegate");
+    if (ident)
+    {
+	buf->writeByte(' ');
+	buf->writestring(ident->toChars());
+    }
+    next->next->toCBuffer2(buf, NULL, hgs);
+#else
+    next->toCBuffer2(buf, Id::delegate, hgs);
+    if (ident)
+    {
+	buf->writestring(ident->toChars());
+    }
+#endif
+}
+
+Expression *TypeDelegate::defaultInit()
+{
+#if LOGDEFAULTINIT
+    printf("TypeDelegate::defaultInit() '%s'\n", toChars());
+#endif
+    Expression *e;
+    e = new NullExp(0);
+    e->type = this;
+    return e;
+}
+
+int TypeDelegate::isZeroInit()
+{
+    return 1;
+}
+
+int TypeDelegate::checkBoolean()
+{
+    return TRUE;
+}
+
+Expression *TypeDelegate::dotExp(Scope *sc, Expression *e, Identifier *ident)
+{
+#if LOGDOTEXP
+    printf("TypeDelegate::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
+#endif
+    if (ident == Id::ptr)
+    {
+	e->type = tvoidptr;
+	return e;
+    }
+    else if (ident == Id::funcptr)
+    {
+	e = e->addressOf(sc);
+	e->type = tvoidptr;
+	e = new AddExp(e->loc, e, new IntegerExp(PTRSIZE));
+	e->type = tvoidptr;
+	e = new PtrExp(e->loc, e);
+	e->type = next->pointerTo();
+	return e;
+    }
+    else
+    {
+	e = Type::dotExp(sc, e, ident);
+    }
+    return e;
+}
+
+int TypeDelegate::hasPointers()
+{
+    return TRUE;
+}
+
+
+
+/***************************** TypeQualified *****************************/
+
+TypeQualified::TypeQualified(TY ty, Loc loc)
+    : Type(ty, NULL)
+{
+    this->loc = loc;
+}
+
+void TypeQualified::syntaxCopyHelper(TypeQualified *t)
+{
+    //printf("TypeQualified::syntaxCopyHelper(%s) %s\n", t->toChars(), toChars());
+    idents.setDim(t->idents.dim);
+    for (int i = 0; i < idents.dim; i++)
+    {
+	Identifier *id = (Identifier *)t->idents.data[i];
+	if (id->dyncast() == DYNCAST_DSYMBOL)
+	{
+	    TemplateInstance *ti = (TemplateInstance *)id;
+
+	    ti = (TemplateInstance *)ti->syntaxCopy(NULL);
+	    id = (Identifier *)ti;
+	}
+	idents.data[i] = id;
+    }
+}
+
+
+void TypeQualified::addIdent(Identifier *ident)
+{
+    idents.push(ident);
+}
+
+void TypeQualified::toCBuffer2Helper(OutBuffer *buf, Identifier *ident, HdrGenState *hgs)
+{
+    int i;
+
+    for (i = 0; i < idents.dim; i++)
+    {	Identifier *id = (Identifier *)idents.data[i];
+
+	buf->writeByte('.');
+
+	if (id->dyncast() == DYNCAST_DSYMBOL)
+	{
+	    TemplateInstance *ti = (TemplateInstance *)id;
+	    ti->toCBuffer(buf, hgs);
+	}
+	else
+	    buf->writestring(id->toChars());
+    }
+}
+
+d_uns64 TypeQualified::size(Loc loc)
+{
+    error(this->loc, "size of type %s is not known", toChars());
+    return 1;
+}
+
+/*************************************
+ * Takes an array of Identifiers and figures out if
+ * it represents a Type or an Expression.
+ * Output:
+ *	if expression, *pe is set
+ *	if type, *pt is set
+ */
+
+void TypeQualified::resolveHelper(Loc loc, Scope *sc,
+	Dsymbol *s, Dsymbol *scopesym,
+	Expression **pe, Type **pt, Dsymbol **ps)
+{
+    Identifier *id = NULL;
+    int i;
+    VarDeclaration *v;
+    EnumMember *em;
+    TupleDeclaration *td;
+    Type *t;
+    Expression *e;
+
+#if 0
+    printf("TypeQualified::resolveHelper(sc = %p, idents = '%s')\n", sc, toChars());
+    if (scopesym)
+	printf("\tscopesym = '%s'\n", scopesym->toChars());
+#endif
+    *pe = NULL;
+    *pt = NULL;
+    *ps = NULL;
+    if (s)
+    {
+	//printf("\t1: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind());
+	s = s->toAlias();
+	//printf("\t2: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind());
+	for (i = 0; i < idents.dim; i++)
+	{   Dsymbol *sm;
+
+	    id = (Identifier *)idents.data[i];
+	    sm = s->searchX(loc, sc, id);
+	    //printf("\t3: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind());
+	    //printf("getType = '%s'\n", s->getType()->toChars());
+	    if (!sm)
+	    {
+		v = s->isVarDeclaration();
+		if (v && id == Id::length)
+		{
+		    if (v->isConst() && v->getExpInitializer())
+		    {	e = v->getExpInitializer()->exp;
+		    }
+		    else
+			e = new VarExp(loc, v);
+		    t = e->type;
+		    if (!t)
+			goto Lerror;
+		    goto L3;
+		}
+		t = s->getType();
+		if (!t && s->isDeclaration())
+		    t = s->isDeclaration()->type;
+		if (t)
+		{
+		    sm = t->toDsymbol(sc);
+		    if (sm)
+		    {	sm = sm->search(loc, id, 0);
+			if (sm)
+			    goto L2;
+		    }
+		    //e = t->getProperty(loc, id);
+		    e = new TypeExp(loc, t);
+		    e = t->dotExp(sc, e, id);
+		    i++;
+		L3:
+		    for (; i < idents.dim; i++)
+		    {
+			id = (Identifier *)idents.data[i];
+			//printf("e: '%s', id: '%s', type = %p\n", e->toChars(), id->toChars(), e->type);
+			e = e->type->dotExp(sc, e, id);
+		    }
+		    *pe = e;
+		}
+		else
+	          Lerror:
+		    error(loc, "identifier '%s' of '%s' is not defined", id->toChars(), toChars());
+		return;
+	    }
+	L2:
+	    s = sm->toAlias();
+	}
+
+	v = s->isVarDeclaration();
+	if (v)
+	{
+	    // It's not a type, it's an expression
+	    if (v->isConst() && v->getExpInitializer())
+	    {
+		ExpInitializer *ei = v->getExpInitializer();
+		assert(ei);
+		*pe = ei->exp->copy();	// make copy so we can change loc
+		(*pe)->loc = loc;
+	    }
+	    else
+	    {
+#if 0
+		WithScopeSymbol *withsym;
+		if (scopesym && (withsym = scopesym->isWithScopeSymbol()) != NULL)
+		{
+		    // Same as wthis.ident
+		    e = new VarExp(loc, withsym->withstate->wthis);
+		    e = new DotIdExp(loc, e, ident);
+		    //assert(0);	// BUG: should handle this
+		}
+		else
+#endif
+		    *pe = new VarExp(loc, v);
+	    }
+	    return;
+	}
+	em = s->isEnumMember();
+	if (em)
+	{
+	    // It's not a type, it's an expression
+	    *pe = em->value->copy();
+	    return;
+	}
+
+L1:
+	t = s->getType();
+	if (!t)
+	{
+	    // If the symbol is an import, try looking inside the import
+	    Import *si;
+
+	    si = s->isImport();
+	    if (si)
+	    {
+		s = si->search(loc, s->ident, 0);
+		if (s && s != si)
+		    goto L1;
+		s = si;
+	    }
+	    *ps = s;
+	    return;
+	}
+	if (t->ty == Tinstance && t != this && !t->deco)
+	{   error(loc, "forward reference to '%s'", t->toChars());
+	    return;
+	}
+
+	if (t != this)
+	{
+	    if (t->reliesOnTident())
+	    {
+		Scope *scx;
+
+		for (scx = sc; 1; scx = scx->enclosing)
+		{
+		    if (!scx)
+		    {   error(loc, "forward reference to '%s'", t->toChars());
+			return;
+		    }
+		    if (scx->scopesym == scopesym)
+			break;
+		}
+		t = t->semantic(loc, scx);
+		//((TypeIdentifier *)t)->resolve(loc, scx, pe, &t, ps);
+	    }
+	}
+	if (t->ty == Ttuple)
+	    *pt = t;
+	else
+	    *pt = t->merge();
+    }
+    if (!s)
+    {
+	error(loc, "identifier '%s' is not defined", toChars());
+    }
+}
+
+/***************************** TypeIdentifier *****************************/
+
+TypeIdentifier::TypeIdentifier(Loc loc, Identifier *ident)
+    : TypeQualified(Tident, loc)
+{
+    this->ident = ident;
+}
+
+
+Type *TypeIdentifier::syntaxCopy()
+{
+    TypeIdentifier *t;
+
+    t = new TypeIdentifier(loc, ident);
+    t->syntaxCopyHelper(this);
+    return t;
+}
+
+void TypeIdentifier::toDecoBuffer(OutBuffer *buf)
+{   unsigned len;
+    char *name;
+
+    name = ident->toChars();
+    len = strlen(name);
+    buf->printf("%c%d%s", mangleChar[ty], len, name);
+    //buf->printf("%c%s", mangleChar[ty], name);
+}
+
+void TypeIdentifier::toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs)
+{
+    OutBuffer tmp;
+
+    tmp.writestring(this->ident->toChars());
+    toCBuffer2Helper(&tmp, NULL, hgs);
+    buf->prependstring(tmp.toChars());
+    if (ident)
+    {	buf->writeByte(' ');
+	buf->writestring(ident->toChars());
+    }
+}
+
+/*************************************
+ * Takes an array of Identifiers and figures out if
+ * it represents a Type or an Expression.
+ * Output:
+ *	if expression, *pe is set
+ *	if type, *pt is set
+ */
+
+void TypeIdentifier::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps)
+{   Dsymbol *s;
+    Dsymbol *scopesym;
+
+    //printf("TypeIdentifier::resolve(sc = %p, idents = '%s')\n", sc, toChars());
+    s = sc->search(loc, ident, &scopesym);
+    resolveHelper(loc, sc, s, scopesym, pe, pt, ps);
+}
+
+/*****************************************
+ * See if type resolves to a symbol, if so,
+ * return that symbol.
+ */
+
+Dsymbol *TypeIdentifier::toDsymbol(Scope *sc)
+{
+    //printf("TypeIdentifier::toDsymbol('%s')\n", toChars());
+    if (!sc)
+	return NULL;
+    //printf("ident = '%s'\n", ident->toChars());
+
+    Dsymbol *scopesym;
+    Dsymbol *s = sc->search(loc, ident, &scopesym);
+    if (s)
+    {
+	for (int i = 0; i < idents.dim; i++)
+	{
+	    Identifier *id = (Identifier *)idents.data[i];
+	    s = s->searchX(loc, sc, id);
+	    if (!s)                 // failed to find a symbol
+	    {	//printf("\tdidn't find a symbol\n");
+		break;
+	    }
+	}
+    }
+    return s;
+}
+
+Type *TypeIdentifier::semantic(Loc loc, Scope *sc)
+{
+    Type *t;
+    Expression *e;
+    Dsymbol *s;
+
+    //printf("TypeIdentifier::semantic(%s)\n", toChars());
+    resolve(loc, sc, &e, &t, &s);
+    if (t)
+    {
+	//printf("\tit's a type %d, %s, %s\n", t->ty, t->toChars(), t->deco);
+
+	if (t->ty == Ttypedef)
+	{   TypeTypedef *tt = (TypeTypedef *)t;
+
+	    if (tt->sym->sem == 1)
+		error(loc, "circular reference of typedef %s", tt->toChars());
+	}
+    }
+    else
+    {
+#ifdef DEBUG
+	if (!global.gag)
+	    printf("1: ");
+#endif
+	if (s)
+	{
+	    s->error(loc, "is used as a type");
+	}
+	else
+	    error(loc, "%s is used as a type", toChars());
+	t = tvoid;
+    }
+    //t->print();
+    return t;
+}
+
+Type *TypeIdentifier::reliesOnTident()
+{
+    return this;
+}
+
+Expression *TypeIdentifier::toExpression()
+{
+    Expression *e = new IdentifierExp(loc, ident);
+    for (int i = 0; i < idents.dim; i++)
+    {
+	Identifier *id = (Identifier *)idents.data[i];
+	e = new DotIdExp(loc, e, id);
+    }
+
+    return e;
+}
+
+/***************************** TypeInstance *****************************/
+
+TypeInstance::TypeInstance(Loc loc, TemplateInstance *tempinst)
+    : TypeQualified(Tinstance, loc)
+{
+    this->tempinst = tempinst;
+}
+
+Type *TypeInstance::syntaxCopy()
+{
+    //printf("TypeInstance::syntaxCopy() %s, %d\n", toChars(), idents.dim);
+    TypeInstance *t;
+
+    t = new TypeInstance(loc, (TemplateInstance *)tempinst->syntaxCopy(NULL));
+    t->syntaxCopyHelper(this);
+    return t;
+}
+
+
+void TypeInstance::toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs)
+{
+    OutBuffer tmp;
+
+    tempinst->toCBuffer(&tmp, hgs);
+    toCBuffer2Helper(&tmp, NULL, hgs);
+    buf->prependstring(tmp.toChars());
+    if (ident)
+    {	buf->writeByte(' ');
+	buf->writestring(ident->toChars());
+    }
+}
+
+void TypeInstance::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps)
+{
+    // Note close similarity to TypeIdentifier::resolve()
+
+    Dsymbol *s;
+
+    *pe = NULL;
+    *pt = NULL;
+    *ps = NULL;
+
+#if 0
+    if (!idents.dim)
+    {
+	error(loc, "template instance '%s' has no identifier", toChars());
+	return;
+    }
+#endif
+    //id = (Identifier *)idents.data[0];
+    //printf("TypeInstance::resolve(sc = %p, idents = '%s')\n", sc, id->toChars());
+    s = tempinst;
+    if (s)
+	s->semantic(sc);
+    resolveHelper(loc, sc, s, NULL, pe, pt, ps);
+    //printf("pt = '%s'\n", (*pt)->toChars());
+}
+
+Type *TypeInstance::semantic(Loc loc, Scope *sc)
+{
+    Type *t;
+    Expression *e;
+    Dsymbol *s;
+
+    //printf("TypeInstance::semantic(%s)\n", toChars());
+
+    if (sc->parameterSpecialization)
+    {
+	unsigned errors = global.errors;
+	global.gag++;
+
+	resolve(loc, sc, &e, &t, &s);
+
+	global.gag--;
+	if (errors != global.errors)
+	{   if (global.gag == 0)
+		global.errors = errors;
+	    return this;
+	}
+    }
+    else
+	resolve(loc, sc, &e, &t, &s);
+
+    if (!t)
+    {
+#ifdef DEBUG
+	printf("2: ");
+#endif
+	error(loc, "%s is used as a type", toChars());
+	t = tvoid;
+    }
+    return t;
+}
+
+
+/***************************** TypeTypeof *****************************/
+
+TypeTypeof::TypeTypeof(Loc loc, Expression *exp)
+	: TypeQualified(Ttypeof, loc)
+{
+    this->exp = exp;
+}
+
+Type *TypeTypeof::syntaxCopy()
+{
+    TypeTypeof *t;
+
+    t = new TypeTypeof(loc, exp->syntaxCopy());
+    t->syntaxCopyHelper(this);
+    return t;
+}
+
+Dsymbol *TypeTypeof::toDsymbol(Scope *sc)
+{
+    Type *t;
+
+    t = semantic(0, sc);
+    if (t == this)
+	return NULL;
+    return t->toDsymbol(sc);
+}
+
+void TypeTypeof::toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs)
+{
+    OutBuffer tmp;
+
+    tmp.writestring("typeof(");
+    exp->toCBuffer(&tmp, hgs);
+    tmp.writeByte(')');
+    toCBuffer2Helper(&tmp, NULL, hgs);
+    buf->prependstring(tmp.toChars());
+    if (ident)
+    {	buf->writeByte(' ');
+	buf->writestring(ident->toChars());
+    }
+}
+
+Type *TypeTypeof::semantic(Loc loc, Scope *sc)
+{   Expression *e;
+    Type *t;
+
+    //printf("TypeTypeof::semantic() %p\n", this);
+
+    //static int nest; if (++nest == 50) *(char*)0=0;
+
+#if 0
+    /* Special case for typeof(this) and typeof(super) since both
+     * should work even if they are not inside a non-static member function
+     */
+    if (exp->op == TOKthis || exp->op == TOKsuper)
+    {
+	// Find enclosing struct or class
+	for (Dsymbol *s = sc->parent; 1; s = s->parent)
+	{
+	    ClassDeclaration *cd;
+	    StructDeclaration *sd;
+
+	    if (!s)
+	    {
+		error(loc, "%s is not in a struct or class scope", exp->toChars());
+		goto Lerr;
+	    }
+	    cd = s->isClassDeclaration();
+	    if (cd)
+	    {
+		if (exp->op == TOKsuper)
+		{
+		    cd = cd->baseClass;
+		    if (!cd)
+		    {	error(loc, "class %s has no 'super'", s->toChars());
+			goto Lerr;
+		    }
+		}
+		t = cd->type;
+		break;
+	    }
+	    sd = s->isStructDeclaration();
+	    if (sd)
+	    {
+		if (exp->op == TOKsuper)
+		{
+		    error(loc, "struct %s has no 'super'", sd->toChars());
+		    goto Lerr;
+		}
+		t = sd->type->pointerTo();
+		break;
+	    }
+	}
+    }
+    else
+#endif
+    {
+	sc->intypeof++;
+	exp = exp->semantic(sc);
+	sc->intypeof--;
+	t = exp->type;
+	if (!t)
+	{
+	    error(loc, "expression (%s) has no type", exp->toChars());
+	    goto Lerr;
+	}
+    }
+
+    if (idents.dim)
+    {
+	Dsymbol *s = t->toDsymbol(sc);
+	for (size_t i = 0; i < idents.dim; i++)
+	{
+	    if (!s)
+		break;
+	    Identifier *id = (Identifier *)idents.data[i];
+	    s = s->searchX(loc, sc, id);
+	}
+	if (s)
+	{
+	    t = s->getType();
+	    if (!t)
+	    {	error(loc, "%s is not a type", s->toChars());
+		goto Lerr;
+	    }
+	}
+	else
+	{   error(loc, "cannot resolve .property for %s", toChars());
+	    goto Lerr;
+	}
+    }
+    return t;
+
+Lerr:
+    return tvoid;
+}
+
+d_uns64 TypeTypeof::size(Loc loc)
+{
+    if (exp->type)
+	return exp->type->size(loc);
+    else
+	return TypeQualified::size(loc);
+}
+
+
+
+/***************************** TypeEnum *****************************/
+
+TypeEnum::TypeEnum(EnumDeclaration *sym)
+	: Type(Tenum, NULL)
+{
+    this->sym = sym;
+}
+
+char *TypeEnum::toChars()
+{
+    return sym->toChars();
+}
+
+Type *TypeEnum::semantic(Loc loc, Scope *sc)
+{
+    sym->semantic(sc);
+    return merge();
+}
+
+d_uns64 TypeEnum::size(Loc loc)
+{
+    if (!sym->memtype)
+    {
+	error(loc, "enum %s is forward referenced", sym->toChars());
+	return 4;
+    }
+    return sym->memtype->size(loc);
+}
+
+unsigned TypeEnum::alignsize()
+{
+    if (!sym->memtype)
+    {
+#ifdef DEBUG
+	printf("1: ");
+#endif
+	error(0, "enum %s is forward referenced", sym->toChars());
+	return 4;
+    }
+    return sym->memtype->alignsize();
+}
+
+Dsymbol *TypeEnum::toDsymbol(Scope *sc)
+{
+    return sym;
+}
+
+Type *TypeEnum::toBasetype()
+{
+    if (!sym->memtype)
+    {
+#ifdef DEBUG
+	printf("2: ");
+#endif
+	error(sym->loc, "enum %s is forward referenced", sym->toChars());
+	return tint32;
+    }
+    return sym->memtype->toBasetype();
+}
+
+void TypeEnum::toDecoBuffer(OutBuffer *buf)
+{   char *name;
+
+    name = sym->mangle();
+//    if (name[0] == '_' && name[1] == 'D')
+//	name += 2;
+    buf->printf("%c%s", mangleChar[ty], name);
+}
+
+void TypeEnum::toTypeInfoBuffer(OutBuffer *buf)
+{
+    toBasetype()->toTypeInfoBuffer(buf);
+}
+
+void TypeEnum::toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs)
+{
+    buf->prependstring(sym->toChars());
+    if (ident)
+    {	buf->writeByte(' ');
+	buf->writestring(ident->toChars());
+    }
+}
+
+Expression *TypeEnum::dotExp(Scope *sc, Expression *e, Identifier *ident)
+{
+    EnumMember *m;
+    Dsymbol *s;
+    Expression *em;
+
+#if LOGDOTEXP
+    printf("TypeEnum::dotExp(e = '%s', ident = '%s') '%s'\n", e->toChars(), ident->toChars(), toChars());
+#endif
+    s = sym->symtab->lookup(ident);
+    if (!s)
+    {
+	return getProperty(e->loc, ident);
+    }
+    m = s->isEnumMember();
+    em = m->value->copy();
+    em->loc = e->loc;
+    return em;
+}
+
+Expression *TypeEnum::getProperty(Loc loc, Identifier *ident)
+{   Expression *e;
+
+    if (ident == Id::max)
+    {
+	if (!sym->symtab)
+	    goto Lfwd;
+	e = new IntegerExp(0, sym->maxval, this);
+    }
+    else if (ident == Id::min)
+    {
+	if (!sym->symtab)
+	    goto Lfwd;
+	e = new IntegerExp(0, sym->minval, this);
+    }
+    else if (ident == Id::init)
+    {
+	if (!sym->symtab)
+	    goto Lfwd;
+	e = defaultInit();
+    }
+    else
+    {
+	if (!sym->memtype)
+	    goto Lfwd;
+	e = sym->memtype->getProperty(loc, ident);
+    }
+    return e;
+
+Lfwd:
+    error(loc, "forward reference of %s.%s", toChars(), ident->toChars());
+    return new IntegerExp(0, 0, this);
+}
+
+int TypeEnum::isintegral()
+{
+    return 1;
+}
+
+int TypeEnum::isfloating()
+{
+    return 0;
+}
+
+int TypeEnum::isunsigned()
+{
+    return sym->memtype->isunsigned();
+}
+
+int TypeEnum::isscalar()
+{
+    return 1;
+    //return sym->memtype->isscalar();
+}
+
+MATCH TypeEnum::implicitConvTo(Type *to)
+{   MATCH m;
+
+    //printf("TypeEnum::implicitConvTo()\n");
+    if (this->equals(to))
+	m = MATCHexact;		// exact match
+    else if (sym->memtype->implicitConvTo(to))
+	m = MATCHconvert;	// match with conversions
+    else
+	m = MATCHnomatch;	// no match
+    return m;
+}
+
+Expression *TypeEnum::defaultInit()
+{
+#if LOGDEFAULTINIT
+    printf("TypeEnum::defaultInit() '%s'\n", toChars());
+#endif
+    // Initialize to first member of enum
+    Expression *e;
+    e = new IntegerExp(0, sym->defaultval, this);
+    return e;
+}
+
+int TypeEnum::isZeroInit()
+{
+    return (sym->defaultval == 0);
+}
+
+int TypeEnum::hasPointers()
+{
+    return toBasetype()->hasPointers();
+}
+
+/***************************** TypeTypedef *****************************/
+
+TypeTypedef::TypeTypedef(TypedefDeclaration *sym)
+	: Type(Ttypedef, NULL)
+{
+    this->sym = sym;
+}
+
+Type *TypeTypedef::syntaxCopy()
+{
+    return this;
+}
+
+char *TypeTypedef::toChars()
+{
+    return sym->toChars();
+}
+
+Type *TypeTypedef::semantic(Loc loc, Scope *sc)
+{
+    //printf("TypeTypedef::semantic(%s), sem = %d\n", toChars(), sym->sem);
+    sym->semantic(sc);
+    return merge();
+}
+
+d_uns64 TypeTypedef::size(Loc loc)
+{
+    return sym->basetype->size(loc);
+}
+
+unsigned TypeTypedef::alignsize()
+{
+    return sym->basetype->alignsize();
+}
+
+Dsymbol *TypeTypedef::toDsymbol(Scope *sc)
+{
+    return sym;
+}
+
+void TypeTypedef::toDecoBuffer(OutBuffer *buf)
+{   unsigned len;
+    char *name;
+
+    name = sym->mangle();
+//    if (name[0] == '_' && name[1] == 'D')
+//	name += 2;
+    //len = strlen(name);
+    //buf->printf("%c%d%s", mangleChar[ty], len, name);
+    buf->printf("%c%s", mangleChar[ty], name);
+}
+
+void TypeTypedef::toTypeInfoBuffer(OutBuffer *buf)
+{
+    sym->basetype->toTypeInfoBuffer(buf);
+}
+
+void TypeTypedef::toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs)
+{
+    //printf("TypeTypedef::toCBuffer2() '%s'\n", sym->toChars());
+    buf->prependstring(sym->toChars());
+    if (ident)
+    {	buf->writeByte(' ');
+	buf->writestring(ident->toChars());
+    }
+}
+
+Expression *TypeTypedef::dotExp(Scope *sc, Expression *e, Identifier *ident)
+{
+#if LOGDOTEXP
+    printf("TypeTypedef::dotExp(e = '%s', ident = '%s') '%s'\n", e->toChars(), ident->toChars(), toChars());
+#endif
+    if (ident == Id::init)
+    {
+	return Type::dotExp(sc, e, ident);
+    }
+    return sym->basetype->dotExp(sc, e, ident);
+}
+
+int TypeTypedef::isbit()
+{
+    return sym->basetype->isbit();
+}
+
+int TypeTypedef::isintegral()
+{
+    //printf("TypeTypedef::isintegral()\n");
+    //printf("sym = '%s'\n", sym->toChars());
+    //printf("basetype = '%s'\n", sym->basetype->toChars());
+    return sym->basetype->isintegral();
+}
+
+int TypeTypedef::isfloating()
+{
+    return sym->basetype->isfloating();
+}
+
+int TypeTypedef::isreal()
+{
+    return sym->basetype->isreal();
+}
+
+int TypeTypedef::isimaginary()
+{
+    return sym->basetype->isimaginary();
+}
+
+int TypeTypedef::iscomplex()
+{
+    return sym->basetype->iscomplex();
+}
+
+int TypeTypedef::isunsigned()
+{
+    return sym->basetype->isunsigned();
+}
+
+int TypeTypedef::isscalar()
+{
+    return sym->basetype->isscalar();
+}
+
+int TypeTypedef::checkBoolean()
+{
+    return sym->basetype->checkBoolean();
+}
+
+Type *TypeTypedef::toBasetype()
+{
+    if (sym->inuse)
+    {
+	sym->error("circular definition");
+	sym->basetype = Type::terror;
+	return Type::terror;
+    }
+    sym->inuse = 1;
+    Type *t = sym->basetype->toBasetype();
+    sym->inuse = 0;
+    return t;
+}
+
+MATCH TypeTypedef::implicitConvTo(Type *to)
+{   MATCH m;
+
+    //printf("TypeTypedef::implicitConvTo()\n");
+    if (this->equals(to))
+	m = MATCHexact;		// exact match
+    else if (sym->basetype->implicitConvTo(to))
+	m = MATCHconvert;	// match with conversions
+    else
+	m = MATCHnomatch;	// no match
+    return m;
+}
+
+Expression *TypeTypedef::defaultInit()
+{   Expression *e;
+    Type *bt;
+
+#if LOGDEFAULTINIT
+    printf("TypeTypedef::defaultInit() '%s'\n", toChars());
+#endif
+    if (sym->init)
+    {
+	//sym->init->toExpression()->print();
+	return sym->init->toExpression();
+    }
+    bt = sym->basetype;
+    e = bt->defaultInit();
+    e->type = this;
+    while (bt->ty == Tsarray)
+    {
+	e->type = bt->next;
+	bt = bt->next->toBasetype();
+    }
+    return e;
+}
+
+int TypeTypedef::isZeroInit()
+{
+    if (sym->init)
+    {
+	if (sym->init->isVoidInitializer())
+	    return 1;		// initialize voids to 0
+	Expression *e = sym->init->toExpression();
+	if (e && e->isBool(FALSE))
+	    return 1;
+	return 0;		// assume not
+    }
+    if (sym->inuse)
+    {
+	sym->error("circular definition");
+	sym->basetype = Type::terror;
+    }
+    sym->inuse = 1;
+    int result = sym->basetype->isZeroInit();
+    sym->inuse = 0;
+    return result;
+}
+
+int TypeTypedef::hasPointers()
+{
+    return toBasetype()->hasPointers();
+}
+
+/***************************** TypeStruct *****************************/
+
+TypeStruct::TypeStruct(StructDeclaration *sym)
+	: Type(Tstruct, NULL)
+{
+    this->sym = sym;
+    llvmInit = 0;
+}
+
+char *TypeStruct::toChars()
+{
+    //printf("sym.parent: %s, deco = %s\n", sym->parent->toChars(), deco);
+    TemplateInstance *ti = sym->parent->isTemplateInstance();
+    if (ti && ti->toAlias() == sym)
+	return ti->toChars();
+    return sym->toChars();
+}
+
+Type *TypeStruct::syntaxCopy()
+{
+    return this;
+}
+
+Type *TypeStruct::semantic(Loc loc, Scope *sc)
+{
+    //printf("TypeStruct::semantic('%s')\n", sym->toChars());
+
+    /* Cannot do semantic for sym because scope chain may not
+     * be right.
+     */
+    //sym->semantic(sc);
+
+    return merge();
+}
+
+d_uns64 TypeStruct::size(Loc loc)
+{
+    return sym->size(loc);
+}
+
+unsigned TypeStruct::alignsize()
+{   unsigned sz;
+
+    sym->size(0);		// give error for forward references
+    sz = sym->alignsize;
+    if (sz > sym->structalign)
+	sz = sym->structalign;
+    return sz;
+}
+
+Dsymbol *TypeStruct::toDsymbol(Scope *sc)
+{
+    return sym;
+}
+
+void TypeStruct::toDecoBuffer(OutBuffer *buf)
+{   unsigned len;
+    char *name;
+
+    name = sym->mangle();
+    //printf("TypeStruct::toDecoBuffer('%s') = '%s'\n", toChars(), name);
+//    if (name[0] == '_' && name[1] == 'D')
+//	name += 2;
+    //len = strlen(name);
+    //buf->printf("%c%d%s", mangleChar[ty], len, name);
+    buf->printf("%c%s", mangleChar[ty], name);
+}
+
+void TypeStruct::toTypeInfoBuffer(OutBuffer *buf)
+{
+    toDecoBuffer(buf);
+}
+
+
+void TypeStruct::toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs)
+{
+    buf->prependbyte(' ');
+    buf->prependstring(toChars());
+    if (ident)
+	buf->writestring(ident->toChars());
+}
+
+Expression *TypeStruct::dotExp(Scope *sc, Expression *e, Identifier *ident)
+{   unsigned offset;
+
+    Expression *b;
+    VarDeclaration *v;
+    Dsymbol *s;
+    DotVarExp *de;
+    Declaration *d;
+
+#if LOGDOTEXP
+    printf("TypeStruct::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
+#endif
+    if (!sym->members)
+    {
+	error(e->loc, "struct %s is forward referenced", sym->toChars());
+	return new IntegerExp(e->loc, 0, Type::tint32);
+    }
+
+    if (ident == Id::tupleof)
+    {
+	/* Create a TupleExp
+	 */
+	Expressions *exps = new Expressions;
+	exps->reserve(sym->fields.dim);
+	for (size_t i = 0; i < sym->fields.dim; i++)
+	{   VarDeclaration *v = (VarDeclaration *)sym->fields.data[i];
+	    Expression *fe = new DotVarExp(e->loc, e, v);
+	    exps->push(fe);
+	}
+	e = new TupleExp(e->loc, exps);
+	e = e->semantic(sc);
+	return e;
+    }
+
+    if (e->op == TOKdotexp)
+    {	DotExp *de = (DotExp *)e;
+
+	if (de->e1->op == TOKimport)
+	{
+	    ScopeExp *se = (ScopeExp *)de->e1;
+
+	    s = se->sds->search(e->loc, ident, 0);
+	    e = de->e1;
+	    goto L1;
+	}
+    }
+
+    s = sym->search(e->loc, ident, 0);
+L1:
+    if (!s)
+    {
+	//return getProperty(e->loc, ident);
+	return Type::dotExp(sc, e, ident);
+    }
+    s = s->toAlias();
+
+    v = s->isVarDeclaration();
+    if (v && v->isConst())
+    {	ExpInitializer *ei = v->getExpInitializer();
+
+	if (ei)
+	{   e = ei->exp->copy();	// need to copy it if it's a StringExp
+	    e = e->semantic(sc);
+	    return e;
+	}
+    }
+
+    if (s->getType())
+    {
+	//return new DotTypeExp(e->loc, e, s);
+	return new TypeExp(e->loc, s->getType());
+    }
+
+    EnumMember *em = s->isEnumMember();
+    if (em)
+    {
+	assert(em->value);
+	return em->value->copy();
+    }
+
+    TemplateMixin *tm = s->isTemplateMixin();
+    if (tm)
+    {	Expression *de;
+
+	de = new DotExp(e->loc, e, new ScopeExp(e->loc, tm));
+	de->type = e->type;
+	return de;
+    }
+
+    TemplateDeclaration *td = s->isTemplateDeclaration();
+    if (td)
+    {
+        e = new DotTemplateExp(e->loc, e, td);
+        e->semantic(sc);
+	return e;
+    }
+
+    d = s->isDeclaration();
+#ifdef DEBUG
+    if (!d)
+	printf("d = %s '%s'\n", s->kind(), s->toChars());
+#endif
+    assert(d);
+
+    if (e->op == TOKtype)
+    {	FuncDeclaration *fd = sc->func;
+
+	if (d->needThis() && fd && fd->vthis)
+	{
+	    e = new DotVarExp(e->loc, new ThisExp(e->loc), d);
+	    e = e->semantic(sc);
+	    return e;
+	}
+	if (d->isTupleDeclaration())
+	{
+	    e = new TupleExp(e->loc, d->isTupleDeclaration());
+	    e = e->semantic(sc);
+	    return e;
+	}
+	return new VarExp(e->loc, d);
+    }
+
+    if (d->isDataseg())
+    {
+	// (e, d)
+	VarExp *ve;
+
+	accessCheck(e->loc, sc, e, d);
+	ve = new VarExp(e->loc, d);
+	e = new CommaExp(e->loc, e, ve);
+	e->type = d->type;
+	return e;
+    }
+
+    if (v)
+    {
+	if (v->toParent() != sym)
+	    sym->error(e->loc, "'%s' is not a member", v->toChars());
+
+	// *(&e + offset)
+	accessCheck(e->loc, sc, e, d);
+	b = new AddrExp(e->loc, e);
+	b->type = e->type->pointerTo();
+	b = new AddExp(e->loc, b, new IntegerExp(e->loc, v->offset, Type::tint32));
+	b->type = v->type->pointerTo();
+	e = new PtrExp(e->loc, b);
+	e->type = v->type;
+	return e;
+    }
+
+    de = new DotVarExp(e->loc, e, d);
+    return de->semantic(sc);
+}
+
+unsigned TypeStruct::memalign(unsigned salign)
+{
+    sym->size(0);		// give error for forward references
+    return sym->structalign;
+}
+
+Expression *TypeStruct::defaultInit()
+{   Symbol *s;
+    Declaration *d;
+
+#if LOGDEFAULTINIT
+    printf("TypeStruct::defaultInit() '%s'\n", toChars());
+#endif
+    s = sym->toInitializer();
+    d = new SymbolDeclaration(sym->loc, s, sym);
+    assert(d);
+    d->type = this;
+    return new VarExp(sym->loc, d);
+}
+
+int TypeStruct::isZeroInit()
+{
+    return sym->zeroInit;
+}
+
+int TypeStruct::checkBoolean()
+{
+    return FALSE;
+}
+
+int TypeStruct::hasPointers()
+{
+    StructDeclaration *s = sym;
+
+    sym->size(0);		// give error for forward references
+    if (s->members)
+    {
+	for (size_t i = 0; i < s->members->dim; i++)
+	{
+	    Dsymbol *sm = (Dsymbol *)s->members->data[i];
+	    if (sm->hasPointers())
+		return TRUE;
+	}
+    }
+    return FALSE;
+}
+
+
+/***************************** TypeClass *****************************/
+
+TypeClass::TypeClass(ClassDeclaration *sym)
+	: Type(Tclass, NULL)
+{
+    this->sym = sym;
+    llvmInit = 0;
+}
+
+char *TypeClass::toChars()
+{
+    return sym->toPrettyChars();
+}
+
+Type *TypeClass::syntaxCopy()
+{
+    return this;
+}
+
+Type *TypeClass::semantic(Loc loc, Scope *sc)
+{
+    //printf("TypeClass::semantic(%s)\n", sym->toChars());
+    if (sym->scope)
+	sym->semantic(sym->scope);
+    return merge();
+}
+
+d_uns64 TypeClass::size(Loc loc)
+{
+    return PTRSIZE;
+}
+
+Dsymbol *TypeClass::toDsymbol(Scope *sc)
+{
+    return sym;
+}
+
+void TypeClass::toDecoBuffer(OutBuffer *buf)
+{   unsigned len;
+    char *name;
+
+    name = sym->mangle();
+//    if (name[0] == '_' && name[1] == 'D')
+//	name += 2;
+    //printf("TypeClass::toDecoBuffer('%s') = '%s'\n", toChars(), name);
+    //len = strlen(name);
+    //buf->printf("%c%d%s", mangleChar[ty], len, name);
+    buf->printf("%c%s", mangleChar[ty], name);
+}
+
+void TypeClass::toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs)
+{
+    buf->prependstring(sym->toChars());
+    if (ident)
+    {	buf->writeByte(' ');
+	buf->writestring(ident->toChars());
+    }
+}
+
+Expression *TypeClass::dotExp(Scope *sc, Expression *e, Identifier *ident)
+{   unsigned offset;
+
+    Expression *b;
+    VarDeclaration *v;
+    Dsymbol *s;
+    DotVarExp *de;
+    Declaration *d;
+
+#if LOGDOTEXP
+    printf("TypeClass::dotExp(e='%s', ident='%s')\n", e->toChars(), ident->toChars());
+#endif
+
+    if (e->op == TOKdotexp)
+    {	DotExp *de = (DotExp *)e;
+
+	if (de->e1->op == TOKimport)
+	{
+	    ScopeExp *se = (ScopeExp *)de->e1;
+
+	    s = se->sds->search(e->loc, ident, 0);
+	    e = de->e1;
+	    goto L1;
+	}
+    }
+
+    if (ident == Id::tupleof)
+    {
+	/* Create a TupleExp
+	 */
+	Expressions *exps = new Expressions;
+	exps->reserve(sym->fields.dim);
+	for (size_t i = 0; i < sym->fields.dim; i++)
+	{   VarDeclaration *v = (VarDeclaration *)sym->fields.data[i];
+	    Expression *fe = new DotVarExp(e->loc, e, v);
+	    exps->push(fe);
+	}
+	e = new TupleExp(e->loc, exps);
+	e = e->semantic(sc);
+	return e;
+    }
+
+    s = sym->search(e->loc, ident, 0);
+L1:
+    if (!s)
+    {
+	// See if it's a base class
+	ClassDeclaration *cbase;
+	for (cbase = sym->baseClass; cbase; cbase = cbase->baseClass)
+	{
+	    if (cbase->ident->equals(ident))
+	    {
+		e = new DotTypeExp(0, e, cbase);
+		return e;
+	    }
+	}
+
+	if (ident == Id::classinfo)
+	{
+	    Type *t;
+
+	    assert(ClassDeclaration::classinfo);
+	    t = ClassDeclaration::classinfo->type;
+	    if (e->op == TOKtype || e->op == TOKdottype)
+	    {
+		if (!sym->vclassinfo)
+		    sym->vclassinfo = new ClassInfoDeclaration(sym);
+		e = new VarExp(e->loc, sym->vclassinfo);
+		e = e->addressOf(sc);
+		e->type = t;	// do this so we don't get redundant dereference
+	    }
+	    else
+	    {
+		e = new PtrExp(e->loc, e);
+		e->type = t->pointerTo();
+		if (sym->isInterfaceDeclaration())
+		{
+		    if (sym->isCOMclass())
+			error(e->loc, "no .classinfo for COM interface objects");
+		    e->type = e->type->pointerTo();
+		    e = new PtrExp(e->loc, e);
+		    e->type = t->pointerTo();
+		}
+		e = new PtrExp(e->loc, e, t);
+	    }
+	    return e;
+	}
+
+	if (ident == Id::typeinfo)
+	{
+	    if (!global.params.useDeprecated)
+		error(e->loc, ".typeinfo deprecated, use typeid(type)");
+	    return getTypeInfo(sc);
+	}
+	if (ident == Id::outer && sym->vthis)
+	{
+	    s = sym->vthis;
+	}
+	else
+	{
+	    //return getProperty(e->loc, ident);
+	    return Type::dotExp(sc, e, ident);
+	}
+    }
+    s = s->toAlias();
+    v = s->isVarDeclaration();
+    if (v && v->isConst())
+    {	ExpInitializer *ei = v->getExpInitializer();
+
+	if (ei)
+	{   e = ei->exp->copy();	// need to copy it if it's a StringExp
+	    e = e->semantic(sc);
+	    return e;
+	}
+    }
+
+    if (s->getType())
+    {
+//	if (e->op == TOKtype)
+	    return new TypeExp(e->loc, s->getType());
+//	return new DotTypeExp(e->loc, e, s);
+    }
+
+    EnumMember *em = s->isEnumMember();
+    if (em)
+    {
+	assert(em->value);
+	return em->value->copy();
+    }
+
+    TemplateMixin *tm = s->isTemplateMixin();
+    if (tm)
+    {	Expression *de;
+
+	de = new DotExp(e->loc, e, new ScopeExp(e->loc, tm));
+	de->type = e->type;
+	return de;
+    }
+
+    TemplateDeclaration *td = s->isTemplateDeclaration();
+    if (td)
+    {
+        e = new DotTemplateExp(e->loc, e, td);
+        e->semantic(sc);
+	return e;
+    }
+
+    d = s->isDeclaration();
+    if (!d)
+    {
+	e->error("%s.%s is not a declaration", e->toChars(), ident->toChars());
+	return new IntegerExp(e->loc, 1, Type::tint32);
+    }
+
+    if (e->op == TOKtype)
+    {
+	VarExp *ve;
+
+	if (d->needThis() && (hasThis(sc) || !d->isFuncDeclaration()))
+	{
+	    if (sc->func)
+	    {
+		ClassDeclaration *thiscd;
+		thiscd = sc->func->toParent()->isClassDeclaration();
+
+		if (thiscd)
+		{
+		    ClassDeclaration *cd = e->type->isClassHandle();
+
+		    if (cd == thiscd)
+		    {
+			e = new ThisExp(e->loc);
+			e = new DotTypeExp(e->loc, e, cd);
+			de = new DotVarExp(e->loc, e, d);
+			e = de->semantic(sc);
+			return e;
+		    }
+		    else if ((!cd || !cd->isBaseOf(thiscd, NULL)) &&
+			     !d->isFuncDeclaration())
+			e->error("'this' is required, but %s is not a base class of %s", e->type->toChars(), thiscd->toChars());
+		}
+	    }
+
+	    de = new DotVarExp(e->loc, new ThisExp(e->loc), d);
+	    e = de->semantic(sc);
+	    return e;
+	}
+	else if (d->isTupleDeclaration())
+	{
+	    e = new TupleExp(e->loc, d->isTupleDeclaration());
+	    e = e->semantic(sc);
+	    return e;
+	}
+	else
+	    ve = new VarExp(e->loc, d);
+	return ve;
+    }
+
+    if (d->isDataseg())
+    {
+	// (e, d)
+	VarExp *ve;
+
+	accessCheck(e->loc, sc, e, d);
+	ve = new VarExp(e->loc, d);
+	e = new CommaExp(e->loc, e, ve);
+	e->type = d->type;
+	return e;
+    }
+
+    if (d->parent && d->toParent()->isModule())
+    {
+	// (e, d)
+	VarExp *ve;
+
+	ve = new VarExp(e->loc, d);
+	e = new CommaExp(e->loc, e, ve);
+	e->type = d->type;
+	return e;
+    }
+
+    de = new DotVarExp(e->loc, e, d);
+    return de->semantic(sc);
+}
+
+ClassDeclaration *TypeClass::isClassHandle()
+{
+    return sym;
+}
+
+int TypeClass::isauto()
+{
+    return sym->isauto;
+}
+
+int TypeClass::isBaseOf(Type *t, int *poffset)
+{
+    if (t->ty == Tclass)
+    {   ClassDeclaration *cd;
+
+	cd   = ((TypeClass *)t)->sym;
+	if (sym->isBaseOf(cd, poffset))
+	    return 1;
+    }
+    return 0;
+}
+
+MATCH TypeClass::implicitConvTo(Type *to)
+{
+    //printf("TypeClass::implicitConvTo('%s')\n", to->toChars());
+    if (this == to)
+	return MATCHexact;
+
+    ClassDeclaration *cdto = to->isClassHandle();
+    if (cdto && cdto->isBaseOf(sym, NULL))
+    {	//printf("is base\n");
+	return MATCHconvert;
+    }
+
+    if (global.params.Dversion == 1)
+    {
+	// Allow conversion to (void *)
+	if (to->ty == Tpointer && to->next->ty == Tvoid)
+	    return MATCHconvert;
+    }
+
+    return MATCHnomatch;
+}
+
+Expression *TypeClass::defaultInit()
+{
+#if LOGDEFAULTINIT
+    printf("TypeClass::defaultInit() '%s'\n", toChars());
+#endif
+    Expression *e;
+    e = new NullExp(0);
+    e->type = this;
+    return e;
+}
+
+int TypeClass::isZeroInit()
+{
+    return 1;
+}
+
+int TypeClass::checkBoolean()
+{
+    return TRUE;
+}
+
+int TypeClass::hasPointers()
+{
+    return TRUE;
+}
+
+/***************************** TypeTuple *****************************/
+
+TypeTuple::TypeTuple(Arguments *arguments)
+    : Type(Ttuple, NULL)
+{
+    //printf("TypeTuple(this = %p)\n", this);
+    this->arguments = arguments;
+#ifdef DEBUG
+    if (arguments)
+    {
+	for (size_t i = 0; i < arguments->dim; i++)
+	{
+	    Argument *arg = (Argument *)arguments->data[i];
+	    assert(arg && arg->type);
+	}
+    }
+#endif
+}
+
+/****************
+ * Form TypeTuple from the types of the expressions.
+ * Assume exps[] is already tuple expanded.
+ */
+
+TypeTuple::TypeTuple(Expressions *exps)
+    : Type(Ttuple, NULL)
+{
+    Arguments *arguments = new Arguments;
+    if (exps)
+    {
+	arguments->setDim(exps->dim);
+	for (size_t i = 0; i < exps->dim; i++)
+	{   Expression *e = (Expression *)exps->data[i];
+	    if (e->type->ty == Ttuple)
+		e->error("cannot form tuple of tuples");
+	    Argument *arg = new Argument(STCin, e->type, NULL, NULL);
+	    arguments->data[i] = (void *)arg;
+	}
+    }
+    this->arguments = arguments;
+}
+
+Type *TypeTuple::syntaxCopy()
+{
+    Arguments *args = Argument::arraySyntaxCopy(arguments);
+    Type *t = new TypeTuple(args);
+    return t;
+}
+
+Type *TypeTuple::semantic(Loc loc, Scope *sc)
+{
+    //printf("TypeTuple::semantic(this = %p)\n", this);
+    if (!deco)
+	deco = merge()->deco;
+
+    /* Don't return merge(), because a tuple with one type has the
+     * same deco as that type.
+     */
+    return this;
+}
+
+int TypeTuple::equals(Object *o)
+{   Type *t;
+
+    t = (Type *)o;
+    //printf("TypeTuple::equals(%s, %s)\n", toChars(), t->toChars());
+    if (this == t)
+    {
+	return 1;
+    }
+    if (t->ty == Ttuple)
+    {	TypeTuple *tt = (TypeTuple *)t;
+
+	if (arguments->dim == tt->arguments->dim)
+	{
+	    for (size_t i = 0; i < tt->arguments->dim; i++)
+	    {   Argument *arg1 = (Argument *)arguments->data[i];
+		Argument *arg2 = (Argument *)tt->arguments->data[i];
+
+		if (!arg1->type->equals(arg2->type))
+		    return 0;
+	    }
+	    return 1;
+	}
+    }
+    return 0;
+}
+
+Type *TypeTuple::reliesOnTident()
+{
+    if (arguments)
+    {
+	for (size_t i = 0; i < arguments->dim; i++)
+	{
+	    Argument *arg = (Argument *)arguments->data[i];
+	    Type *t = arg->type->reliesOnTident();
+	    if (t)
+		return t;
+	}
+    }
+    return NULL;
+}
+
+void TypeTuple::toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs)
+{
+    OutBuffer buf2;
+    Argument::argsToCBuffer(&buf2, hgs, arguments, 0);
+    buf->prependstring(buf2.toChars());
+    if (ident)
+    {	buf->writeByte(' ');
+	buf->writestring(ident->toChars());
+    }
+}
+
+void TypeTuple::toDecoBuffer(OutBuffer *buf)
+{
+    //printf("TypeTuple::toDecoBuffer() this = %p\n", this);
+    OutBuffer buf2;
+    Argument::argsToDecoBuffer(&buf2, arguments);
+    unsigned len = buf2.offset;
+    buf->printf("%c%d%.*s", mangleChar[ty], len, len, (char *)buf2.extractData());
+}
+
+Expression *TypeTuple::getProperty(Loc loc, Identifier *ident)
+{   Expression *e;
+
+#if LOGDOTEXP
+    printf("TypeTuple::getProperty(type = '%s', ident = '%s')\n", toChars(), ident->toChars());
+#endif
+    if (ident == Id::length)
+    {
+	e = new IntegerExp(loc, arguments->dim, Type::tsize_t);
+    }
+    else
+    {
+	error(loc, "no property '%s' for tuple '%s'", ident->toChars(), toChars());
+	e = new IntegerExp(loc, 1, Type::tint32);
+    }
+    return e;
+}
+
+/***************************** TypeSlice *****************************/
+
+/* This is so we can slice a TypeTuple */
+
+TypeSlice::TypeSlice(Type *next, Expression *lwr, Expression *upr)
+    : Type(Tslice, next)
+{
+    //printf("TypeSlice[%s .. %s]\n", lwr->toChars(), upr->toChars());
+    this->lwr = lwr;
+    this->upr = upr;
+}
+
+Type *TypeSlice::syntaxCopy()
+{
+    Type *t = new TypeSlice(next->syntaxCopy(), lwr->syntaxCopy(), upr->syntaxCopy());
+    return t;
+}
+
+Type *TypeSlice::semantic(Loc loc, Scope *sc)
+{
+    //printf("TypeSlice::semantic() %s\n", toChars());
+    next = next->semantic(loc, sc);
+    //printf("next: %s\n", next->toChars());
+
+    Type *tbn = next->toBasetype();
+    if (tbn->ty != Ttuple)
+    {	error(loc, "can only slice tuple types, not %s", tbn->toChars());
+	return Type::terror;
+    }
+    TypeTuple *tt = (TypeTuple *)tbn;
+
+    lwr = semanticLength(sc, tbn, lwr);
+    lwr = lwr->optimize(WANTvalue);
+    uinteger_t i1 = lwr->toUInteger();
+
+    upr = semanticLength(sc, tbn, upr);
+    upr = upr->optimize(WANTvalue);
+    uinteger_t i2 = upr->toUInteger();
+
+    if (!(i1 <= i2 && i2 <= tt->arguments->dim))
+    {	error(loc, "slice [%ju..%ju] is out of range of [0..%u]", i1, i2, tt->arguments->dim);
+	return Type::terror;
+    }
+
+    Arguments *args = new Arguments;
+    args->reserve(i2 - i1);
+    for (size_t i = i1; i < i2; i++)
+    {	Argument *arg = (Argument *)tt->arguments->data[i];
+	args->push(arg);
+    }
+
+    return new TypeTuple(args);
+}
+
+void TypeSlice::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps)
+{
+    next->resolve(loc, sc, pe, pt, ps);
+    if (*pe)
+    {	// It's really a slice expression
+	Expression *e;
+	e = new SliceExp(loc, *pe, lwr, upr);
+	*pe = e;
+    }
+    else if (*ps)
+    {	Dsymbol *s = *ps;
+	TupleDeclaration *td = s->isTupleDeclaration();
+	if (td)
+	{
+	    /* It's a slice of a TupleDeclaration
+	     */
+	    ScopeDsymbol *sym = new ArrayScopeSymbol(td);
+	    sym->parent = sc->scopesym;
+	    sc = sc->push(sym);
+
+	    lwr = lwr->semantic(sc);
+	    lwr = lwr->optimize(WANTvalue);
+	    uinteger_t i1 = lwr->toUInteger();
+
+	    upr = upr->semantic(sc);
+	    upr = upr->optimize(WANTvalue);
+	    uinteger_t i2 = upr->toUInteger();
+
+	    sc = sc->pop();
+
+	    if (!(i1 <= i2 && i2 <= td->objects->dim))
+	    {   error(loc, "slice [%ju..%ju] is out of range of [0..%u]", i1, i2, td->objects->dim);
+		goto Ldefault;
+	    }
+
+	    if (i1 == 0 && i2 == td->objects->dim)
+	    {
+		*ps = td;
+		return;
+	    }
+
+	    /* Create a new TupleDeclaration which
+	     * is a slice [i1..i2] out of the old one.
+	     */
+	    Objects *objects = new Objects;
+	    objects->setDim(i2 - i1);
+	    for (size_t i = 0; i < objects->dim; i++)
+	    {
+		objects->data[i] = td->objects->data[(size_t)i1 + i];
+	    }
+
+	    TupleDeclaration *tds = new TupleDeclaration(loc, td->ident, objects);
+	    *ps = tds;
+	}
+	else
+	    goto Ldefault;
+    }
+    else
+    {
+     Ldefault:
+	Type::resolve(loc, sc, pe, pt, ps);
+    }
+}
+
+void TypeSlice::toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs)
+{
+    OutBuffer buf2;
+
+    buf2.printf("[%s .. ", lwr->toChars());
+    buf2.printf("%s]", upr->toChars());
+
+    buf->prependstring(buf2.toChars());
+    if (ident)
+    {
+	buf->writeByte(' ');
+	buf->writestring(ident->toChars());
+    }
+    next->toCBuffer2(buf, NULL, hgs);
+}
+
+/***************************** Argument *****************************/
+
+Argument::Argument(unsigned storageClass, Type *type, Identifier *ident, Expression *defaultArg)
+{
+    this->type = type;
+    this->ident = ident;
+    this->storageClass = storageClass;
+    this->defaultArg = defaultArg;
+    this->llvmCopy = false;
+    this->vardecl = 0;
+}
+
+Argument *Argument::syntaxCopy()
+{
+    Argument *a = new Argument(storageClass,
+		type ? type->syntaxCopy() : NULL,
+		ident,
+		defaultArg ? defaultArg->syntaxCopy() : NULL);
+    return a;
+}
+
+Arguments *Argument::arraySyntaxCopy(Arguments *args)
+{   Arguments *a = NULL;
+
+    if (args)
+    {
+	a = new Arguments();
+	a->setDim(args->dim);
+	for (size_t i = 0; i < a->dim; i++)
+	{   Argument *arg = (Argument *)args->data[i];
+
+	    arg = arg->syntaxCopy();
+	    a->data[i] = (void *)arg;
+	}
+    }
+    return a;
+}
+
+char *Argument::argsTypesToChars(Arguments *args, int varargs)
+{   OutBuffer *buf;
+
+    buf = new OutBuffer();
+
+    buf->writeByte('(');
+    if (args)
+    {	int i;
+	OutBuffer argbuf;
+	HdrGenState hgs;
+
+	for (i = 0; i < args->dim; i++)
+	{   Argument *arg;
+
+	    if (i)
+		buf->writeByte(',');
+	    arg = (Argument *)args->data[i];
+	    argbuf.reset();
+	    arg->type->toCBuffer2(&argbuf, NULL, &hgs);
+	    buf->write(&argbuf);
+	}
+	if (varargs)
+	{
+	    if (i && varargs == 1)
+		buf->writeByte(',');
+	    buf->writestring("...");
+	}
+    }
+    buf->writeByte(')');
+
+    return buf->toChars();
+}
+
+void Argument::argsToCBuffer(OutBuffer *buf, HdrGenState *hgs, Arguments *arguments, int varargs)
+{
+    buf->writeByte('(');
+    if (arguments)
+    {	int i;
+	OutBuffer argbuf;
+
+	for (i = 0; i < arguments->dim; i++)
+	{   Argument *arg;
+
+	    if (i)
+		buf->writestring(", ");
+	    arg = (Argument *)arguments->data[i];
+	    if (arg->storageClass & STCout)
+		buf->writestring("out ");
+	    else if (arg->storageClass & STCref)
+		buf->writestring((global.params.Dversion == 1)
+			? (char *)"inout " : (char *)"ref ");
+	    else if (arg->storageClass & STClazy)
+		buf->writestring("lazy ");
+	    argbuf.reset();
+	    arg->type->toCBuffer2(&argbuf, arg->ident, hgs);
+	    if (arg->defaultArg)
+	    {
+		argbuf.writestring(" = ");
+		arg->defaultArg->toCBuffer(&argbuf, hgs);
+	    }
+	    buf->write(&argbuf);
+	}
+	if (varargs)
+	{
+	    if (i && varargs == 1)
+		buf->writeByte(',');
+	    buf->writestring("...");
+	}
+    }
+    buf->writeByte(')');
+}
+
+
+void Argument::argsToDecoBuffer(OutBuffer *buf, Arguments *arguments)
+{
+    //printf("Argument::argsToDecoBuffer()\n");
+
+    // Write argument types
+    if (arguments)
+    {
+	size_t dim = Argument::dim(arguments);
+	for (size_t i = 0; i < dim; i++)
+	{
+	    Argument *arg = Argument::getNth(arguments, i);
+	    arg->toDecoBuffer(buf);
+	}
+    }
+}
+
+/****************************************************
+ * Determine if parameter is a lazy array of delegates.
+ * If so, return the return type of those delegates.
+ * If not, return NULL.
+ */
+
+Type *Argument::isLazyArray()
+{
+//    if (inout == Lazy)
+    {
+	Type *tb = type->toBasetype();
+	if (tb->ty == Tsarray || tb->ty == Tarray)
+	{
+	    Type *tel = tb->next->toBasetype();
+	    if (tel->ty == Tdelegate)
+	    {
+		TypeDelegate *td = (TypeDelegate *)tel;
+		TypeFunction *tf = (TypeFunction *)td->next;
+
+		if (!tf->varargs && Argument::dim(tf->parameters) == 0)
+		{
+		    return tf->next;	// return type of delegate
+		}
+	    }
+	}
+    }
+    return NULL;
+}
+
+void Argument::toDecoBuffer(OutBuffer *buf)
+{
+    switch (storageClass & (STCin | STCout | STCref | STClazy))
+    {   case 0:
+	case STCin:
+	    break;
+	case STCout:
+	    buf->writeByte('J');
+	    break;
+	case STCref:
+	    buf->writeByte('K');
+	    break;
+	case STClazy:
+	    buf->writeByte('L');
+	    break;
+	default:
+#ifdef DEBUG
+	    halt();
+#endif
+	    assert(0);
+    }
+    type->toDecoBuffer(buf);
+}
+
+/***************************************
+ * Determine number of arguments, folding in tuples.
+ */
+
+size_t Argument::dim(Arguments *args)
+{
+    size_t n = 0;
+    if (args)
+    {
+	for (size_t i = 0; i < args->dim; i++)
+	{   Argument *arg = (Argument *)args->data[i];
+	    Type *t = arg->type->toBasetype();
+
+	    if (t->ty == Ttuple)
+	    {   TypeTuple *tu = (TypeTuple *)t;
+		n += dim(tu->arguments);
+	    }
+	    else
+		n++;
+	}
+    }
+    return n;
+}
+
+/***************************************
+ * Get nth Argument, folding in tuples.
+ * Returns:
+ *	Argument*	nth Argument
+ *	NULL		not found, *pn gets incremented by the number
+ *			of Arguments
+ */
+
+Argument *Argument::getNth(Arguments *args, size_t nth, size_t *pn)
+{
+    if (!args)
+	return NULL;
+
+    size_t n = 0;
+    for (size_t i = 0; i < args->dim; i++)
+    {   Argument *arg = (Argument *)args->data[i];
+	Type *t = arg->type->toBasetype();
+
+	if (t->ty == Ttuple)
+	{   TypeTuple *tu = (TypeTuple *)t;
+	    arg = getNth(tu->arguments, nth - n, &n);
+	    if (arg)
+		return arg;
+	}
+	else if (n == nth)
+	    return arg;
+	else
+	    n++;
+    }
+
+    if (pn)
+	*pn += n;
+    return NULL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/mtype.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,705 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#ifndef DMD_MTYPE_H
+#define DMD_MTYPE_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include "root.h"
+#include "stringtable.h"
+
+#include "arraytypes.h"
+#include "expression.h"
+
+namespace llvm
+{
+    class Value;
+    class Type;
+    class Instruction;
+}
+
+struct Scope;
+struct Identifier;
+struct Expression;
+struct StructDeclaration;
+struct ClassDeclaration;
+struct VarDeclaration;
+struct EnumDeclaration;
+struct TypedefDeclaration;
+struct TypeInfoDeclaration;
+struct Dsymbol;
+struct TemplateInstance;
+enum LINK;
+
+struct TypeBasic;
+struct HdrGenState;
+
+// Back end
+#if IN_GCC
+union tree_node; typedef union tree_node TYPE;
+typedef TYPE type;
+#else
+typedef struct TYPE type;
+#endif
+struct Symbol;
+
+enum TY
+{
+    Tarray,		// dynamic array
+    Tsarray,		// static array
+    Taarray,		// associative array
+    Tpointer,
+    Treference,
+    Tfunction,
+    Tident,
+    Tclass,
+    Tstruct,
+    Tenum,
+    Ttypedef,
+    Tdelegate,
+
+    Tnone,
+    Tvoid,
+    Tint8,
+    Tuns8,
+    Tint16,
+    Tuns16,
+    Tint32,
+    Tuns32,
+    Tint64,
+    Tuns64,
+    Tfloat32,
+    Tfloat64,
+    Tfloat80,
+
+    Timaginary32,
+    Timaginary64,
+    Timaginary80,
+
+    Tcomplex32,
+    Tcomplex64,
+    Tcomplex80,
+
+    Tbit,
+    Tbool,
+    Tchar,
+    Twchar,
+    Tdchar,
+
+    Terror,
+    Tinstance,
+    Ttypeof,
+    Ttuple,
+    Tslice,
+    TMAX
+};
+
+#define Tascii Tchar
+
+extern int Tsize_t;
+extern int Tptrdiff_t;
+
+struct Type : Object
+{
+    TY ty;
+    Type *next;
+    char *deco;
+    Type *pto;		// merged pointer to this type
+    Type *rto;		// reference to this type
+    Type *arrayof;	// array of this type
+    TypeInfoDeclaration *vtinfo;	// TypeInfo object for this Type
+
+    type *ctype;	// for back end
+
+    #define tvoid	basic[Tvoid]
+    #define tint8	basic[Tint8]
+    #define tuns8	basic[Tuns8]
+    #define tint16	basic[Tint16]
+    #define tuns16	basic[Tuns16]
+    #define tint32	basic[Tint32]
+    #define tuns32	basic[Tuns32]
+    #define tint64	basic[Tint64]
+    #define tuns64	basic[Tuns64]
+    #define tfloat32	basic[Tfloat32]
+    #define tfloat64	basic[Tfloat64]
+    #define tfloat80	basic[Tfloat80]
+
+    #define timaginary32 basic[Timaginary32]
+    #define timaginary64 basic[Timaginary64]
+    #define timaginary80 basic[Timaginary80]
+
+    #define tcomplex32	basic[Tcomplex32]
+    #define tcomplex64	basic[Tcomplex64]
+    #define tcomplex80	basic[Tcomplex80]
+
+    #define tbit	basic[Tbit]
+    #define tbool	basic[Tbool]
+    #define tchar	basic[Tchar]
+    #define twchar	basic[Twchar]
+    #define tdchar	basic[Tdchar]
+
+    // Some special types
+    #define tshiftcnt	tint32		// right side of shift expression
+//    #define tboolean	tint32		// result of boolean expression
+    #define tboolean	tbool		// result of boolean expression
+    #define tindex	tint32		// array/ptr index
+    static Type *tvoidptr;		// void*
+    #define terror	basic[Terror]	// for error recovery
+
+    #define tsize_t	basic[Tsize_t]		// matches size_t alias
+    #define tptrdiff_t	basic[Tptrdiff_t]	// matches ptrdiff_t alias
+    #define thash_t	tsize_t			// matches hash_t alias
+
+    static ClassDeclaration *typeinfo;
+    static ClassDeclaration *typeinfoclass;
+    static ClassDeclaration *typeinfointerface;
+    static ClassDeclaration *typeinfostruct;
+    static ClassDeclaration *typeinfotypedef;
+    static ClassDeclaration *typeinfopointer;
+    static ClassDeclaration *typeinfoarray;
+    static ClassDeclaration *typeinfostaticarray;
+    static ClassDeclaration *typeinfoassociativearray;
+    static ClassDeclaration *typeinfoenum;
+    static ClassDeclaration *typeinfofunction;
+    static ClassDeclaration *typeinfodelegate;
+    static ClassDeclaration *typeinfotypelist;
+
+    static Type *basic[TMAX];
+    static unsigned char mangleChar[TMAX];
+    static StringTable stringtable;
+
+    // These tables are for implicit conversion of binary ops;
+    // the indices are the type of operand one, followed by operand two.
+    static unsigned char impcnvResult[TMAX][TMAX];
+    static unsigned char impcnvType1[TMAX][TMAX];
+    static unsigned char impcnvType2[TMAX][TMAX];
+
+    // If !=0, give warning on implicit conversion
+    static unsigned char impcnvWarn[TMAX][TMAX];
+
+    Type(TY ty, Type *next);
+    virtual Type *syntaxCopy();
+    int equals(Object *o);
+    int dyncast() { return DYNCAST_TYPE; } // kludge for template.isType()
+    int covariant(Type *t);
+    char *toChars();
+    static char needThisPrefix();
+    static void init();
+    d_uns64 size();
+    virtual d_uns64 size(Loc loc);
+    virtual unsigned alignsize();
+    virtual Type *semantic(Loc loc, Scope *sc);
+    virtual void toDecoBuffer(OutBuffer *buf);
+    virtual void toTypeInfoBuffer(OutBuffer *buf);
+    Type *merge();
+    void toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs);
+    virtual void toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs);
+    virtual int isbit();
+    virtual int isintegral();
+    virtual int isfloating();	// real, imaginary, or complex
+    virtual int isreal();
+    virtual int isimaginary();
+    virtual int iscomplex();
+    virtual int isscalar();
+    virtual int isunsigned();
+    virtual int isauto();
+    virtual int isString();
+    virtual int checkBoolean();	// if can be converted to boolean value
+    void checkDeprecated(Loc loc, Scope *sc);
+    Type *pointerTo();
+    Type *referenceTo();
+    Type *arrayOf();
+    virtual Dsymbol *toDsymbol(Scope *sc);
+    virtual Type *toBasetype();
+    virtual int isBaseOf(Type *t, int *poffset);
+    virtual MATCH implicitConvTo(Type *to);
+    virtual ClassDeclaration *isClassHandle();
+    virtual Expression *getProperty(Loc loc, Identifier *ident);
+    virtual Expression *dotExp(Scope *sc, Expression *e, Identifier *ident);
+    virtual unsigned memalign(unsigned salign);
+    virtual Expression *defaultInit();
+    virtual int isZeroInit();		// if initializer is 0
+    virtual dt_t **toDt(dt_t **pdt);
+    Identifier *getTypeInfoIdent(int internal);
+    virtual MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes);
+    virtual void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps);
+    Expression *getInternalTypeInfo(Scope *sc);
+    Expression *getTypeInfo(Scope *sc);
+    virtual TypeInfoDeclaration *getTypeInfoDeclaration();
+    virtual int builtinTypeInfo();
+    virtual Type *reliesOnTident();
+    virtual Expression *toExpression();
+    virtual int hasPointers();
+    Type *nextOf() { return next; }
+
+    static void error(Loc loc, const char *format, ...);
+
+    // For backend
+    virtual unsigned totym();
+    virtual type *toCtype();
+    virtual type *toCParamtype();
+    virtual Symbol *toSymbol();
+
+    llvm::Type* llvmType;
+
+    // For eliminating dynamic_cast
+    virtual TypeBasic *isTypeBasic();
+};
+
+struct TypeBasic : Type
+{
+    char *dstring;
+    char *cstring;
+    unsigned flags;
+
+    TypeBasic(TY ty);
+    Type *syntaxCopy();
+    d_uns64 size(Loc loc);
+    unsigned alignsize();
+    Expression *getProperty(Loc loc, Identifier *ident);
+    Expression *dotExp(Scope *sc, Expression *e, Identifier *ident);
+    char *toChars();
+    void toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs);
+    int isintegral();
+    int isbit();
+    int isfloating();
+    int isreal();
+    int isimaginary();
+    int iscomplex();
+    int isscalar();
+    int isunsigned();
+    MATCH implicitConvTo(Type *to);
+    Expression *defaultInit();
+    int isZeroInit();
+    int builtinTypeInfo();
+
+    // For eliminating dynamic_cast
+    TypeBasic *isTypeBasic();
+};
+
+struct TypeArray : Type
+{
+    TypeArray(TY ty, Type *next);
+    virtual void toPrettyBracket(OutBuffer *buf, HdrGenState *hgs) = 0;
+    void toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs);
+    Expression *dotExp(Scope *sc, Expression *e, Identifier *ident);
+};
+
+// Static array, one with a fixed dimension
+struct TypeSArray : TypeArray
+{
+    Expression *dim;
+
+    TypeSArray(Type *t, Expression *dim);
+    Type *syntaxCopy();
+    d_uns64 size(Loc loc);
+    unsigned alignsize();
+    Type *semantic(Loc loc, Scope *sc);
+    void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps);
+    void toDecoBuffer(OutBuffer *buf);
+    void toTypeInfoBuffer(OutBuffer *buf);
+    void toPrettyBracket(OutBuffer *buf, HdrGenState *hgs);
+    Expression *dotExp(Scope *sc, Expression *e, Identifier *ident);
+    int isString();
+    int isZeroInit();
+    unsigned memalign(unsigned salign);
+    MATCH implicitConvTo(Type *to);
+    Expression *defaultInit();
+    dt_t **toDt(dt_t **pdt);
+    dt_t **toDtElem(dt_t **pdt, Expression *e);
+    MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes);
+    TypeInfoDeclaration *getTypeInfoDeclaration();
+    Expression *toExpression();
+    int hasPointers();
+
+    type *toCtype();
+    type *toCParamtype();
+};
+
+// Dynamic array, no dimension
+struct TypeDArray : TypeArray
+{
+    TypeDArray(Type *t);
+    Type *syntaxCopy();
+    d_uns64 size(Loc loc);
+    unsigned alignsize();
+    Type *semantic(Loc loc, Scope *sc);
+    void toDecoBuffer(OutBuffer *buf);
+    void toTypeInfoBuffer(OutBuffer *buf);
+    void toPrettyBracket(OutBuffer *buf, HdrGenState *hgs);
+    Expression *dotExp(Scope *sc, Expression *e, Identifier *ident);
+    int isString();
+    int isZeroInit();
+    int checkBoolean();
+    MATCH implicitConvTo(Type *to);
+    Expression *defaultInit();
+    int builtinTypeInfo();
+    TypeInfoDeclaration *getTypeInfoDeclaration();
+    int hasPointers();
+
+    type *toCtype();
+};
+
+struct TypeAArray : TypeArray
+{
+    Type *index;		// key type for type checking
+    Type *key;			// actual key type
+
+    TypeAArray(Type *t, Type *index);
+    Type *syntaxCopy();
+    d_uns64 size(Loc loc);
+    Type *semantic(Loc loc, Scope *sc);
+    void toDecoBuffer(OutBuffer *buf);
+    void toPrettyBracket(OutBuffer *buf, HdrGenState *hgs);
+    Expression *dotExp(Scope *sc, Expression *e, Identifier *ident);
+    Expression *defaultInit();
+    MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes);
+    int checkBoolean();
+    TypeInfoDeclaration *getTypeInfoDeclaration();
+    int hasPointers();
+
+    // Back end
+    Symbol *aaGetSymbol(char *func, int flags);
+
+    type *toCtype();
+};
+
+struct TypePointer : Type
+{
+    TypePointer(Type *t);
+    Type *syntaxCopy();
+    Type *semantic(Loc loc, Scope *sc);
+    d_uns64 size(Loc loc);
+    void toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs);
+    MATCH implicitConvTo(Type *to);
+    int isscalar();
+    Expression *defaultInit();
+    int isZeroInit();
+    TypeInfoDeclaration *getTypeInfoDeclaration();
+    int hasPointers();
+
+    type *toCtype();
+};
+
+struct TypeReference : Type
+{
+    TypeReference(Type *t);
+    Type *syntaxCopy();
+    d_uns64 size(Loc loc);
+    void toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs);
+    Expression *dotExp(Scope *sc, Expression *e, Identifier *ident);
+    Expression *defaultInit();
+    int isZeroInit();
+};
+
+enum RET
+{
+    RETregs	= 1,	// returned in registers
+    RETstack	= 2,	// returned on stack
+};
+
+struct TypeFunction : Type
+{
+    Arguments *parameters;	// function parameters
+    int varargs;	// 1: T t, ...) style for variable number of arguments
+			// 2: T t ...) style for variable number of arguments
+    enum LINK linkage;	// calling convention
+
+    int inuse;
+
+    TypeFunction(Arguments *parameters, Type *treturn, int varargs, enum LINK linkage);
+    Type *syntaxCopy();
+    Type *semantic(Loc loc, Scope *sc);
+    void toDecoBuffer(OutBuffer *buf);
+    void toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs);
+    MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes);
+    TypeInfoDeclaration *getTypeInfoDeclaration();
+    Type *reliesOnTident();
+
+    int callMatch(Expressions *toargs);
+    type *toCtype();
+    enum RET retStyle();
+
+    unsigned totym();
+
+    bool llvmRetInPtr;
+    llvm::Value* llvmRetArg;
+    llvm::Instruction* llvmAllocaPoint;
+};
+
+struct TypeDelegate : Type
+{
+    TypeDelegate(Type *t);
+    Type *syntaxCopy();
+    Type *semantic(Loc loc, Scope *sc);
+    d_uns64 size(Loc loc);
+    void toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs);
+    Expression *defaultInit();
+    int isZeroInit();
+    int checkBoolean();
+    TypeInfoDeclaration *getTypeInfoDeclaration();
+    Expression *dotExp(Scope *sc, Expression *e, Identifier *ident);
+    int hasPointers();
+
+    type *toCtype();
+};
+
+struct TypeQualified : Type
+{
+    Loc loc;
+    Array idents;	// array of Identifier's representing ident.ident.ident etc.
+
+    TypeQualified(TY ty, Loc loc);
+    void syntaxCopyHelper(TypeQualified *t);
+    void addIdent(Identifier *ident);
+    void toCBuffer2Helper(OutBuffer *buf, Identifier *ident, HdrGenState *hgs);
+    d_uns64 size(Loc loc);
+    void resolveHelper(Loc loc, Scope *sc, Dsymbol *s, Dsymbol *scopesym,
+	Expression **pe, Type **pt, Dsymbol **ps);
+};
+
+struct TypeIdentifier : TypeQualified
+{
+    Identifier *ident;
+
+    TypeIdentifier(Loc loc, Identifier *ident);
+    Type *syntaxCopy();
+    //char *toChars();
+    void toDecoBuffer(OutBuffer *buf);
+    void toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs);
+    void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps);
+    Dsymbol *toDsymbol(Scope *sc);
+    Type *semantic(Loc loc, Scope *sc);
+    MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes);
+    Type *reliesOnTident();
+    Expression *toExpression();
+};
+
+/* Similar to TypeIdentifier, but with a TemplateInstance as the root
+ */
+struct TypeInstance : TypeQualified
+{
+    TemplateInstance *tempinst;
+
+    TypeInstance(Loc loc, TemplateInstance *tempinst);
+    Type *syntaxCopy();
+    //char *toChars();
+    //void toDecoBuffer(OutBuffer *buf);
+    void toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs);
+    void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps);
+    Type *semantic(Loc loc, Scope *sc);
+    MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes);
+};
+
+struct TypeTypeof : TypeQualified
+{
+    Expression *exp;
+
+    TypeTypeof(Loc loc, Expression *exp);
+    Type *syntaxCopy();
+    Dsymbol *toDsymbol(Scope *sc);
+    void toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs);
+    Type *semantic(Loc loc, Scope *sc);
+    d_uns64 size(Loc loc);
+};
+
+struct TypeStruct : Type
+{
+    StructDeclaration *sym;
+
+    TypeStruct(StructDeclaration *sym);
+    d_uns64 size(Loc loc);
+    unsigned alignsize();
+    char *toChars();
+    Type *syntaxCopy();
+    Type *semantic(Loc loc, Scope *sc);
+    Dsymbol *toDsymbol(Scope *sc);
+    void toDecoBuffer(OutBuffer *buf);
+    void toTypeInfoBuffer(OutBuffer *buf);
+    void toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs);
+    Expression *dotExp(Scope *sc, Expression *e, Identifier *ident);
+    unsigned memalign(unsigned salign);
+    Expression *defaultInit();
+    int isZeroInit();
+    int checkBoolean();
+    dt_t **toDt(dt_t **pdt);
+    MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes);
+    TypeInfoDeclaration *getTypeInfoDeclaration();
+    int hasPointers();
+
+    type *toCtype();
+
+    llvm::Value* llvmInit;
+};
+
+struct TypeEnum : Type
+{
+    EnumDeclaration *sym;
+
+    TypeEnum(EnumDeclaration *sym);
+    d_uns64 size(Loc loc);
+    unsigned alignsize();
+    char *toChars();
+    Type *semantic(Loc loc, Scope *sc);
+    Dsymbol *toDsymbol(Scope *sc);
+    void toDecoBuffer(OutBuffer *buf);
+    void toTypeInfoBuffer(OutBuffer *buf);
+    void toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs);
+    Expression *dotExp(Scope *sc, Expression *e, Identifier *ident);
+    Expression *getProperty(Loc loc, Identifier *ident);
+    int isintegral();
+    int isfloating();
+    int isscalar();
+    int isunsigned();
+    MATCH implicitConvTo(Type *to);
+    Type *toBasetype();
+    Expression *defaultInit();
+    int isZeroInit();
+    MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes);
+    TypeInfoDeclaration *getTypeInfoDeclaration();
+    int hasPointers();
+
+    type *toCtype();
+};
+
+struct TypeTypedef : Type
+{
+    TypedefDeclaration *sym;
+
+    TypeTypedef(TypedefDeclaration *sym);
+    Type *syntaxCopy();
+    d_uns64 size(Loc loc);
+    unsigned alignsize();
+    char *toChars();
+    Type *semantic(Loc loc, Scope *sc);
+    Dsymbol *toDsymbol(Scope *sc);
+    void toDecoBuffer(OutBuffer *buf);
+    void toTypeInfoBuffer(OutBuffer *buf);
+    void toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs);
+    Expression *dotExp(Scope *sc, Expression *e, Identifier *ident);
+    int isbit();
+    int isintegral();
+    int isfloating();
+    int isreal();
+    int isimaginary();
+    int iscomplex();
+    int isscalar();
+    int isunsigned();
+    int checkBoolean();
+    Type *toBasetype();
+    MATCH implicitConvTo(Type *to);
+    Expression *defaultInit();
+    int isZeroInit();
+    dt_t **toDt(dt_t **pdt);
+    MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes);
+    TypeInfoDeclaration *getTypeInfoDeclaration();
+    int hasPointers();
+
+    type *toCtype();
+    type *toCParamtype();
+};
+
+struct TypeClass : Type
+{
+    ClassDeclaration *sym;
+
+    TypeClass(ClassDeclaration *sym);
+    d_uns64 size(Loc loc);
+    char *toChars();
+    Type *syntaxCopy();
+    Type *semantic(Loc loc, Scope *sc);
+    Dsymbol *toDsymbol(Scope *sc);
+    void toDecoBuffer(OutBuffer *buf);
+    void toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs);
+    Expression *dotExp(Scope *sc, Expression *e, Identifier *ident);
+    ClassDeclaration *isClassHandle();
+    int isBaseOf(Type *t, int *poffset);
+    MATCH implicitConvTo(Type *to);
+    Expression *defaultInit();
+    int isZeroInit();
+    MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes);
+    int isauto();
+    int checkBoolean();
+    TypeInfoDeclaration *getTypeInfoDeclaration();
+    int hasPointers();
+
+    type *toCtype();
+
+    Symbol *toSymbol();
+
+    llvm::Value* llvmInit;
+};
+
+struct TypeTuple : Type
+{
+    Arguments *arguments;	// types making up the tuple
+
+    TypeTuple(Arguments *arguments);
+    TypeTuple(Expressions *exps);
+    Type *syntaxCopy();
+    Type *semantic(Loc loc, Scope *sc);
+    int equals(Object *o);
+    Type *reliesOnTident();
+    void toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs);
+    void toDecoBuffer(OutBuffer *buf);
+    Expression *getProperty(Loc loc, Identifier *ident);
+    TypeInfoDeclaration *getTypeInfoDeclaration();
+};
+
+struct TypeSlice : Type
+{
+    Expression *lwr;
+    Expression *upr;
+
+    TypeSlice(Type *next, Expression *lwr, Expression *upr);
+    Type *syntaxCopy();
+    Type *semantic(Loc loc, Scope *sc);
+    void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps);
+    void toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs);
+};
+
+/**************************************************************/
+
+//enum InOut { None, In, Out, InOut, Lazy };
+
+struct Argument : Object
+{
+    //enum InOut inout;
+    unsigned storageClass;
+    Type *type;
+    Identifier *ident;
+    Expression *defaultArg;
+
+    Argument(unsigned storageClass, Type *type, Identifier *ident, Expression *defaultArg);
+    Argument *syntaxCopy();
+    Type *isLazyArray();
+    void toDecoBuffer(OutBuffer *buf);
+    static Arguments *arraySyntaxCopy(Arguments *args);
+    static char *argsTypesToChars(Arguments *args, int varargs);
+    static void argsToCBuffer(OutBuffer *buf, HdrGenState *hgs, Arguments *arguments, int varargs);
+    static void argsToDecoBuffer(OutBuffer *buf, Arguments *arguments);
+    static size_t dim(Arguments *arguments);
+    static Argument *getNth(Arguments *arguments, size_t nth, size_t *pn = NULL);
+
+    // backend
+    bool llvmCopy;
+    VarDeclaration* vardecl;
+};
+
+extern int PTRSIZE;
+extern int REALSIZE;
+extern int REALPAD;
+extern int Tsize_t;
+extern int Tptrdiff_t;
+
+#endif /* DMD_MTYPE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/opover.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,748 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <assert.h>
+#include <complex>
+
+#ifdef __APPLE__
+#define integer_t dmd_integer_t
+#endif
+
+#if IN_GCC || IN_LLVM
+#include "mem.h"
+#elif linux
+#include "../root/mem.h"
+#elif _WIN32
+#include "..\root\mem.h"
+#endif
+
+//#include "port.h"
+#include "mtype.h"
+#include "init.h"
+#include "expression.h"
+#include "id.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "template.h"
+
+static Expression *build_overload(Loc loc, Scope *sc, Expression *ethis, Expression *earg, Identifier *id);
+static void inferApplyArgTypesX(FuncDeclaration *fstart, Arguments *arguments);
+static int inferApplyArgTypesY(TypeFunction *tf, Arguments *arguments);
+static void templateResolve(Match *m, TemplateDeclaration *td, Scope *sc, Loc loc, Objects *targsi, Expressions *arguments);
+
+/******************************** Expression **************************/
+
+
+/***********************************
+ * Determine if operands of binary op can be reversed
+ * to fit operator overload.
+ */
+
+int Expression::isCommutative()
+{
+    return FALSE;	// default is no reverse
+}
+
+/***********************************
+ * Get Identifier for operator overload.
+ */
+
+Identifier *Expression::opId()
+{
+    assert(0);
+    return NULL;
+}
+
+/***********************************
+ * Get Identifier for reverse operator overload,
+ * NULL if not supported for this operator.
+ */
+
+Identifier *Expression::opId_r()
+{
+    return NULL;
+}
+
+/************************* Operators *****************************/
+
+Identifier *UAddExp::opId()   { return Id::uadd; }
+
+Identifier *NegExp::opId()   { return Id::neg; }
+
+Identifier *ComExp::opId()   { return Id::com; }
+
+Identifier *CastExp::opId()   { return Id::cast; }
+
+Identifier *InExp::opId()     { return Id::opIn; }
+Identifier *InExp::opId_r()     { return Id::opIn_r; }
+
+Identifier *PostExp::opId() { return (op == TOKplusplus)
+				? Id::postinc
+				: Id::postdec; }
+
+int AddExp::isCommutative()  { return TRUE; }
+Identifier *AddExp::opId()   { return Id::add; }
+Identifier *AddExp::opId_r() { return Id::add_r; }
+
+Identifier *MinExp::opId()   { return Id::sub; }
+Identifier *MinExp::opId_r() { return Id::sub_r; }
+
+int MulExp::isCommutative()  { return TRUE; }
+Identifier *MulExp::opId()   { return Id::mul; }
+Identifier *MulExp::opId_r() { return Id::mul_r; }
+
+Identifier *DivExp::opId()   { return Id::div; }
+Identifier *DivExp::opId_r() { return Id::div_r; }
+
+Identifier *ModExp::opId()   { return Id::mod; }
+Identifier *ModExp::opId_r() { return Id::mod_r; }
+
+Identifier *ShlExp::opId()   { return Id::shl; }
+Identifier *ShlExp::opId_r() { return Id::shl_r; }
+
+Identifier *ShrExp::opId()   { return Id::shr; }
+Identifier *ShrExp::opId_r() { return Id::shr_r; }
+
+Identifier *UshrExp::opId()   { return Id::ushr; }
+Identifier *UshrExp::opId_r() { return Id::ushr_r; }
+
+int AndExp::isCommutative()  { return TRUE; }
+Identifier *AndExp::opId()   { return Id::iand; }
+Identifier *AndExp::opId_r() { return Id::iand_r; }
+
+int OrExp::isCommutative()  { return TRUE; }
+Identifier *OrExp::opId()   { return Id::ior; }
+Identifier *OrExp::opId_r() { return Id::ior_r; }
+
+int XorExp::isCommutative()  { return TRUE; }
+Identifier *XorExp::opId()   { return Id::ixor; }
+Identifier *XorExp::opId_r() { return Id::ixor_r; }
+
+Identifier *CatExp::opId()   { return Id::cat; }
+Identifier *CatExp::opId_r() { return Id::cat_r; }
+
+Identifier *    AssignExp::opId()  { return Id::assign;  }
+Identifier * AddAssignExp::opId()  { return Id::addass;  }
+Identifier * MinAssignExp::opId()  { return Id::subass;  }
+Identifier * MulAssignExp::opId()  { return Id::mulass;  }
+Identifier * DivAssignExp::opId()  { return Id::divass;  }
+Identifier * ModAssignExp::opId()  { return Id::modass;  }
+Identifier * AndAssignExp::opId()  { return Id::andass;  }
+Identifier *  OrAssignExp::opId()  { return Id::orass;   }
+Identifier * XorAssignExp::opId()  { return Id::xorass;  }
+Identifier * ShlAssignExp::opId()  { return Id::shlass;  }
+Identifier * ShrAssignExp::opId()  { return Id::shrass;  }
+Identifier *UshrAssignExp::opId()  { return Id::ushrass; }
+Identifier * CatAssignExp::opId()  { return Id::catass;  }
+
+int EqualExp::isCommutative()  { return TRUE; }
+Identifier *EqualExp::opId()   { return Id::eq; }
+
+int CmpExp::isCommutative()  { return TRUE; }
+Identifier *CmpExp::opId()   { return Id::cmp; }
+
+Identifier *ArrayExp::opId()	{ return Id::index; }
+
+
+/************************************
+ * Operator overload.
+ * Check for operator overload, if so, replace
+ * with function call.
+ * Return NULL if not an operator overload.
+ */
+
+Expression *UnaExp::op_overload(Scope *sc)
+{
+    AggregateDeclaration *ad;
+    Dsymbol *fd;
+    Type *t1 = e1->type->toBasetype();
+
+    if (t1->ty == Tclass)
+    {
+	ad = ((TypeClass *)t1)->sym;
+	goto L1;
+    }
+    else if (t1->ty == Tstruct)
+    {
+	ad = ((TypeStruct *)t1)->sym;
+
+    L1:
+	fd = search_function(ad, opId());
+	if (fd)
+	{
+	    if (op == TOKarray)
+	    {
+		Expression *e;
+		ArrayExp *ae = (ArrayExp *)this;
+
+		e = new DotIdExp(loc, e1, fd->ident);
+		e = new CallExp(loc, e, ae->arguments);
+		e = e->semantic(sc);
+		return e;
+	    }
+	    else
+	    {
+		// Rewrite +e1 as e1.add()
+		return build_overload(loc, sc, e1, NULL, fd->ident);
+	    }
+	}
+    }
+    return NULL;
+}
+
+
+Expression *BinExp::op_overload(Scope *sc)
+{
+    //printf("BinExp::op_overload() (%s)\n", toChars());
+
+    AggregateDeclaration *ad;
+    Type *t1 = e1->type->toBasetype();
+    Type *t2 = e2->type->toBasetype();
+    Identifier *id = opId();
+    Identifier *id_r = opId_r();
+
+    Match m;
+    Expressions args1;
+    Expressions args2;
+    int argsset = 0;
+
+    AggregateDeclaration *ad1;
+    if (t1->ty == Tclass)
+	ad1 = ((TypeClass *)t1)->sym;
+    else if (t1->ty == Tstruct)
+	ad1 = ((TypeStruct *)t1)->sym;
+    else
+	ad1 = NULL;
+
+    AggregateDeclaration *ad2;
+    if (t2->ty == Tclass)
+	ad2 = ((TypeClass *)t2)->sym;
+    else if (t2->ty == Tstruct)
+	ad2 = ((TypeStruct *)t2)->sym;
+    else
+	ad2 = NULL;
+
+    Dsymbol *s = NULL;
+    Dsymbol *s_r = NULL;
+    FuncDeclaration *fd = NULL;
+    TemplateDeclaration *td = NULL;
+    if (ad1 && id)
+    {
+	s = search_function(ad1, id);
+    }
+    if (ad2 && id_r)
+    {
+	s_r = search_function(ad2, id_r);
+    }
+
+    if (s || s_r)
+    {
+	/* Try:
+	 *	a.opfunc(b)
+	 *	b.opfunc_r(a)
+	 * and see which is better.
+	 */
+	Expression *e;
+	FuncDeclaration *lastf;
+
+	args1.setDim(1);
+	args1.data[0] = (void*) e1;
+	args2.setDim(1);
+	args2.data[0] = (void*) e2;
+	argsset = 1;
+
+	memset(&m, 0, sizeof(m));
+	m.last = MATCHnomatch;
+
+	if (s)
+	{
+	    fd = s->isFuncDeclaration();
+	    if (fd)
+	    {
+		overloadResolveX(&m, fd, &args2);
+	    }
+	    else
+	    {   td = s->isTemplateDeclaration();
+		templateResolve(&m, td, sc, loc, NULL, &args2);
+	    }
+	}
+
+	lastf = m.lastf;
+
+	if (s_r)
+	{
+	    fd = s_r->isFuncDeclaration();
+	    if (fd)
+	    {
+		overloadResolveX(&m, fd, &args1);
+	    }
+	    else
+	    {   td = s_r->isTemplateDeclaration();
+		templateResolve(&m, td, sc, loc, NULL, &args1);
+	    }
+	}
+
+	if (m.count > 1)
+	{
+	    // Error, ambiguous
+	    error("overloads %s and %s both match argument list for %s",
+		    m.lastf->type->toChars(),
+		    m.nextf->type->toChars(),
+		    m.lastf->toChars());
+	}
+	else if (m.last == MATCHnomatch)
+	{
+	    m.lastf = m.anyf;
+	}
+
+	if (op == TOKplusplus || op == TOKminusminus)
+	    // Kludge because operator overloading regards e++ and e--
+	    // as unary, but it's implemented as a binary.
+	    // Rewrite (e1 ++ e2) as e1.postinc()
+	    // Rewrite (e1 -- e2) as e1.postdec()
+	    e = build_overload(loc, sc, e1, NULL, id);
+	else if (lastf && m.lastf == lastf || m.last == MATCHnomatch)
+	    // Rewrite (e1 op e2) as e1.opfunc(e2)
+	    e = build_overload(loc, sc, e1, e2, id);
+	else
+	    // Rewrite (e1 op e2) as e2.opfunc_r(e1)
+	    e = build_overload(loc, sc, e2, e1, id_r);
+	return e;
+    }
+
+    if (isCommutative())
+    {
+	s = NULL;
+	s_r = NULL;
+	if (ad1 && id_r)
+	{
+	    s_r = search_function(ad1, id_r);
+	}
+	if (ad2 && id)
+	{
+	    s = search_function(ad2, id);
+	}
+
+	if (s || s_r)
+	{
+	    /* Try:
+	     *	a.opfunc_r(b)
+	     *	b.opfunc(a)
+	     * and see which is better.
+	     */
+	    Expression *e;
+	    FuncDeclaration *lastf;
+
+	    if (!argsset)
+	    {	args1.setDim(1);
+		args1.data[0] = (void*) e1;
+		args2.setDim(1);
+		args2.data[0] = (void*) e2;
+	    }
+
+	    memset(&m, 0, sizeof(m));
+	    m.last = MATCHnomatch;
+
+	    if (s_r)
+	    {
+		fd = s_r->isFuncDeclaration();
+		if (fd)
+		{
+		    overloadResolveX(&m, fd, &args2);
+		}
+		else
+		{   td = s_r->isTemplateDeclaration();
+		    templateResolve(&m, td, sc, loc, NULL, &args2);
+		}
+	    }
+	    lastf = m.lastf;
+
+	    if (s)
+	    {
+		fd = s->isFuncDeclaration();
+		if (fd)
+		{
+		    overloadResolveX(&m, fd, &args1);
+		}
+		else
+		{   td = s->isTemplateDeclaration();
+		    templateResolve(&m, td, sc, loc, NULL, &args1);
+		}
+	    }
+
+	    if (m.count > 1)
+	    {
+		// Error, ambiguous
+		error("overloads %s and %s both match argument list for %s",
+			m.lastf->type->toChars(),
+			m.nextf->type->toChars(),
+			m.lastf->toChars());
+	    }
+	    else if (m.last == MATCHnomatch)
+	    {
+		m.lastf = m.anyf;
+	    }
+
+	    if (lastf && m.lastf == lastf ||
+		id_r && m.last == MATCHnomatch)
+		// Rewrite (e1 op e2) as e1.opfunc_r(e2)
+		e = build_overload(loc, sc, e1, e2, id_r);
+	    else
+		// Rewrite (e1 op e2) as e2.opfunc(e1)
+		e = build_overload(loc, sc, e2, e1, id);
+
+	    // When reversing operands of comparison operators,
+	    // need to reverse the sense of the op
+	    switch (op)
+	    {
+		case TOKlt:	op = TOKgt;	break;
+		case TOKgt:	op = TOKlt;	break;
+		case TOKle:	op = TOKge;	break;
+		case TOKge:	op = TOKle;	break;
+
+		// Floating point compares
+		case TOKule:	op = TOKuge;	 break;
+		case TOKul:	op = TOKug;	 break;
+		case TOKuge:	op = TOKule;	 break;
+		case TOKug:	op = TOKul;	 break;
+
+		// These are symmetric
+		case TOKunord:
+		case TOKlg:
+		case TOKleg:
+		case TOKue:
+		    break;
+	    }
+
+	    return e;
+	}
+    }
+
+    return NULL;
+}
+
+/***********************************
+ * Utility to build a function call out of this reference and argument.
+ */
+
+static Expression *build_overload(Loc loc, Scope *sc, Expression *ethis, Expression *earg, Identifier *id)
+{
+    Expression *e;
+
+    //printf("build_overload(id = '%s')\n", id->toChars());
+    //earg->print();
+    //earg->type->print();
+    e = new DotIdExp(loc, ethis, id);
+
+    if (earg)
+	e = new CallExp(loc, e, earg);
+    else
+	e = new CallExp(loc, e);
+
+    e = e->semantic(sc);
+    return e;
+}
+
+/***************************************
+ * Search for function funcid in aggregate ad.
+ */
+
+Dsymbol *search_function(AggregateDeclaration *ad, Identifier *funcid)
+{
+    Dsymbol *s;
+    FuncDeclaration *fd;
+    TemplateDeclaration *td;
+
+    s = ad->search(0, funcid, 0);
+    if (s)
+    {	Dsymbol *s2;
+
+	//printf("search_function: s = '%s'\n", s->kind());
+	s2 = s->toAlias();
+	//printf("search_function: s2 = '%s'\n", s2->kind());
+	fd = s2->isFuncDeclaration();
+	if (fd && fd->type->ty == Tfunction)
+	    return fd;
+
+	td = s2->isTemplateDeclaration();
+	if (td)
+	    return td;
+    }
+    return NULL;
+}
+
+
+/*****************************************
+ * Given array of arguments and an aggregate type,
+ * if any of the argument types are missing, attempt to infer
+ * them from the aggregate type.
+ */
+
+void inferApplyArgTypes(enum TOK op, Arguments *arguments, Expression *aggr)
+{
+    if (!arguments || !arguments->dim)
+	return;
+
+    /* Return if no arguments need types.
+     */
+    for (size_t u = 0; 1; u++)
+    {	if (u == arguments->dim)
+	    return;
+	Argument *arg = (Argument *)arguments->data[u];
+	if (!arg->type)
+	    break;
+    }
+
+    AggregateDeclaration *ad;
+    FuncDeclaration *fd;
+
+    Argument *arg = (Argument *)arguments->data[0];
+    Type *taggr = aggr->type;
+    if (!taggr)
+	return;
+    Type *tab = taggr->toBasetype();
+    switch (tab->ty)
+    {
+	case Tarray:
+	case Tsarray:
+	case Ttuple:
+	    if (arguments->dim == 2)
+	    {
+		if (!arg->type)
+		    arg->type = Type::tsize_t;	// key type
+		arg = (Argument *)arguments->data[1];
+	    }
+	    if (!arg->type && tab->ty != Ttuple)
+		arg->type = tab->nextOf();	// value type
+	    break;
+
+	case Taarray:
+	{   TypeAArray *taa = (TypeAArray *)tab;
+
+	    if (arguments->dim == 2)
+	    {
+		if (!arg->type)
+		    arg->type = taa->index;	// key type
+		arg = (Argument *)arguments->data[1];
+	    }
+	    if (!arg->type)
+		arg->type = taa->next;		// value type
+	    break;
+	}
+
+	case Tclass:
+	    ad = ((TypeClass *)tab)->sym;
+	    goto Laggr;
+
+	case Tstruct:
+	    ad = ((TypeStruct *)tab)->sym;
+	    goto Laggr;
+
+	Laggr:
+#if 0
+	    if (arguments->dim == 1)
+	    {
+		if (!arg->type)
+		{
+		    /* Look for an opNext() overload
+		     */
+		    Dsymbol *s = search_function(ad, Id::next);
+		    fd = s ? s->isFuncDeclaration() : NULL;
+		    if (!fd)
+			goto Lapply;
+		    arg->type = fd->type->next;
+		}
+		break;
+	    }
+#endif
+	Lapply:
+	{   /* Look for an
+	     *	int opApply(int delegate(ref Type [, ...]) dg);
+	     * overload
+	     */
+	    Dsymbol *s = search_function(ad,
+			(op == TOKforeach_reverse) ? Id::applyReverse
+						   : Id::apply);
+	    if (s)
+	    {
+		fd = s->isFuncDeclaration();
+		if (fd)
+		    inferApplyArgTypesX(fd, arguments);
+	    }
+	    break;
+	}
+
+	case Tdelegate:
+	{
+	    if (0 && aggr->op == TOKdelegate)
+	    {	DelegateExp *de = (DelegateExp *)aggr;
+
+		fd = de->func->isFuncDeclaration();
+		if (fd)
+		    inferApplyArgTypesX(fd, arguments);
+	    }
+	    else
+	    {
+		inferApplyArgTypesY((TypeFunction *)tab->nextOf(), arguments);
+	    }
+	    break;
+	}
+
+	default:
+	    break;		// ignore error, caught later
+    }
+}
+
+/********************************
+ * Recursive helper function,
+ * analogous to func.overloadResolveX().
+ */
+
+int fp3(void *param, FuncDeclaration *f)
+{
+    Arguments *arguments = (Arguments *)param;
+    TypeFunction *tf = (TypeFunction *)f->type;
+    if (inferApplyArgTypesY(tf, arguments) == 1)
+	return 0;
+    if (arguments->dim == 0)
+	return 1;
+    return 0;
+}
+
+static void inferApplyArgTypesX(FuncDeclaration *fstart, Arguments *arguments)
+{
+    overloadApply(fstart, &fp3, arguments);
+}
+
+#if 0
+static void inferApplyArgTypesX(FuncDeclaration *fstart, Arguments *arguments)
+{
+    Declaration *d;
+    Declaration *next;
+
+    for (d = fstart; d; d = next)
+    {
+	FuncDeclaration *f;
+	FuncAliasDeclaration *fa;
+	AliasDeclaration *a;
+
+	fa = d->isFuncAliasDeclaration();
+	if (fa)
+	{
+	    inferApplyArgTypesX(fa->funcalias, arguments);
+	    next = fa->overnext;
+	}
+	else if ((f = d->isFuncDeclaration()) != NULL)
+	{
+	    next = f->overnext;
+
+	    TypeFunction *tf = (TypeFunction *)f->type;
+	    if (inferApplyArgTypesY(tf, arguments) == 1)
+		continue;
+	    if (arguments->dim == 0)
+		return;
+	}
+	else if ((a = d->isAliasDeclaration()) != NULL)
+	{
+	    Dsymbol *s = a->toAlias();
+	    next = s->isDeclaration();
+	    if (next == a)
+		break;
+	    if (next == fstart)
+		break;
+	}
+	else
+	{   d->error("is aliased to a function");
+	    break;
+	}
+    }
+}
+#endif
+
+/******************************
+ * Infer arguments from type of function.
+ * Returns:
+ *	0 match for this function
+ *	1 no match for this function
+ */
+
+static int inferApplyArgTypesY(TypeFunction *tf, Arguments *arguments)
+{   size_t nparams;
+    Argument *p;
+
+    if (Argument::dim(tf->parameters) != 1)
+	goto Lnomatch;
+    p = Argument::getNth(tf->parameters, 0);
+    if (p->type->ty != Tdelegate)
+	goto Lnomatch;
+    tf = (TypeFunction *)p->type->nextOf();
+    assert(tf->ty == Tfunction);
+
+    /* We now have tf, the type of the delegate. Match it against
+     * the arguments, filling in missing argument types.
+     */
+    nparams = Argument::dim(tf->parameters);
+    if (nparams == 0 || tf->varargs)
+	goto Lnomatch;		// not enough parameters
+    if (arguments->dim != nparams)
+	goto Lnomatch;		// not enough parameters
+
+    for (size_t u = 0; u < nparams; u++)
+    {
+	Argument *arg = (Argument *)arguments->data[u];
+	Argument *param = Argument::getNth(tf->parameters, u);
+	if (arg->type)
+	{   if (!arg->type->equals(param->type))
+	    {
+		/* Cannot resolve argument types. Indicate an
+		 * error by setting the number of arguments to 0.
+		 */
+		arguments->dim = 0;
+		goto Lmatch;
+	    }
+	    continue;
+	}
+	arg->type = param->type;
+    }
+  Lmatch:
+    return 0;
+
+  Lnomatch:
+    return 1;
+}
+
+/**************************************
+ */
+
+static void templateResolve(Match *m, TemplateDeclaration *td, Scope *sc, Loc loc, Objects *targsi, Expressions *arguments)
+{
+    FuncDeclaration *fd;
+
+    assert(td);
+    fd = td->deduce(sc, loc, targsi, arguments);
+    if (!fd)
+	return;
+    m->anyf = fd;
+    if (m->last >= MATCHexact)
+    {
+	m->nextf = fd;
+	m->count++;
+    }
+    else
+    {
+	m->last = MATCHexact;
+	m->lastf = fd;
+	m->count = 1;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/optimize.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,750 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <ctype.h>
+#include <assert.h>
+#include <math.h>
+
+#if __DMC__
+#include <complex.h>
+#endif
+
+#include "lexer.h"
+#include "mtype.h"
+#include "expression.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "init.h"
+
+
+#ifdef IN_GCC
+#include "d-gcc-real.h"
+
+/* %% fix? */
+extern "C" bool real_isnan (const real_t *);
+#endif
+
+static real_t zero;	// work around DMC bug for now
+
+
+/*************************************
+ * If expression is a variable with a const initializer,
+ * return that initializer.
+ */
+
+Expression *fromConstInitializer(Expression *e1)
+{
+    //printf("fromConstInitializer(%s)\n", e1->toChars());
+    if (e1->op == TOKvar)
+    {	VarExp *ve = (VarExp *)e1;
+	VarDeclaration *v = ve->var->isVarDeclaration();
+	if (v && v->isConst() && v->init)
+	{   Expression *ei = v->init->toExpression();
+	    if (ei && ei->type)
+		e1 = ei;
+	}
+    }
+    return e1;
+}
+
+
+Expression *Expression::optimize(int result)
+{
+    //printf("Expression::optimize(result = x%x) %s\n", result, toChars());
+    return this;
+}
+
+Expression *VarExp::optimize(int result)
+{
+    if (result & WANTinterpret)
+    {
+	return fromConstInitializer(this);
+    }
+    return this;
+}
+
+Expression *TupleExp::optimize(int result)
+{
+    for (size_t i = 0; i < exps->dim; i++)
+    {   Expression *e = (Expression *)exps->data[i];
+
+	e = e->optimize(WANTvalue | (result & WANTinterpret));
+	exps->data[i] = (void *)e;
+    }
+    return this;
+}
+
+Expression *ArrayLiteralExp::optimize(int result)
+{
+    if (elements)
+    {
+	for (size_t i = 0; i < elements->dim; i++)
+	{   Expression *e = (Expression *)elements->data[i];
+
+	    e = e->optimize(WANTvalue | (result & WANTinterpret));
+	    elements->data[i] = (void *)e;
+	}
+    }
+    return this;
+}
+
+Expression *AssocArrayLiteralExp::optimize(int result)
+{
+    assert(keys->dim == values->dim);
+    for (size_t i = 0; i < keys->dim; i++)
+    {   Expression *e = (Expression *)keys->data[i];
+
+	e = e->optimize(WANTvalue | (result & WANTinterpret));
+	keys->data[i] = (void *)e;
+
+	e = (Expression *)values->data[i];
+	e = e->optimize(WANTvalue | (result & WANTinterpret));
+	values->data[i] = (void *)e;
+    }
+    return this;
+}
+
+Expression *StructLiteralExp::optimize(int result)
+{
+    if (elements)
+    {
+	for (size_t i = 0; i < elements->dim; i++)
+	{   Expression *e = (Expression *)elements->data[i];
+	    if (!e)
+		continue;
+	    e = e->optimize(WANTvalue | (result & WANTinterpret));
+	    elements->data[i] = (void *)e;
+	}
+    }
+    return this;
+}
+
+Expression *TypeExp::optimize(int result)
+{
+    return this;
+}
+
+Expression *UnaExp::optimize(int result)
+{
+    e1 = e1->optimize(result);
+    return this;
+}
+
+Expression *NegExp::optimize(int result)
+{   Expression *e;
+
+    e1 = e1->optimize(result);
+    if (e1->isConst() == 1)
+    {
+	e = Neg(type, e1);
+    }
+    else
+	e = this;
+    return e;
+}
+
+Expression *ComExp::optimize(int result)
+{   Expression *e;
+
+    e1 = e1->optimize(result);
+    if (e1->isConst() == 1)
+    {
+	e = Com(type, e1);
+    }
+    else
+	e = this;
+    return e;
+}
+
+Expression *NotExp::optimize(int result)
+{   Expression *e;
+
+    e1 = e1->optimize(result);
+    if (e1->isConst() == 1)
+    {
+	e = Not(type, e1);
+    }
+    else
+	e = this;
+    return e;
+}
+
+Expression *BoolExp::optimize(int result)
+{   Expression *e;
+
+    e1 = e1->optimize(result);
+    if (e1->isConst() == 1)
+    {
+	e = Bool(type, e1);
+    }
+    else
+	e = this;
+    return e;
+}
+
+Expression *AddrExp::optimize(int result)
+{   Expression *e;
+
+    //printf("AddrExp::optimize(result = %d) %s\n", result, toChars());
+    e1 = e1->optimize(result);
+    // Convert &*ex to ex
+    if (e1->op == TOKstar)
+    {	Expression *ex;
+
+	ex = ((PtrExp *)e1)->e1;
+	if (type->equals(ex->type))
+	    e = ex;
+	else
+	{
+	    e = ex->copy();
+	    e->type = type;
+	}
+	return e;
+    }
+    if (e1->op == TOKvar)
+    {	VarExp *ve = (VarExp *)e1;
+	if (!ve->var->isOut() && !ve->var->isRef() &&
+	    !ve->var->isImportedSymbol())
+	{
+	    e = new SymOffExp(loc, ve->var, 0);
+	    e->type = type;
+	    return e;
+	}
+    }
+    if (e1->op == TOKindex)
+    {	// Convert &array[n] to &array+n
+	IndexExp *ae = (IndexExp *)e1;
+
+	if (ae->e2->op == TOKint64 && ae->e1->op == TOKvar)
+	{
+	    integer_t index = ae->e2->toInteger();
+	    VarExp *ve = (VarExp *)ae->e1;
+	    if (ve->type->ty == Tsarray && ve->type->next->ty != Tbit
+		&& !ve->var->isImportedSymbol())
+	    {
+		TypeSArray *ts = (TypeSArray *)ve->type;
+		integer_t dim = ts->dim->toInteger();
+		if (index < 0 || index >= dim)
+		    error("array index %jd is out of bounds [0..%jd]", index, dim);
+		e = new SymOffExp(loc, ve->var, index * ts->next->size());
+		e->type = type;
+		return e;
+	    }
+	}
+    }
+    return this;
+}
+
+Expression *PtrExp::optimize(int result)
+{
+    //printf("PtrExp::optimize(result = x%x) %s\n", result, toChars());
+    e1 = e1->optimize(result);
+    // Convert *&ex to ex
+    if (e1->op == TOKaddress)
+    {	Expression *e;
+	Expression *ex;
+
+	ex = ((AddrExp *)e1)->e1;
+	if (type->equals(ex->type))
+	    e = ex;
+	else
+	{
+	    e = ex->copy();
+	    e->type = type;
+	}
+	return e;
+    }
+    // Constant fold *(&structliteral + offset)
+    if (e1->op == TOKadd)
+    {
+	Expression *e;
+	e = Ptr(type, e1);
+	if (e != EXP_CANT_INTERPRET)
+	    return e;
+    }
+
+    return this;
+}
+
+Expression *CallExp::optimize(int result)
+{   Expression *e = this;
+
+    e1 = e1->optimize(result);
+    if (e1->op == TOKvar && result & WANTinterpret)
+    {
+	FuncDeclaration *fd = ((VarExp *)e1)->var->isFuncDeclaration();
+	if (fd)
+	{
+	    Expression *eresult = fd->interpret(NULL, arguments);
+	    if (eresult)
+		e = eresult;
+	    else if (result & WANTinterpret)
+		error("cannot evaluate %s at compile time", toChars());
+	}
+    }
+    return e;
+}
+
+
+Expression *CastExp::optimize(int result)
+{
+    //printf("CastExp::optimize(result = %d) %s\n", result, toChars());
+    //printf("from %s to %s\n", type->toChars(), to->toChars());
+    //printf("from %s\n", type->toChars());
+    //printf("type = %p\n", type);
+    assert(type);
+    enum TOK op1 = e1->op;
+
+    e1 = e1->optimize(result);
+    if (result & WANTinterpret)
+	e1 = fromConstInitializer(e1);
+
+    if ((e1->op == TOKstring || e1->op == TOKarrayliteral) &&
+	(type->ty == Tpointer || type->ty == Tarray) &&
+	type->next->equals(e1->type->next)
+       )
+    {
+	e1->type = type;
+	return e1;
+    }
+    /* The first test here is to prevent infinite loops
+     */
+    if (op1 != TOKarrayliteral && e1->op == TOKarrayliteral)
+	return e1->castTo(NULL, to);
+    if (e1->op == TOKnull &&
+	(type->ty == Tpointer || type->ty == Tclass))
+    {
+	e1->type = type;
+	return e1;
+    }
+
+    if (result & WANTflags && type->ty == Tclass && e1->type->ty == Tclass)
+    {
+	// See if we can remove an unnecessary cast
+	ClassDeclaration *cdfrom;
+	ClassDeclaration *cdto;
+	int offset;
+
+	cdfrom = e1->type->isClassHandle();
+	cdto   = type->isClassHandle();
+	if (cdto->isBaseOf(cdfrom, &offset) && offset == 0)
+	{
+	    e1->type = type;
+	    return e1;
+	}
+    }
+
+    Expression *e;
+
+    if (e1->isConst())
+    {
+	if (e1->op == TOKsymoff)
+	{
+	    if (type->size() == e1->type->size() &&
+		type->toBasetype()->ty != Tsarray)
+	    {
+		e1->type = type;
+		return e1;
+	    }
+	    return this;
+	}
+	if (to->toBasetype()->ty == Tvoid)
+	    e = this;
+	else
+	    e = Cast(type, to, e1);
+    }
+    else
+	e = this;
+    return e;
+}
+
+Expression *BinExp::optimize(int result)
+{
+    //printf("BinExp::optimize(result = %d) %s\n", result, toChars());
+    e1 = e1->optimize(result);
+    e2 = e2->optimize(result);
+    return this;
+}
+
+Expression *AddExp::optimize(int result)
+{   Expression *e;
+
+    //printf("AddExp::optimize(%s)\n", toChars());
+    e1 = e1->optimize(result);
+    e2 = e2->optimize(result);
+    if (e1->isConst() && e2->isConst())
+    {
+	if (e1->op == TOKsymoff && e2->op == TOKsymoff)
+	    return this;
+	e = Add(type, e1, e2);
+    }
+    else
+	e = this;
+    return e;
+}
+
+Expression *MinExp::optimize(int result)
+{   Expression *e;
+
+    e1 = e1->optimize(result);
+    e2 = e2->optimize(result);
+    if (e1->isConst() && e2->isConst())
+    {
+	if (e2->op == TOKsymoff)
+	    return this;
+	e = Min(type, e1, e2);
+    }
+    else
+	e = this;
+    return e;
+}
+
+Expression *MulExp::optimize(int result)
+{   Expression *e;
+
+    //printf("MulExp::optimize(result = %d) %s\n", result, toChars());
+    e1 = e1->optimize(result);
+    e2 = e2->optimize(result);
+    if (e1->isConst() == 1 && e2->isConst() == 1)
+    {
+	e = Mul(type, e1, e2);
+    }
+    else
+	e = this;
+    return e;
+}
+
+Expression *DivExp::optimize(int result)
+{   Expression *e;
+
+    //printf("DivExp::optimize(%s)\n", toChars());
+    e1 = e1->optimize(result);
+    e2 = e2->optimize(result);
+    if (e1->isConst() == 1 && e2->isConst() == 1)
+    {
+	e = Div(type, e1, e2);
+    }
+    else
+	e = this;
+    return e;
+}
+
+Expression *ModExp::optimize(int result)
+{   Expression *e;
+
+    e1 = e1->optimize(result);
+    e2 = e2->optimize(result);
+    if (e1->isConst() == 1 && e2->isConst() == 1)
+    {
+	e = Mod(type, e1, e2);
+    }
+    else
+	e = this;
+    return e;
+}
+
+Expression *ShlExp::optimize(int result)
+{   Expression *e;
+
+    //printf("ShlExp::optimize(result = %d) %s\n", result, toChars());
+    e1 = e1->optimize(result);
+    e2 = e2->optimize(result);
+    e = this;
+    if (e2->isConst() == 1)
+    {
+	integer_t i2 = e2->toInteger();
+	if (i2 < 0 || i2 > e1->type->size() * 8)
+	{   error("shift left by %jd exceeds %zu", i2, e2->type->size() * 8);
+	    e2 = new IntegerExp(0);
+	}
+	if (e1->isConst() == 1)
+	    e = new IntegerExp(loc, e1->toInteger() << e2->toInteger(), type);
+    }
+    return e;
+}
+
+Expression *ShrExp::optimize(int result)
+{   Expression *e;
+
+    e1 = e1->optimize(result);
+    e2 = e2->optimize(result);
+
+    if (e1->isConst() == 1 && e2->isConst() == 1)
+    {
+	e = Shr(type, e1, e2);
+    }
+    else
+	e = this;
+    return e;
+}
+
+Expression *UshrExp::optimize(int result)
+{   Expression *e;
+
+    //printf("UshrExp::optimize() %s\n", toChars());
+    e1 = e1->optimize(result);
+    e2 = e2->optimize(result);
+
+    if (e1->isConst() == 1 && e2->isConst() == 1)
+    {
+	e = Ushr(type, e1, e2);
+    }
+    else
+	e = this;
+    return e;
+}
+
+Expression *AndExp::optimize(int result)
+{   Expression *e;
+
+    e1 = e1->optimize(result);
+    e2 = e2->optimize(result);
+    if (e1->isConst() == 1 && e2->isConst() == 1)
+	e = And(type, e1, e2);
+    else
+	e = this;
+    return e;
+}
+
+Expression *OrExp::optimize(int result)
+{   Expression *e;
+
+    e1 = e1->optimize(result);
+    e2 = e2->optimize(result);
+    if (e1->isConst() == 1 && e2->isConst() == 1)
+	e = Or(type, e1, e2);
+    else
+	e = this;
+    return e;
+}
+
+Expression *XorExp::optimize(int result)
+{   Expression *e;
+
+    e1 = e1->optimize(result);
+    e2 = e2->optimize(result);
+    if (e1->isConst() == 1 && e2->isConst() == 1)
+	e = Xor(type, e1, e2);
+    else
+	e = this;
+    return e;
+}
+
+Expression *CommaExp::optimize(int result)
+{   Expression *e;
+
+    //printf("CommaExp::optimize(result = %d) %s\n", result, toChars());
+    e1 = e1->optimize(result & WANTinterpret);
+    e2 = e2->optimize(result);
+    if (!e1 || e1->op == TOKint64 || e1->op == TOKfloat64 || !e1->checkSideEffect(2))
+    {
+	e = e2;
+	if (e)
+	    e->type = type;
+    }
+    else
+	e = this;
+    //printf("-CommaExp::optimize(result = %d) %s\n", result, e->toChars());
+    return e;
+}
+
+Expression *ArrayLengthExp::optimize(int result)
+{   Expression *e;
+
+    //printf("ArrayLengthExp::optimize(result = %d) %s\n", result, toChars());
+    e1 = e1->optimize(WANTvalue | (result & WANTinterpret));
+    e = this;
+    if (e1->op == TOKstring || e1->op == TOKarrayliteral || e1->op == TOKassocarrayliteral)
+    {
+	e = ArrayLength(type, e1);
+    }
+    return e;
+}
+
+Expression *EqualExp::optimize(int result)
+{   Expression *e;
+
+    //printf("EqualExp::optimize(result = %x) %s\n", result, toChars());
+    e1 = e1->optimize(WANTvalue | (result & WANTinterpret));
+    e2 = e2->optimize(WANTvalue | (result & WANTinterpret));
+    e = this;
+
+    Expression *e1 = fromConstInitializer(this->e1);
+    Expression *e2 = fromConstInitializer(this->e2);
+
+    e = Equal(op, type, e1, e2);
+    if (e == EXP_CANT_INTERPRET)
+	e = this;
+    return e;
+}
+
+Expression *IdentityExp::optimize(int result)
+{   Expression *e;
+
+    //printf("IdentityExp::optimize(result = %d) %s\n", result, toChars());
+    e1 = e1->optimize(WANTvalue | (result & WANTinterpret));
+    e2 = e2->optimize(WANTvalue | (result & WANTinterpret));
+    e = this;
+
+    if (this->e1->isConst() && this->e2->isConst())
+    {
+	e = Identity(op, type, this->e1, this->e2);
+    }
+    return e;
+}
+
+Expression *IndexExp::optimize(int result)
+{   Expression *e;
+
+    //printf("IndexExp::optimize(result = %d) %s\n", result, toChars());
+    Expression *e1 = this->e1->optimize(WANTvalue | (result & WANTinterpret));
+    if (result & WANTinterpret)
+	e1 = fromConstInitializer(e1);
+    e2 = e2->optimize(WANTvalue | (result & WANTinterpret));
+    e = Index(type, e1, e2);
+    if (e == EXP_CANT_INTERPRET)
+	e = this;
+    return e;
+}
+
+Expression *SliceExp::optimize(int result)
+{   Expression *e;
+
+    //printf("SliceExp::optimize(result = %d) %s\n", result, toChars());
+    e = this;
+    e1 = e1->optimize(WANTvalue | (result & WANTinterpret));
+    if (!lwr)
+    {	if (e1->op == TOKstring)
+	{   // Convert slice of string literal into dynamic array
+	    Type *t = e1->type->toBasetype();
+	    if (t->next)
+		e = e1->castTo(NULL, t->next->arrayOf());
+	}
+	return e;
+    }
+    if (result & WANTinterpret)
+	e1 = fromConstInitializer(e1);
+    lwr = lwr->optimize(WANTvalue | (result & WANTinterpret));
+    upr = upr->optimize(WANTvalue | (result & WANTinterpret));
+    e = Slice(type, e1, lwr, upr);
+    if (e == EXP_CANT_INTERPRET)
+	e = this;
+    return e;
+}
+
+Expression *AndAndExp::optimize(int result)
+{   Expression *e;
+
+    //printf("AndAndExp::optimize(%d) %s\n", result, toChars());
+    e1 = e1->optimize(WANTflags | (result & WANTinterpret));
+    e = this;
+    if (e1->isBool(FALSE))
+    {
+	e = new CommaExp(loc, e1, new IntegerExp(loc, 0, type));
+	e->type = type;
+	e = e->optimize(result);
+    }
+    else
+    {
+	e2 = e2->optimize(WANTflags | (result & WANTinterpret));
+	if (result && e2->type->toBasetype()->ty == Tvoid && !global.errors)
+	    error("void has no value");
+	if (e1->isConst())
+	{
+	    if (e2->isConst())
+	    {	int n1 = e1->isBool(1);
+		int n2 = e2->isBool(1);
+
+		e = new IntegerExp(loc, n1 && n2, type);
+	    }
+	    else if (e1->isBool(TRUE))
+		e = new BoolExp(loc, e2, type);
+	}
+    }
+    return e;
+}
+
+Expression *OrOrExp::optimize(int result)
+{   Expression *e;
+
+    e1 = e1->optimize(WANTflags | (result & WANTinterpret));
+    e = this;
+    if (e1->isBool(TRUE))
+    {	// Replace with (e1, 1)
+	e = new CommaExp(loc, e1, new IntegerExp(loc, 1, type));
+	e->type = type;
+	e = e->optimize(result);
+    }
+    else
+    {
+	e2 = e2->optimize(WANTflags | (result & WANTinterpret));
+	if (result && e2->type->toBasetype()->ty == Tvoid && !global.errors)
+	    error("void has no value");
+	if (e1->isConst())
+	{
+	    if (e2->isConst())
+	    {	int n1 = e1->isBool(1);
+		int n2 = e2->isBool(1);
+
+		e = new IntegerExp(loc, n1 || n2, type);
+	    }
+	    else if (e1->isBool(FALSE))
+		e = new BoolExp(loc, e2, type);
+	}
+    }
+    return e;
+}
+
+Expression *CmpExp::optimize(int result)
+{   Expression *e;
+
+    //printf("CmpExp::optimize() %s\n", toChars());
+    e1 = e1->optimize(result);
+    e2 = e2->optimize(result);
+    if (e1->isConst() == 1 && e2->isConst() == 1)
+    {
+	e = Cmp(op, type, this->e1, this->e2);
+    }
+    else
+	e = this;
+    return e;
+}
+
+Expression *CatExp::optimize(int result)
+{   Expression *e;
+
+    //printf("CatExp::optimize(%d) %s\n", result, toChars());
+    e1 = e1->optimize(result);
+    e2 = e2->optimize(result);
+    e = Cat(type, e1, e2);
+    if (e == EXP_CANT_INTERPRET)
+	e = this;
+    return e;
+}
+
+
+Expression *CondExp::optimize(int result)
+{   Expression *e;
+
+    econd = econd->optimize(WANTflags | (result & WANTinterpret));
+    if (econd->isBool(TRUE))
+	e = e1->optimize(result);
+    else if (econd->isBool(FALSE))
+	e = e2->optimize(result);
+    else
+    {	e1 = e1->optimize(result);
+	e2 = e2->optimize(result);
+	e = this;
+    }
+    return e;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/parse.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,4907 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "mem.h"
+#include "lexer.h"
+#include "parse.h"
+#include "init.h"
+#include "attrib.h"
+#include "cond.h"
+#include "mtype.h"
+#include "template.h"
+#include "staticassert.h"
+#include "expression.h"
+#include "statement.h"
+#include "module.h"
+#include "dsymbol.h"
+#include "import.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "enum.h"
+#include "id.h"
+#include "version.h"
+
+// How multiple declarations are parsed.
+// If 1, treat as C.
+// If 0, treat:
+//	int *p, i;
+// as:
+//	int* p;
+//	int* i;
+#define CDECLSYNTAX	0
+
+// Support C cast syntax:
+//	(type)(expression)
+#define CCASTSYNTAX	1
+
+// Support C array declarations, such as
+//	int a[3][4];
+#define CARRAYDECL	1
+
+// Support left-to-right array declarations
+#define LTORARRAYDECL	1
+
+
+Parser::Parser(Module *module, unsigned char *base, unsigned length, int doDocComment)
+    : Lexer(module, base, 0, length, doDocComment, 0)
+{
+    //printf("Parser::Parser()\n");
+    md = NULL;
+    linkage = LINKd;
+    endloc = 0;
+    inBrackets = 0;
+    //nextToken();		// start up the scanner
+}
+
+Array *Parser::parseModule()
+{
+    Array *decldefs;
+
+    // ModuleDeclation leads off
+    if (token.value == TOKmodule)
+    {
+	unsigned char *comment = token.blockComment;
+
+	nextToken();
+	if (token.value != TOKidentifier)
+	{   error("Identifier expected following module");
+	    goto Lerr;
+	}
+	else
+	{
+	    Array *a = NULL;
+	    Identifier *id;
+
+	    id = token.ident;
+	    while (nextToken() == TOKdot)
+	    {
+		if (!a)
+		    a = new Array();
+		a->push(id);
+		nextToken();
+		if (token.value != TOKidentifier)
+		{   error("Identifier expected following package");
+		    goto Lerr;
+		}
+		id = token.ident;
+	    }
+
+	    md = new ModuleDeclaration(a, id);
+
+	    if (token.value != TOKsemicolon)
+		error("';' expected following module declaration instead of %s", token.toChars());
+	    nextToken();
+	    addComment(mod, comment);
+	}
+    }
+
+    decldefs = parseDeclDefs(0);
+    if (token.value != TOKeof)
+    {	error("unrecognized declaration");
+	goto Lerr;
+    }
+    return decldefs;
+
+Lerr:
+    while (token.value != TOKsemicolon && token.value != TOKeof)
+	nextToken();
+    nextToken();
+    return new Array();
+}
+
+Array *Parser::parseDeclDefs(int once)
+{   Dsymbol *s;
+    Array *decldefs;
+    Array *a;
+    Array *aelse;
+    enum PROT prot;
+    unsigned stc;
+    Condition *condition;
+    unsigned char *comment;
+
+    //printf("Parser::parseDeclDefs()\n");
+    decldefs = new Array();
+    do
+    {
+	comment = token.blockComment;
+	switch (token.value)
+	{
+	    case TOKenum:
+		s = parseEnum();
+		break;
+
+	    case TOKstruct:
+	    case TOKunion:
+	    case TOKclass:
+	    case TOKinterface:
+		s = parseAggregate();
+		break;
+
+	    case TOKimport:
+		s = parseImport(decldefs, 0);
+		break;
+
+	    case TOKtemplate:
+		s = (Dsymbol *)parseTemplateDeclaration();
+		break;
+
+	    case TOKmixin:
+	    {	Loc loc = this->loc;
+		if (peek(&token)->value == TOKlparen)
+		{   // mixin(string)
+		    nextToken();
+		    check(TOKlparen, "mixin");
+		    Expression *e = parseAssignExp();
+		    check(TOKrparen);
+		    check(TOKsemicolon);
+		    s = new CompileDeclaration(loc, e);
+		    break;
+		}
+		s = parseMixin();
+		break;
+	    }
+
+	    CASE_BASIC_TYPES:
+	    case TOKalias:
+	    case TOKtypedef:
+	    case TOKidentifier:
+	    case TOKtypeof:
+	    case TOKdot:
+	    Ldeclaration:
+		a = parseDeclarations();
+		decldefs->append(a);
+		continue;
+
+	    case TOKthis:
+		s = parseCtor();
+		break;
+
+	    case TOKtilde:
+		s = parseDtor();
+		break;
+
+	    case TOKinvariant:
+#if 1
+		s = parseInvariant();
+#else
+		if (peek(&token)->value == TOKlcurly)
+		    s = parseInvariant();
+		else
+		{
+		    stc = STCinvariant;
+		    goto Lstc;
+		}
+#endif
+		break;
+
+	    case TOKunittest:
+		s = parseUnitTest();
+		break;
+
+	    case TOKnew:
+		s = parseNew();
+		break;
+
+	    case TOKdelete:
+		s = parseDelete();
+		break;
+
+	    case TOKeof:
+	    case TOKrcurly:
+		return decldefs;
+
+	    case TOKstatic:
+		nextToken();
+		if (token.value == TOKthis)
+		    s = parseStaticCtor();
+		else if (token.value == TOKtilde)
+		    s = parseStaticDtor();
+		else if (token.value == TOKassert)
+		    s = parseStaticAssert();
+		else if (token.value == TOKif)
+		{   condition = parseStaticIfCondition();
+		    a = parseBlock();
+		    aelse = NULL;
+		    if (token.value == TOKelse)
+		    {   nextToken();
+			aelse = parseBlock();
+		    }
+		    s = new StaticIfDeclaration(condition, a, aelse);
+		    break;
+		}
+		else if (token.value == TOKimport)
+		{
+		    s = parseImport(decldefs, 1);
+		}
+		else
+		{   stc = STCstatic;
+		    goto Lstc2;
+		}
+		break;
+
+	    case TOKconst:	  stc = STCconst;	 goto Lstc;
+	    case TOKfinal:	  stc = STCfinal;	 goto Lstc;
+	    case TOKauto:	  stc = STCauto;	 goto Lstc;
+	    case TOKscope:	  stc = STCscope;	 goto Lstc;
+	    case TOKoverride:	  stc = STCoverride;	 goto Lstc;
+	    case TOKabstract:	  stc = STCabstract;	 goto Lstc;
+	    case TOKsynchronized: stc = STCsynchronized; goto Lstc;
+	    case TOKdeprecated:   stc = STCdeprecated;	 goto Lstc;
+
+	    Lstc:
+		nextToken();
+	    Lstc2:
+		switch (token.value)
+		{
+		    case TOKconst:	  stc |= STCconst;	 goto Lstc;
+		    case TOKfinal:	  stc |= STCfinal;	 goto Lstc;
+		    case TOKauto:	  stc |= STCauto;	 goto Lstc;
+		    case TOKscope:	  stc |= STCscope;	 goto Lstc;
+		    case TOKoverride:	  stc |= STCoverride;	 goto Lstc;
+		    case TOKabstract:	  stc |= STCabstract;	 goto Lstc;
+		    case TOKsynchronized: stc |= STCsynchronized; goto Lstc;
+		    case TOKdeprecated:   stc |= STCdeprecated;	 goto Lstc;
+		    //case TOKinvariant:    stc |= STCinvariant;   goto Lstc;
+		    default:
+			break;
+		}
+
+		/* Look for auto initializers:
+		 *	storage_class identifier = initializer;
+		 */
+		if (token.value == TOKidentifier &&
+		    peek(&token)->value == TOKassign)
+		{
+		    while (1)
+		    {
+			Identifier *ident = token.ident;
+			nextToken();
+			nextToken();
+			Initializer *init = parseInitializer();
+			VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init);
+			v->storage_class = stc;
+			s = v;
+			if (token.value == TOKsemicolon)
+			{
+			    nextToken();
+			}
+			else if (token.value == TOKcomma)
+			{
+			    nextToken();
+			    if (token.value == TOKidentifier &&
+				peek(&token)->value == TOKassign)
+			    {
+				decldefs->push(s);
+				addComment(s, comment);
+				continue;
+			    }
+			    else
+				error("Identifier expected following comma");
+			}
+			else
+			    error("semicolon expected following auto declaration, not '%s'", token.toChars());
+			break;
+		    }
+		}
+		else
+		{   a = parseBlock();
+		    s = new StorageClassDeclaration(stc, a);
+		}
+		break;
+
+	    case TOKextern:
+		if (peek(&token)->value != TOKlparen)
+		{   stc = STCextern;
+		    goto Lstc;
+		}
+	    {
+		enum LINK linksave = linkage;
+		linkage = parseLinkage();
+		a = parseBlock();
+		s = new LinkDeclaration(linkage, a);
+		linkage = linksave;
+		break;
+	    }
+	    case TOKprivate:	prot = PROTprivate;	goto Lprot;
+	    case TOKpackage:	prot = PROTpackage;	goto Lprot;
+	    case TOKprotected:	prot = PROTprotected;	goto Lprot;
+	    case TOKpublic:	prot = PROTpublic;	goto Lprot;
+	    case TOKexport:	prot = PROTexport;	goto Lprot;
+
+	    Lprot:
+		nextToken();
+		a = parseBlock();
+		s = new ProtDeclaration(prot, a);
+		break;
+
+	    case TOKalign:
+	    {	unsigned n;
+
+		s = NULL;
+		nextToken();
+		if (token.value == TOKlparen)
+		{
+		    nextToken();
+		    if (token.value == TOKint32v)
+			n = (unsigned)token.uns64value;
+		    else
+		    {	error("integer expected, not %s", token.toChars());
+			n = 1;
+		    }
+		    nextToken();
+		    check(TOKrparen);
+		}
+		else
+		    n = global.structalign;		// default
+
+		a = parseBlock();
+		s = new AlignDeclaration(n, a);
+		break;
+	    }
+
+	    case TOKpragma:
+	    {	Identifier *ident;
+		Expressions *args = NULL;
+
+		nextToken();
+		check(TOKlparen);
+		if (token.value != TOKidentifier)
+		{   error("pragma(identifier expected");
+		    goto Lerror;
+		}
+		ident = token.ident;
+		nextToken();
+		if (token.value == TOKcomma)
+		    args = parseArguments();	// pragma(identifier, args...)
+		else
+		    check(TOKrparen);		// pragma(identifier)
+
+		if (token.value == TOKsemicolon)
+		    a = NULL;
+		else
+		    a = parseBlock();
+		s = new PragmaDeclaration(loc, ident, args, a);
+		break;
+	    }
+
+	    case TOKdebug:
+		nextToken();
+		if (token.value == TOKassign)
+		{
+		    nextToken();
+		    if (token.value == TOKidentifier)
+			s = new DebugSymbol(loc, token.ident);
+		    else if (token.value == TOKint32v)
+			s = new DebugSymbol(loc, (unsigned)token.uns64value);
+		    else
+		    {	error("identifier or integer expected, not %s", token.toChars());
+			s = NULL;
+		    }
+		    nextToken();
+		    if (token.value != TOKsemicolon)
+			error("semicolon expected");
+		    nextToken();
+		    break;
+		}
+
+		condition = parseDebugCondition();
+		goto Lcondition;
+
+	    case TOKversion:
+		nextToken();
+		if (token.value == TOKassign)
+		{
+		    nextToken();
+		    if (token.value == TOKidentifier)
+			s = new VersionSymbol(loc, token.ident);
+		    else if (token.value == TOKint32v)
+			s = new VersionSymbol(loc, (unsigned)token.uns64value);
+		    else
+		    {	error("identifier or integer expected, not %s", token.toChars());
+			s = NULL;
+		    }
+		    nextToken();
+		    if (token.value != TOKsemicolon)
+			error("semicolon expected");
+		    nextToken();
+		    break;
+		}
+		condition = parseVersionCondition();
+		goto Lcondition;
+
+	    Lcondition:
+		a = parseBlock();
+		aelse = NULL;
+		if (token.value == TOKelse)
+		{   nextToken();
+		    aelse = parseBlock();
+		}
+		s = new ConditionalDeclaration(condition, a, aelse);
+		break;
+
+	    case TOKsemicolon:		// empty declaration
+		nextToken();
+		continue;
+
+	    default:
+		error("Declaration expected, not '%s'",token.toChars());
+	    Lerror:
+		while (token.value != TOKsemicolon && token.value != TOKeof)
+		    nextToken();
+		nextToken();
+		s = NULL;
+		continue;
+	}
+	if (s)
+	{   decldefs->push(s);
+	    addComment(s, comment);
+	}
+    } while (!once);
+    return decldefs;
+}
+
+
+/********************************************
+ * Parse declarations after an align, protection, or extern decl.
+ */
+
+Array *Parser::parseBlock()
+{
+    Array *a = NULL;
+    Dsymbol *s;
+
+    //printf("parseBlock()\n");
+    switch (token.value)
+    {
+	case TOKsemicolon:
+	    error("declaration expected following attribute, not ';'");
+	    nextToken();
+	    break;
+
+	case TOKlcurly:
+	    nextToken();
+	    a = parseDeclDefs(0);
+	    if (token.value != TOKrcurly)
+	    {   /* { */
+		error("matching '}' expected, not %s", token.toChars());
+	    }
+	    else
+		nextToken();
+	    break;
+
+	case TOKcolon:
+	    nextToken();
+#if 0
+	    a = NULL;
+#else
+	    a = parseDeclDefs(0);	// grab declarations up to closing curly bracket
+#endif
+	    break;
+
+	default:
+	    a = parseDeclDefs(1);
+	    break;
+    }
+    return a;
+}
+
+/**********************************
+ * Parse a static assertion.
+ */
+
+StaticAssert *Parser::parseStaticAssert()
+{
+    Loc loc = this->loc;
+    Expression *exp;
+    Expression *msg = NULL;
+
+    //printf("parseStaticAssert()\n");
+    nextToken();
+    check(TOKlparen);
+    exp = parseAssignExp();
+    if (token.value == TOKcomma)
+    {	nextToken();
+	msg = parseAssignExp();
+    }
+    check(TOKrparen);
+    check(TOKsemicolon);
+    return new StaticAssert(loc, exp, msg);
+}
+
+
+/***********************************
+ * Parse extern (linkage)
+ * The parser is on the 'extern' token.
+ */
+
+enum LINK Parser::parseLinkage()
+{
+    enum LINK link = LINKdefault;
+    nextToken();
+    assert(token.value == TOKlparen);
+    nextToken();
+    if (token.value == TOKidentifier)
+    {   Identifier *id = token.ident;
+
+	nextToken();
+	if (id == Id::Windows)
+	    link = LINKwindows;
+	else if (id == Id::Pascal)
+	    link = LINKpascal;
+	else if (id == Id::D)
+	    link = LINKd;
+	else if (id == Id::C)
+	{
+	    link = LINKc;
+	    if (token.value == TOKplusplus)
+	    {   link = LINKcpp;
+		nextToken();
+	    }
+	}
+	else if (id == Id::System)
+	{
+#if _WIN32
+	    link = LINKwindows;
+#else
+	    link = LINKc;
+#endif
+	}
+	else
+	{
+	    error("valid linkage identifiers are D, C, C++, Pascal, Windows, System");
+	    link = LINKd;
+	}
+    }
+    else
+    {
+	link = LINKd;		// default
+    }
+    check(TOKrparen);
+    return link;
+}
+
+/**************************************
+ * Parse a debug conditional
+ */
+
+Condition *Parser::parseDebugCondition()
+{
+    Condition *c;
+
+    if (token.value == TOKlparen)
+    {
+	nextToken();
+	unsigned level = 1;
+	Identifier *id = NULL;
+
+	if (token.value == TOKidentifier)
+	    id = token.ident;
+	else if (token.value == TOKint32v)
+	    level = (unsigned)token.uns64value;
+	else
+	    error("identifier or integer expected, not %s", token.toChars());
+	nextToken();
+	check(TOKrparen);
+	c = new DebugCondition(mod, level, id);
+    }
+    else
+	c = new DebugCondition(mod, 1, NULL);
+    return c;
+
+}
+
+/**************************************
+ * Parse a version conditional
+ */
+
+Condition *Parser::parseVersionCondition()
+{
+    Condition *c;
+    unsigned level = 1;
+    Identifier *id = NULL;
+
+    if (token.value == TOKlparen)
+    {
+	nextToken();
+	if (token.value == TOKidentifier)
+	    id = token.ident;
+	else if (token.value == TOKint32v)
+	    level = (unsigned)token.uns64value;
+	else
+	    error("identifier or integer expected, not %s", token.toChars());
+	nextToken();
+	check(TOKrparen);
+
+    }
+    else
+       error("(condition) expected following version");
+    c = new VersionCondition(mod, level, id);
+    return c;
+
+}
+
+/***********************************************
+ *	static if (expression)
+ *	    body
+ *	else
+ *	    body
+ */
+
+Condition *Parser::parseStaticIfCondition()
+{   Expression *exp;
+    Condition *condition;
+    Array *aif;
+    Array *aelse;
+    Loc loc = this->loc;
+
+    nextToken();
+    if (token.value == TOKlparen)
+    {
+	nextToken();
+	exp = parseAssignExp();
+	check(TOKrparen);
+    }
+    else
+    {   error("(expression) expected following static if");
+	exp = NULL;
+    }
+    condition = new StaticIfCondition(loc, exp);
+    return condition;
+}
+
+
+/*****************************************
+ * Parse a constructor definition:
+ *	this(arguments) { body }
+ * Current token is 'this'.
+ */
+
+CtorDeclaration *Parser::parseCtor()
+{
+    CtorDeclaration *f;
+    Arguments *arguments;
+    int varargs;
+    Loc loc = this->loc;
+
+    nextToken();
+    arguments = parseParameters(&varargs);
+    f = new CtorDeclaration(loc, 0, arguments, varargs);
+    parseContracts(f);
+    return f;
+}
+
+/*****************************************
+ * Parse a destructor definition:
+ *	~this() { body }
+ * Current token is '~'.
+ */
+
+DtorDeclaration *Parser::parseDtor()
+{
+    DtorDeclaration *f;
+    Loc loc = this->loc;
+
+    nextToken();
+    check(TOKthis);
+    check(TOKlparen);
+    check(TOKrparen);
+
+    f = new DtorDeclaration(loc, 0);
+    parseContracts(f);
+    return f;
+}
+
+/*****************************************
+ * Parse a static constructor definition:
+ *	static this() { body }
+ * Current token is 'this'.
+ */
+
+StaticCtorDeclaration *Parser::parseStaticCtor()
+{
+    StaticCtorDeclaration *f;
+    Loc loc = this->loc;
+
+    nextToken();
+    check(TOKlparen);
+    check(TOKrparen);
+
+    f = new StaticCtorDeclaration(loc, 0);
+    parseContracts(f);
+    return f;
+}
+
+/*****************************************
+ * Parse a static destructor definition:
+ *	static ~this() { body }
+ * Current token is '~'.
+ */
+
+StaticDtorDeclaration *Parser::parseStaticDtor()
+{
+    StaticDtorDeclaration *f;
+    Loc loc = this->loc;
+
+    nextToken();
+    check(TOKthis);
+    check(TOKlparen);
+    check(TOKrparen);
+
+    f = new StaticDtorDeclaration(loc, 0);
+    parseContracts(f);
+    return f;
+}
+
+/*****************************************
+ * Parse an invariant definition:
+ *	invariant { body }
+ * Current token is 'invariant'.
+ */
+
+InvariantDeclaration *Parser::parseInvariant()
+{
+    InvariantDeclaration *f;
+    Loc loc = this->loc;
+
+    nextToken();
+    if (token.value == TOKlparen)	// optional ()
+    {
+	nextToken();
+	check(TOKrparen);
+    }
+
+    f = new InvariantDeclaration(loc, 0);
+    f->fbody = parseStatement(PScurly);
+    return f;
+}
+
+/*****************************************
+ * Parse a unittest definition:
+ *	unittest { body }
+ * Current token is 'unittest'.
+ */
+
+UnitTestDeclaration *Parser::parseUnitTest()
+{
+    UnitTestDeclaration *f;
+    Statement *body;
+    Loc loc = this->loc;
+
+    nextToken();
+
+    body = parseStatement(PScurly);
+
+    f = new UnitTestDeclaration(loc, this->loc);
+    f->fbody = body;
+    return f;
+}
+
+/*****************************************
+ * Parse a new definition:
+ *	new(arguments) { body }
+ * Current token is 'new'.
+ */
+
+NewDeclaration *Parser::parseNew()
+{
+    NewDeclaration *f;
+    Arguments *arguments;
+    int varargs;
+    Loc loc = this->loc;
+
+    nextToken();
+    arguments = parseParameters(&varargs);
+    f = new NewDeclaration(loc, 0, arguments, varargs);
+    parseContracts(f);
+    return f;
+}
+
+/*****************************************
+ * Parse a delete definition:
+ *	delete(arguments) { body }
+ * Current token is 'delete'.
+ */
+
+DeleteDeclaration *Parser::parseDelete()
+{
+    DeleteDeclaration *f;
+    Arguments *arguments;
+    int varargs;
+    Loc loc = this->loc;
+
+    nextToken();
+    arguments = parseParameters(&varargs);
+    if (varargs)
+	error("... not allowed in delete function parameter list");
+    f = new DeleteDeclaration(loc, 0, arguments);
+    parseContracts(f);
+    return f;
+}
+
+/**********************************************
+ * Parse parameter list.
+ */
+
+Arguments *Parser::parseParameters(int *pvarargs)
+{
+    Arguments *arguments = new Arguments();
+    int varargs = 0;
+    int hasdefault = 0;
+
+    check(TOKlparen);
+    while (1)
+    {   Type *tb;
+	Identifier *ai;
+	Type *at;
+	Argument *a;
+	unsigned storageClass;
+	Expression *ae;
+
+	ai = NULL;
+	storageClass = STCin;		// parameter is "in" by default
+	switch (token.value)
+	{
+	    case TOKrparen:
+		break;
+
+	    case TOKdotdotdot:
+		varargs = 1;
+		nextToken();
+		break;
+
+	    case TOKin:
+		storageClass = STCin;
+		nextToken();
+		goto L1;
+
+	    case TOKout:
+		storageClass = STCout;
+		nextToken();
+		goto L1;
+
+	    case TOKinout:
+	    case TOKref:
+		storageClass = STCref;
+		nextToken();
+		goto L1;
+
+	    case TOKlazy:
+		storageClass = STClazy;
+		nextToken();
+		goto L1;
+
+	    default:
+	    L1:
+		tb = parseBasicType();
+		at = parseDeclarator(tb, &ai);
+		ae = NULL;
+		if (token.value == TOKassign)	// = defaultArg
+		{   nextToken();
+		    ae = parseAssignExp();
+		    hasdefault = 1;
+		}
+		else
+		{   if (hasdefault)
+			error("default argument expected for %s",
+				ai ? ai->toChars() : at->toChars());
+		}
+		if (token.value == TOKdotdotdot)
+		{   /* This is:
+		     *	at ai ...
+		     */
+
+		    if (storageClass & (STCout | STCref))
+			error("variadic argument cannot be out or ref");
+		    varargs = 2;
+		    a = new Argument(storageClass, at, ai, ae);
+		    arguments->push(a);
+		    nextToken();
+		    break;
+		}
+		a = new Argument(storageClass, at, ai, ae);
+		arguments->push(a);
+		if (token.value == TOKcomma)
+		{   nextToken();
+		    continue;
+		}
+		break;
+	}
+	break;
+    }
+    check(TOKrparen);
+    *pvarargs = varargs;
+    return arguments;
+}
+
+
+/*************************************
+ */
+
+EnumDeclaration *Parser::parseEnum()
+{   EnumDeclaration *e;
+    Identifier *id;
+    Type *t;
+    Loc loc = this->loc;
+
+    //printf("Parser::parseEnum()\n");
+    nextToken();
+    if (token.value == TOKidentifier)
+    {	id = token.ident;
+	nextToken();
+    }
+    else
+	id = NULL;
+
+    if (token.value == TOKcolon)
+    {
+	nextToken();
+	t = parseBasicType();
+    }
+    else
+	t = NULL;
+
+    e = new EnumDeclaration(loc, id, t);
+    if (token.value == TOKsemicolon && id)
+ 	nextToken();
+    else if (token.value == TOKlcurly)
+    {
+	//printf("enum definition\n");
+	e->members = new Array();
+	nextToken();
+	unsigned char *comment = token.blockComment;
+	while (token.value != TOKrcurly)
+	{
+	    if (token.value == TOKidentifier)
+	    {	EnumMember *em;
+		Expression *value;
+		Identifier *ident;
+
+		loc = this->loc;
+		ident = token.ident;
+		value = NULL;
+		nextToken();
+		if (token.value == TOKassign)
+		{
+		    nextToken();
+		    value = parseAssignExp();
+		}
+		em = new EnumMember(loc, ident, value);
+		e->members->push(em);
+		if (token.value == TOKrcurly)
+		    ;
+		else
+		{   addComment(em, comment);
+		    comment = NULL;
+		    check(TOKcomma);
+		}
+		addComment(em, comment);
+		comment = token.blockComment;
+	    }
+	    else
+	    {	error("enum member expected");
+		nextToken();
+	    }
+	}
+	nextToken();
+    }
+    else
+	error("enum declaration is invalid");
+
+    return e;
+}
+
+Dsymbol *Parser::parseAggregate()
+{   AggregateDeclaration *a = NULL;
+    int anon = 0;
+    enum TOK tok;
+    Identifier *id;
+    TemplateParameters *tpl = NULL;
+
+    //printf("Parser::parseAggregate()\n");
+    tok = token.value;
+    nextToken();
+    if (token.value != TOKidentifier)
+    {	id = NULL;
+    }
+    else
+    {	id = token.ident;
+	nextToken();
+
+	if (token.value == TOKlparen)
+	{   // Class template declaration.
+
+	    // Gather template parameter list
+	    tpl = parseTemplateParameterList();
+	}
+    }
+
+    Loc loc = this->loc;
+    switch (tok)
+    {	case TOKclass:
+	case TOKinterface:
+	{
+	    if (!id)
+		error("anonymous classes not allowed");
+
+	    // Collect base class(es)
+	    BaseClasses *baseclasses = NULL;
+	    if (token.value == TOKcolon)
+	    {
+		nextToken();
+		baseclasses = parseBaseClasses();
+
+		if (token.value != TOKlcurly)
+		    error("members expected");
+	    }
+
+	    if (tok == TOKclass)
+		a = new ClassDeclaration(loc, id, baseclasses);
+	    else
+		a = new InterfaceDeclaration(loc, id, baseclasses);
+	    break;
+	}
+
+	case TOKstruct:
+	    if (id)
+		a = new StructDeclaration(loc, id);
+	    else
+		anon = 1;
+	    break;
+
+	case TOKunion:
+	    if (id)
+		a = new UnionDeclaration(loc, id);
+	    else
+		anon = 2;
+	    break;
+
+	default:
+	    assert(0);
+	    break;
+    }
+    if (a && token.value == TOKsemicolon)
+    { 	nextToken();
+    }
+    else if (token.value == TOKlcurly)
+    {
+	//printf("aggregate definition\n");
+	nextToken();
+	Array *decl = parseDeclDefs(0);
+	if (token.value != TOKrcurly)
+	    error("} expected following member declarations in aggregate");
+	nextToken();
+	if (anon)
+	{
+	    /* Anonymous structs/unions are more like attributes.
+	     */
+	    return new AnonDeclaration(loc, anon - 1, decl);
+	}
+	else
+	    a->members = decl;
+    }
+    else
+    {
+	error("{ } expected following aggregate declaration");
+	a = new StructDeclaration(loc, NULL);
+    }
+
+    if (tpl)
+    {	Array *decldefs;
+	TemplateDeclaration *tempdecl;
+
+	// Wrap a template around the aggregate declaration
+	decldefs = new Array();
+	decldefs->push(a);
+	tempdecl = new TemplateDeclaration(loc, id, tpl, decldefs);
+	return tempdecl;
+    }
+
+    return a;
+}
+
+/*******************************************
+ */
+
+BaseClasses *Parser::parseBaseClasses()
+{
+    enum PROT protection = PROTpublic;
+    BaseClasses *baseclasses = new BaseClasses();
+
+    for (; 1; nextToken())
+    {
+	switch (token.value)
+	{
+	    case TOKidentifier:
+		break;
+	    case TOKprivate:
+		protection = PROTprivate;
+		continue;
+	    case TOKpackage:
+		protection = PROTpackage;
+		continue;
+	    case TOKprotected:
+		protection = PROTprotected;
+		continue;
+	    case TOKpublic:
+		protection = PROTpublic;
+		continue;
+	    default:
+		error("base classes expected instead of %s", token.toChars());
+		return NULL;
+	}
+	BaseClass *b = new BaseClass(parseBasicType(), protection);
+	baseclasses->push(b);
+	if (token.value != TOKcomma)
+	    break;
+	protection = PROTpublic;
+    }
+    return baseclasses;
+}
+
+/**************************************
+ * Parse a TemplateDeclaration.
+ */
+
+TemplateDeclaration *Parser::parseTemplateDeclaration()
+{
+    TemplateDeclaration *tempdecl;
+    Identifier *id;
+    TemplateParameters *tpl;
+    Array *decldefs;
+    Loc loc = this->loc;
+
+    nextToken();
+    if (token.value != TOKidentifier)
+    {   error("TemplateIdentifier expected following template");
+	goto Lerr;
+    }
+    id = token.ident;
+    nextToken();
+    tpl = parseTemplateParameterList();
+    if (!tpl)
+	goto Lerr;
+
+    if (token.value != TOKlcurly)
+    {	error("members of template declaration expected");
+	goto Lerr;
+    }
+    else
+    {
+	nextToken();
+	decldefs = parseDeclDefs(0);
+	if (token.value != TOKrcurly)
+	{   error("template member expected");
+	    goto Lerr;
+	}
+	nextToken();
+    }
+
+    tempdecl = new TemplateDeclaration(loc, id, tpl, decldefs);
+    return tempdecl;
+
+Lerr:
+    return NULL;
+}
+
+/******************************************
+ * Parse template parameter list.
+ */
+
+TemplateParameters *Parser::parseTemplateParameterList()
+{
+    TemplateParameters *tpl;
+
+    if (token.value != TOKlparen)
+    {   error("parenthesized TemplateParameterList expected following TemplateIdentifier");
+	goto Lerr;
+    }
+    tpl = new TemplateParameters();
+    nextToken();
+
+    // Get array of TemplateParameters
+    if (token.value != TOKrparen)
+    {	int isvariadic = 0;
+
+	while (1)
+	{   TemplateParameter *tp;
+	    Identifier *tp_ident = NULL;
+	    Type *tp_spectype = NULL;
+	    Type *tp_valtype = NULL;
+	    Type *tp_defaulttype = NULL;
+	    Expression *tp_specvalue = NULL;
+	    Expression *tp_defaultvalue = NULL;
+	    Token *t;
+
+	    // Get TemplateParameter
+
+	    // First, look ahead to see if it is a TypeParameter or a ValueParameter
+	    t = peek(&token);
+	    if (token.value == TOKalias)
+	    {	// AliasParameter
+		nextToken();
+		if (token.value != TOKidentifier)
+		{   error("Identifier expected for template parameter");
+		    goto Lerr;
+		}
+		tp_ident = token.ident;
+		nextToken();
+		if (token.value == TOKcolon)	// : Type
+		{
+		    nextToken();
+		    tp_spectype = parseBasicType();
+		    tp_spectype = parseDeclarator(tp_spectype, NULL);
+		}
+		if (token.value == TOKassign)	// = Type
+		{
+		    nextToken();
+		    tp_defaulttype = parseBasicType();
+		    tp_defaulttype = parseDeclarator(tp_defaulttype, NULL);
+		}
+		tp = new TemplateAliasParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
+	    }
+	    else if (t->value == TOKcolon || t->value == TOKassign ||
+		     t->value == TOKcomma || t->value == TOKrparen)
+	    {	// TypeParameter
+		if (token.value != TOKidentifier)
+		{   error("Identifier expected for template parameter");
+		    goto Lerr;
+		}
+		tp_ident = token.ident;
+		nextToken();
+		if (token.value == TOKcolon)	// : Type
+		{
+		    nextToken();
+		    tp_spectype = parseBasicType();
+		    tp_spectype = parseDeclarator(tp_spectype, NULL);
+		}
+		if (token.value == TOKassign)	// = Type
+		{
+		    nextToken();
+		    tp_defaulttype = parseBasicType();
+		    tp_defaulttype = parseDeclarator(tp_defaulttype, NULL);
+		}
+		tp = new TemplateTypeParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
+	    }
+	    else if (token.value == TOKidentifier && t->value == TOKdotdotdot)
+	    {	// ident...
+		if (isvariadic)
+		    error("variadic template parameter must be last");
+		isvariadic = 1;
+		tp_ident = token.ident;
+		nextToken();
+		nextToken();
+		tp = new TemplateTupleParameter(loc, tp_ident);
+	    }
+	    else
+	    {	// ValueParameter
+		tp_valtype = parseBasicType();
+		tp_valtype = parseDeclarator(tp_valtype, &tp_ident);
+		if (!tp_ident)
+		{
+		    error("no identifier for template value parameter");
+		    goto Lerr;
+		}
+		if (token.value == TOKcolon)	// : CondExpression
+		{
+		    nextToken();
+		    tp_specvalue = parseCondExp();
+		}
+		if (token.value == TOKassign)	// = CondExpression
+		{
+		    nextToken();
+		    tp_defaultvalue = parseCondExp();
+		}
+		tp = new TemplateValueParameter(loc, tp_ident, tp_valtype, tp_specvalue, tp_defaultvalue);
+	    }
+	    tpl->push(tp);
+	    if (token.value != TOKcomma)
+		break;
+	    nextToken();
+	}
+    }
+    check(TOKrparen);
+    return tpl;
+
+Lerr:
+    return NULL;
+}
+
+/******************************************
+ * Parse template mixin.
+ *	mixin Foo;
+ *	mixin Foo!(args);
+ *	mixin a.b.c!(args).Foo!(args);
+ *	mixin Foo!(args) identifier;
+ *	mixin typeof(expr).identifier!(args);
+ */
+
+Dsymbol *Parser::parseMixin()
+{
+    TemplateMixin *tm;
+    Identifier *id;
+    Type *tqual;
+    Objects *tiargs;
+    Array *idents;
+
+    //printf("parseMixin()\n");
+    nextToken();
+    tqual = NULL;
+    if (token.value == TOKdot)
+    {
+	id = Id::empty;
+    }
+    else
+    {
+	if (token.value == TOKtypeof)
+	{   Expression *exp;
+
+	    nextToken();
+	    check(TOKlparen);
+	    exp = parseExpression();
+	    check(TOKrparen);
+	    tqual = new TypeTypeof(loc, exp);
+	    check(TOKdot);
+	}
+	if (token.value != TOKidentifier)
+	{
+	    error("identifier expected, not %s", token.toChars());
+	    goto Lerr;
+	}
+	id = token.ident;
+	nextToken();
+    }
+
+    idents = new Array();
+    while (1)
+    {
+	tiargs = NULL;
+	if (token.value == TOKnot)
+	{
+	    nextToken();
+	    tiargs = parseTemplateArgumentList();
+	}
+
+	if (token.value != TOKdot)
+	    break;
+
+	if (tiargs)
+	{   TemplateInstance *tempinst = new TemplateInstance(loc, id);
+	    tempinst->tiargs = tiargs;
+	    id = (Identifier *)tempinst;
+	    tiargs = NULL;
+	}
+	idents->push(id);
+
+	nextToken();
+	if (token.value != TOKidentifier)
+	{   error("identifier expected following '.' instead of '%s'", token.toChars());
+	    break;
+	}
+	id = token.ident;
+	nextToken();
+    }
+    idents->push(id);
+
+    if (token.value == TOKidentifier)
+    {
+	id = token.ident;
+	nextToken();
+    }
+    else
+	id = NULL;
+
+    tm = new TemplateMixin(loc, id, tqual, idents, tiargs);
+    if (token.value != TOKsemicolon)
+	error("';' expected after mixin");
+    nextToken();
+
+    return tm;
+
+Lerr:
+    return NULL;
+}
+
+/******************************************
+ * Parse template argument list.
+ * Input:
+ * 	current token is opening '('
+ * Output:
+ *	current token is one after closing ')'
+ */
+
+Objects *Parser::parseTemplateArgumentList()
+{
+    //printf("Parser::parseTemplateArgumentList()\n");
+    Objects *tiargs = new Objects();
+    if (token.value != TOKlparen)
+    {   error("!(TemplateArgumentList) expected following TemplateIdentifier");
+	return tiargs;
+    }
+    nextToken();
+
+    // Get TemplateArgumentList
+    if (token.value != TOKrparen)
+    {
+	while (1)
+	{
+	    // See if it is an Expression or a Type
+	    if (isDeclaration(&token, 0, TOKreserved, NULL))
+	    {	// Type
+		Type *ta;
+
+		// Get TemplateArgument
+		ta = parseBasicType();
+		ta = parseDeclarator(ta, NULL);
+		tiargs->push(ta);
+	    }
+	    else
+	    {	// Expression
+		Expression *ea;
+
+		ea = parseAssignExp();
+		tiargs->push(ea);
+	    }
+	    if (token.value != TOKcomma)
+		break;
+	    nextToken();
+	}
+    }
+    check(TOKrparen, "template argument list");
+    return tiargs;
+}
+
+Import *Parser::parseImport(Array *decldefs, int isstatic)
+{   Import *s;
+    Identifier *id;
+    Identifier *aliasid = NULL;
+    Array *a;
+    Loc loc;
+
+    //printf("Parser::parseImport()\n");
+    do
+    {
+     L1:
+	nextToken();
+	if (token.value != TOKidentifier)
+	{   error("Identifier expected following import");
+	    break;
+	}
+
+	loc = this->loc;
+	a = NULL;
+	id = token.ident;
+	nextToken();
+	if (!aliasid && token.value == TOKassign)
+	{
+	    aliasid = id;
+	    goto L1;
+	}
+	while (token.value == TOKdot)
+	{
+	    if (!a)
+		a = new Array();
+	    a->push(id);
+	    nextToken();
+	    if (token.value != TOKidentifier)
+	    {   error("Identifier expected following package");
+		break;
+	    }
+	    id = token.ident;
+	    nextToken();
+	}
+
+	s = new Import(loc, a, token.ident, aliasid, isstatic);
+	decldefs->push(s);
+
+	/* Look for
+	 *	: alias=name, alias=name;
+	 * syntax.
+	 */
+	if (token.value == TOKcolon)
+	{
+	    do
+	    {	Identifier *name;
+		Identifier *alias;
+
+		nextToken();
+		if (token.value != TOKidentifier)
+		{   error("Identifier expected following :");
+		    break;
+		}
+		alias = token.ident;
+		nextToken();
+		if (token.value == TOKassign)
+		{
+		    nextToken();
+		    if (token.value != TOKidentifier)
+		    {   error("Identifier expected following %s=", alias->toChars());
+			break;
+		    }
+		    name = token.ident;
+		    nextToken();
+		}
+		else
+		{   name = alias;
+		    alias = NULL;
+		}
+		s->addAlias(name, alias);
+	    } while (token.value == TOKcomma);
+	    break;	// no comma-separated imports of this form
+	}
+
+	aliasid = NULL;
+    } while (token.value == TOKcomma);
+
+    if (token.value == TOKsemicolon)
+ 	nextToken();
+    else
+    {
+	error("';' expected");
+	nextToken();
+    }
+
+    return NULL;
+}
+
+Type *Parser::parseBasicType()
+{   Type *t;
+    Identifier *id;
+    TypeQualified *tid;
+    TemplateInstance *tempinst;
+
+    //printf("parseBasicType()\n");
+    switch (token.value)
+    {
+	CASE_BASIC_TYPES_X(t):
+	    nextToken();
+	    break;
+
+	case TOKidentifier:
+	    id = token.ident;
+	    nextToken();
+	    if (token.value == TOKnot)
+	    {
+		nextToken();
+		tempinst = new TemplateInstance(loc, id);
+		tempinst->tiargs = parseTemplateArgumentList();
+		tid = new TypeInstance(loc, tempinst);
+		goto Lident2;
+	    }
+	Lident:
+	    tid = new TypeIdentifier(loc, id);
+	Lident2:
+	    while (token.value == TOKdot)
+	    {	nextToken();
+		if (token.value != TOKidentifier)
+		{   error("identifier expected following '.' instead of '%s'", token.toChars());
+		    break;
+		}
+		id = token.ident;
+		nextToken();
+		if (token.value == TOKnot)
+		{
+		    nextToken();
+		    tempinst = new TemplateInstance(loc, id);
+		    tempinst->tiargs = parseTemplateArgumentList();
+		    tid->addIdent((Identifier *)tempinst);
+		}
+		else
+		    tid->addIdent(id);
+	    }
+	    t = tid;
+	    break;
+
+	case TOKdot:
+	    id = Id::empty;
+	    goto Lident;
+
+	case TOKtypeof:
+	{   Expression *exp;
+
+	    nextToken();
+	    check(TOKlparen);
+	    exp = parseExpression();
+	    check(TOKrparen);
+	    tid = new TypeTypeof(loc, exp);
+	    goto Lident2;
+	}
+
+	default:
+	    error("basic type expected, not %s", token.toChars());
+	    t = Type::tint32;
+	    break;
+    }
+    return t;
+}
+
+Type *Parser::parseBasicType2(Type *t)
+{
+    Type *ts;
+    Type *ta;
+
+    //printf("parseBasicType2()\n");
+    while (1)
+    {
+	switch (token.value)
+	{
+	    case TOKmul:
+		t = new TypePointer(t);
+		nextToken();
+		continue;
+
+	    case TOKlbracket:
+#if LTORARRAYDECL
+		// Handle []. Make sure things like
+		//     int[3][1] a;
+		// is (array[1] of array[3] of int)
+		nextToken();
+		if (token.value == TOKrbracket)
+		{
+		    t = new TypeDArray(t);			// []
+		    nextToken();
+		}
+		else if (isDeclaration(&token, 0, TOKrbracket, NULL))
+		{   // It's an associative array declaration
+		    Type *index;
+
+		    //printf("it's an associative array\n");
+		    index = parseBasicType();
+		    index = parseDeclarator(index, NULL);	// [ type ]
+		    t = new TypeAArray(t, index);
+		    check(TOKrbracket);
+		}
+		else
+		{
+		    //printf("it's [expression]\n");
+		    inBrackets++;
+		    Expression *e = parseExpression();		// [ expression ]
+		    if (token.value == TOKslice)
+		    {	Expression *e2;
+
+			nextToken();
+			e2 = parseExpression();			// [ exp .. exp ]
+			t = new TypeSlice(t, e, e2);
+		    }
+		    else
+			t = new TypeSArray(t,e);
+		    inBrackets--;
+		    check(TOKrbracket);
+		}
+		continue;
+#else
+		// Handle []. Make sure things like
+		//     int[3][1] a;
+		// is (array[3] of array[1] of int)
+		ts = t;
+		while (token.value == TOKlbracket)
+		{
+		    nextToken();
+		    if (token.value == TOKrbracket)
+		    {
+			ta = new TypeDArray(t);			// []
+			nextToken();
+		    }
+		    else if (isDeclaration(&token, 0, TOKrbracket, NULL))
+		    {   // It's an associative array declaration
+			Type *index;
+
+			//printf("it's an associative array\n");
+			index = parseBasicType();
+			index = parseDeclarator(index, NULL);	// [ type ]
+			check(TOKrbracket);
+			ta = new TypeAArray(t, index);
+		    }
+		    else
+		    {
+			//printf("it's [expression]\n");
+			Expression *e = parseExpression();	// [ expression ]
+			ta = new TypeSArray(t,e);
+			check(TOKrbracket);
+		    }
+		    Type **pt;
+		    for (pt = &ts; *pt != t; pt = &(*pt)->next)
+			;
+		    *pt = ta;
+		}
+		t = ts;
+		continue;
+#endif
+
+	    case TOKdelegate:
+	    case TOKfunction:
+	    {	// Handle delegate declaration:
+		//	t delegate(parameter list)
+		//	t function(parameter list)
+		Arguments *arguments;
+		int varargs;
+		enum TOK save = token.value;
+
+		nextToken();
+		arguments = parseParameters(&varargs);
+		t = new TypeFunction(arguments, t, varargs, linkage);
+		if (save == TOKdelegate)
+		    t = new TypeDelegate(t);
+		else
+		    t = new TypePointer(t);	// pointer to function
+		continue;
+	    }
+
+	    default:
+		ts = t;
+		break;
+	}
+	break;
+    }
+    return ts;
+}
+
+Type *Parser::parseDeclarator(Type *t, Identifier **pident, TemplateParameters **tpl)
+{   Type *ts;
+    Type *ta;
+
+    //printf("parseDeclarator(tpl = %p)\n", tpl);
+    t = parseBasicType2(t);
+
+    switch (token.value)
+    {
+
+	case TOKidentifier:
+	    if (pident)
+		*pident = token.ident;
+	    else
+		error("unexpected identifer '%s' in declarator", token.ident->toChars());
+	    ts = t;
+	    nextToken();
+	    break;
+
+	case TOKlparen:
+	    nextToken();
+	    ts = parseDeclarator(t, pident);
+	    check(TOKrparen);
+	    break;
+
+	default:
+	    ts = t;
+	    break;
+    }
+
+    while (1)
+    {
+	switch (token.value)
+	{
+#if CARRAYDECL
+	    case TOKlbracket:
+	    {	// This is the old C-style post [] syntax.
+		nextToken();
+		if (token.value == TOKrbracket)
+		{
+		    ta = new TypeDArray(t);			// []
+		    nextToken();
+		}
+		else if (isDeclaration(&token, 0, TOKrbracket, NULL))
+		{   // It's an associative array declaration
+		    Type *index;
+
+		    //printf("it's an associative array\n");
+		    index = parseBasicType();
+		    index = parseDeclarator(index, NULL);	// [ type ]
+		    check(TOKrbracket);
+		    ta = new TypeAArray(t, index);
+		}
+		else
+		{
+		    //printf("it's [expression]\n");
+		    Expression *e = parseExpression();		// [ expression ]
+		    ta = new TypeSArray(t, e);
+		    check(TOKrbracket);
+		}
+		Type **pt;
+		for (pt = &ts; *pt != t; pt = &(*pt)->next)
+		    ;
+		*pt = ta;
+		continue;
+	    }
+#endif
+	    case TOKlparen:
+	    {	Arguments *arguments;
+		int varargs;
+		Type **pt;
+
+		if (tpl)
+		{
+		    /* Look ahead to see if this is (...)(...),
+		     * i.e. a function template declaration
+		     */
+		    if (peekPastParen(&token)->value == TOKlparen)
+		    {   // It's a function template declaration
+			//printf("function template declaration\n");
+
+			// Gather template parameter list
+			*tpl = parseTemplateParameterList();
+		    }
+		}
+
+		arguments = parseParameters(&varargs);
+		ta = new TypeFunction(arguments, t, varargs, linkage);
+		for (pt = &ts; *pt != t; pt = &(*pt)->next)
+		    ;
+		*pt = ta;
+		break;
+	    }
+	}
+	break;
+    }
+
+    return ts;
+}
+
+/**********************************
+ * Return array of Declaration *'s.
+ */
+
+Array *Parser::parseDeclarations()
+{
+    enum STC storage_class;
+    enum STC stc;
+    Type *ts;
+    Type *t;
+    Type *tfirst;
+    Identifier *ident;
+    Array *a;
+    enum TOK tok;
+    unsigned char *comment = token.blockComment;
+    enum LINK link = linkage;
+
+    //printf("parseDeclarations()\n");
+    switch (token.value)
+    {
+	case TOKtypedef:
+	case TOKalias:
+	    tok = token.value;
+	    nextToken();
+	    break;
+
+	default:
+	    tok = TOKreserved;
+	    break;
+    }
+
+    storage_class = STCundefined;
+    while (1)
+    {
+	switch (token.value)
+	{
+	    case TOKconst:	stc = STCconst;		 goto L1;
+	    case TOKstatic:	stc = STCstatic;	 goto L1;
+	    case TOKfinal:	stc = STCfinal;		 goto L1;
+	    case TOKauto:	stc = STCauto;		 goto L1;
+	    case TOKscope:	stc = STCscope;		 goto L1;
+	    case TOKoverride:	stc = STCoverride;	 goto L1;
+	    case TOKabstract:	stc = STCabstract;	 goto L1;
+	    case TOKsynchronized: stc = STCsynchronized; goto L1;
+	    case TOKdeprecated: stc = STCdeprecated;	 goto L1;
+	    L1:
+		if (storage_class & stc)
+		    error("redundant storage class '%s'", token.toChars());
+		storage_class = (STC) (storage_class | stc);
+		nextToken();
+		continue;
+
+	    case TOKextern:
+		if (peek(&token)->value != TOKlparen)
+		{   stc = STCextern;
+		    goto L1;
+		}
+
+		link = parseLinkage();
+		continue;
+
+	    default:
+		break;
+	}
+	break;
+    }
+
+    a = new Array();
+
+    /* Look for auto initializers:
+     *	storage_class identifier = initializer;
+     */
+    while (storage_class &&
+	token.value == TOKidentifier &&
+	peek(&token)->value == TOKassign)
+    {
+	ident = token.ident;
+	nextToken();
+	nextToken();
+	Initializer *init = parseInitializer();
+	VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init);
+	v->storage_class = storage_class;
+	a->push(v);
+	if (token.value == TOKsemicolon)
+	{
+	    nextToken();
+	    addComment(v, comment);
+	}
+	else if (token.value == TOKcomma)
+	{
+	    nextToken();
+	    if (!(token.value == TOKidentifier && peek(&token)->value == TOKassign))
+	    {
+		error("Identifier expected following comma");
+	    }
+	    else
+		continue;
+	}
+	else
+	    error("semicolon expected following auto declaration, not '%s'", token.toChars());
+	return a;
+    }
+
+    if (token.value == TOKclass)
+    {	AggregateDeclaration *s;
+
+	s = (AggregateDeclaration *)parseAggregate();
+	s->storage_class |= storage_class;
+	a->push(s);
+	addComment(s, comment);
+	return a;
+    }
+
+    ts = parseBasicType();
+    ts = parseBasicType2(ts);
+    tfirst = NULL;
+
+    while (1)
+    {
+	Loc loc = this->loc;
+	TemplateParameters *tpl = NULL;
+
+	ident = NULL;
+	t = parseDeclarator(ts, &ident, &tpl);
+	assert(t);
+	if (!tfirst)
+	    tfirst = t;
+	else if (t != tfirst)
+	    error("multiple declarations must have the same type, not %s and %s",
+		tfirst->toChars(), t->toChars());
+	if (!ident)
+	    error("no identifier for declarator %s", t->toChars());
+
+	if (tok == TOKtypedef || tok == TOKalias)
+	{   Declaration *v;
+	    Initializer *init;
+
+	    init = NULL;
+	    if (token.value == TOKassign)
+	    {
+		nextToken();
+		init = parseInitializer();
+	    }
+	    if (tok == TOKtypedef)
+		v = new TypedefDeclaration(loc, ident, t, init);
+	    else
+	    {	if (init)
+		    error("alias cannot have initializer");
+		v = new AliasDeclaration(loc, ident, t);
+	    }
+	    v->storage_class = storage_class;
+	    if (link == linkage)
+		a->push(v);
+	    else
+	    {
+		Array *ax = new Array();
+		ax->push(v);
+		Dsymbol *s = new LinkDeclaration(link, ax);
+		a->push(s);
+	    }
+	    switch (token.value)
+	    {   case TOKsemicolon:
+		    nextToken();
+		    addComment(v, comment);
+		    break;
+
+		case TOKcomma:
+		    nextToken();
+		    addComment(v, comment);
+		    continue;
+
+		default:
+		    error("semicolon expected to close %s declaration", Token::toChars(tok));
+		    break;
+	    }
+	}
+	else if (t->ty == Tfunction)
+	{   FuncDeclaration *f;
+	    Dsymbol *s;
+
+	    f = new FuncDeclaration(loc, 0, ident, storage_class, t);
+	    addComment(f, comment);
+	    parseContracts(f);
+	    addComment(f, NULL);
+	    if (link == linkage)
+	    {
+		s = f;
+	    }
+	    else
+	    {
+		Array *ax = new Array();
+		ax->push(f);
+		s = new LinkDeclaration(link, ax);
+	    }
+	    if (tpl)			// it's a function template
+	    {   Array *decldefs;
+		TemplateDeclaration *tempdecl;
+
+		// Wrap a template around the aggregate declaration
+		decldefs = new Array();
+		decldefs->push(s);
+		tempdecl = new TemplateDeclaration(loc, s->ident, tpl, decldefs);
+		s = tempdecl;
+	    }
+	    addComment(s, comment);
+	    a->push(s);
+	}
+	else
+	{   VarDeclaration *v;
+	    Initializer *init;
+
+	    init = NULL;
+	    if (token.value == TOKassign)
+	    {
+		nextToken();
+		init = parseInitializer();
+	    }
+	    v = new VarDeclaration(loc, t, ident, init);
+	    v->storage_class = storage_class;
+	    if (link == linkage)
+		a->push(v);
+	    else
+	    {
+		Array *ax = new Array();
+		ax->push(v);
+		Dsymbol *s = new LinkDeclaration(link, ax);
+		a->push(s);
+	    }
+	    switch (token.value)
+	    {   case TOKsemicolon:
+		    nextToken();
+		    addComment(v, comment);
+		    break;
+
+		case TOKcomma:
+		    nextToken();
+		    addComment(v, comment);
+		    continue;
+
+		default:
+		    error("semicolon expected, not '%s'", token.toChars());
+		    break;
+	    }
+	}
+	break;
+    }
+    return a;
+}
+
+/*****************************************
+ * Parse contracts following function declaration.
+ */
+
+void Parser::parseContracts(FuncDeclaration *f)
+{
+    Type *tb;
+    enum LINK linksave = linkage;
+
+    // The following is irrelevant, as it is overridden by sc->linkage in
+    // TypeFunction::semantic
+    linkage = LINKd;		// nested functions have D linkage
+L1:
+    switch (token.value)
+    {
+	case TOKlcurly:
+	    if (f->frequire || f->fensure)
+		error("missing body { ... } after in or out");
+	    f->fbody = parseStatement(PSsemi);
+	    f->endloc = endloc;
+	    break;
+
+	case TOKbody:
+	    nextToken();
+	    f->fbody = parseStatement(PScurly);
+	    f->endloc = endloc;
+	    break;
+
+	case TOKsemicolon:
+	    if (f->frequire || f->fensure)
+		error("missing body { ... } after in or out");
+	    nextToken();
+	    break;
+
+#if 0	// Do we want this for function declarations, so we can do:
+    // int x, y, foo(), z;
+	case TOKcomma:
+	    nextToken();
+	    continue;
+#endif
+
+#if 0 // Dumped feature
+	case TOKthrow:
+	    if (!f->fthrows)
+		f->fthrows = new Array();
+	    nextToken();
+	    check(TOKlparen);
+	    while (1)
+	    {
+		tb = parseBasicType();
+		f->fthrows->push(tb);
+		if (token.value == TOKcomma)
+		{   nextToken();
+		    continue;
+		}
+		break;
+	    }
+	    check(TOKrparen);
+	    goto L1;
+#endif
+
+	case TOKin:
+	    nextToken();
+	    if (f->frequire)
+		error("redundant 'in' statement");
+	    f->frequire = parseStatement(PScurly | PSscope);
+	    goto L1;
+
+	case TOKout:
+	    // parse: out (identifier) { statement }
+	    nextToken();
+	    if (token.value != TOKlcurly)
+	    {
+		check(TOKlparen);
+		if (token.value != TOKidentifier)	   
+		    error("(identifier) following 'out' expected, not %s", token.toChars());
+		f->outId = token.ident;
+		nextToken();
+		check(TOKrparen);
+	    }
+	    if (f->fensure)
+		error("redundant 'out' statement");
+	    f->fensure = parseStatement(PScurly | PSscope);
+	    goto L1;
+
+	default:
+	    error("semicolon expected following function declaration");
+	    break;
+    }
+    linkage = linksave;
+}
+
+/*****************************************
+ */
+
+Initializer *Parser::parseInitializer()
+{
+    StructInitializer *is;
+    ArrayInitializer *ia;
+    ExpInitializer *ie;
+    Expression *e;
+    Identifier *id;
+    Initializer *value;
+    int comma;
+    Loc loc = this->loc;
+    Token *t;
+    int braces;
+
+    switch (token.value)
+    {
+	case TOKlcurly:
+	    /* Scan ahead to see if it is a struct initializer or
+	     * a function literal.
+	     * If it contains a ';', it is a function literal.
+	     * Treat { } as a struct initializer.
+	     */
+	    braces = 1;
+	    for (t = peek(&token); 1; t = peek(t))
+	    {
+		switch (t->value)
+		{
+		    case TOKsemicolon:
+		    case TOKreturn:
+			goto Lexpression;
+
+		    case TOKlcurly:
+			braces++;
+			continue;
+
+		    case TOKrcurly:
+			if (--braces == 0)
+			    break;
+			continue;
+
+		    default:
+			continue;
+		}
+		break;
+	    }
+
+	    is = new StructInitializer(loc);
+	    nextToken();
+	    comma = 0;
+	    while (1)
+	    {
+		switch (token.value)
+		{
+		    case TOKidentifier:
+			if (comma == 1)
+			    error("comma expected separating field initializers");
+			t = peek(&token);
+			if (t->value == TOKcolon)
+			{
+			    id = token.ident;
+			    nextToken();
+			    nextToken();	// skip over ':'
+			}
+			else
+			{   id = NULL;
+			}
+			value = parseInitializer();
+			is->addInit(id, value);
+			comma = 1;
+			continue;
+
+		    case TOKcomma:
+			nextToken();
+			comma = 2;
+			continue;
+
+		    case TOKrcurly:		// allow trailing comma's
+			nextToken();
+			break;
+
+		    default:
+			value = parseInitializer();
+			is->addInit(NULL, value);
+			comma = 1;
+			continue;
+			//error("found '%s' instead of field initializer", token.toChars());
+			//break;
+		}
+		break;
+	    }
+	    return is;
+
+	case TOKlbracket:
+	    ia = new ArrayInitializer(loc);
+	    nextToken();
+	    comma = 0;
+	    while (1)
+	    {
+		switch (token.value)
+		{
+		    default:
+			if (comma == 1)
+			{   error("comma expected separating array initializers, not %s", token.toChars());
+			    nextToken();
+			    break;
+			}
+			e = parseAssignExp();
+			if (!e)
+			    break;
+			if (token.value == TOKcolon)
+			{
+			    nextToken();
+			    value = parseInitializer();
+			}
+			else
+			{   value = new ExpInitializer(e->loc, e);
+			    e = NULL;
+			}
+			ia->addInit(e, value);
+			comma = 1;
+			continue;
+
+		    case TOKlcurly:
+		    case TOKlbracket:
+			if (comma == 1)
+			    error("comma expected separating array initializers, not %s", token.toChars());
+			value = parseInitializer();
+			ia->addInit(NULL, value);
+			comma = 1;
+			continue;
+
+		    case TOKcomma:
+			nextToken();
+			comma = 2;
+			continue;
+
+		    case TOKrbracket:		// allow trailing comma's
+			nextToken();
+			break;
+
+		    case TOKeof:
+			error("found '%s' instead of array initializer", token.toChars());
+			break;
+		}
+		break;
+	    }
+	    return ia;
+
+	case TOKvoid:
+	    t = peek(&token);
+	    if (t->value == TOKsemicolon || t->value == TOKcomma)
+	    {
+		nextToken();
+		return new VoidInitializer(loc);
+	    }
+	    goto Lexpression;
+
+	default:
+	Lexpression:
+	    e = parseAssignExp();
+	    ie = new ExpInitializer(loc, e);
+	    return ie;
+    }
+}
+
+
+/*****************************************
+ * Input:
+ *	flags	PSxxxx
+ */
+
+Statement *Parser::parseStatement(int flags)
+{   Statement *s;
+    Token *t;
+    Condition *condition;
+    Statement *ifbody;
+    Statement *elsebody;
+    Loc loc = this->loc;
+
+    //printf("parseStatement()\n");
+
+    if (flags & PScurly && token.value != TOKlcurly)
+	error("statement expected to be { }, not %s", token.toChars());
+
+    switch (token.value)
+    {
+	case TOKidentifier:
+	    // Need to look ahead to see if it is a declaration, label, or expression
+	    t = peek(&token);
+	    if (t->value == TOKcolon)
+	    {	// It's a label
+		Identifier *ident;
+
+		ident = token.ident;
+		nextToken();
+		nextToken();
+		s = parseStatement(PSsemi);
+		s = new LabelStatement(loc, ident, s);
+		break;
+	    }
+	    // fallthrough to TOKdot
+	case TOKdot:
+	case TOKtypeof:
+	    if (isDeclaration(&token, 2, TOKreserved, NULL))
+		goto Ldeclaration;
+	    else
+		goto Lexp;
+	    break;
+
+	case TOKassert:
+	case TOKthis:
+	case TOKsuper:
+	case TOKint32v:
+	case TOKuns32v:
+	case TOKint64v:
+	case TOKuns64v:
+	case TOKfloat32v:
+	case TOKfloat64v:
+	case TOKfloat80v:
+	case TOKimaginary32v:
+	case TOKimaginary64v:
+	case TOKimaginary80v:
+	case TOKcharv:
+	case TOKwcharv:
+	case TOKdcharv:
+	case TOKnull:
+	case TOKtrue:
+	case TOKfalse:
+	case TOKstring:
+	case TOKlparen:
+	case TOKcast:
+	case TOKmul:
+	case TOKmin:
+	case TOKadd:
+	case TOKplusplus:
+	case TOKminusminus:
+	case TOKnew:
+	case TOKdelete:
+	case TOKdelegate:
+	case TOKfunction:
+	case TOKtypeid:
+	case TOKis:
+	case TOKlbracket:
+	Lexp:
+	{   Expression *exp;
+
+	    exp = parseExpression();
+	    check(TOKsemicolon, "statement");
+	    s = new ExpStatement(loc, exp);
+	    break;
+	}
+
+	case TOKstatic:
+	{   // Look ahead to see if it's static assert() or static if()
+	    Token *t;
+
+	    t = peek(&token);
+	    if (t->value == TOKassert)
+	    {
+		nextToken();
+		s = new StaticAssertStatement(parseStaticAssert());
+		break;
+	    }
+	    if (t->value == TOKif)
+	    {
+		nextToken();
+		condition = parseStaticIfCondition();
+		goto Lcondition;
+	    }
+	    goto Ldeclaration;
+	}
+
+	CASE_BASIC_TYPES:
+	case TOKtypedef:
+	case TOKalias:
+	case TOKconst:
+	case TOKauto:
+	case TOKextern:
+	case TOKfinal:
+	case TOKinvariant:
+//	case TOKtypeof:
+	Ldeclaration:
+	{   Array *a;
+
+	    a = parseDeclarations();
+	    if (a->dim > 1)
+	    {
+		Statements *as = new Statements();
+		as->reserve(a->dim);
+		for (int i = 0; i < a->dim; i++)
+		{
+		    Dsymbol *d = (Dsymbol *)a->data[i];
+		    s = new DeclarationStatement(loc, d);
+		    as->push(s);
+		}
+		s = new CompoundStatement(loc, as);
+	    }
+	    else if (a->dim == 1)
+	    {
+		Dsymbol *d = (Dsymbol *)a->data[0];
+		s = new DeclarationStatement(loc, d);
+	    }
+	    else
+		assert(0);
+	    if (flags & PSscope)
+		s = new ScopeStatement(loc, s);
+	    break;
+	}
+
+	case TOKstruct:
+	case TOKunion:
+	case TOKclass:
+	case TOKinterface:
+	{   Dsymbol *d;
+
+	    d = parseAggregate();
+	    s = new DeclarationStatement(loc, d);
+	    break;
+	}
+
+	case TOKenum:
+	{   Dsymbol *d;
+
+	    d = parseEnum();
+	    s = new DeclarationStatement(loc, d);
+	    break;
+	}
+
+	case TOKmixin:
+	{   t = peek(&token);
+	    if (t->value == TOKlparen)
+	    {	// mixin(string)
+		nextToken();
+		check(TOKlparen, "mixin");
+		Expression *e = parseAssignExp();
+		check(TOKrparen);
+		check(TOKsemicolon);
+		s = new CompileStatement(loc, e);
+		break;
+	    }
+	    Dsymbol *d = parseMixin();
+	    s = new DeclarationStatement(loc, d);
+	    break;
+	}
+
+	case TOKlcurly:
+	{   Statements *statements;
+
+	    nextToken();
+	    statements = new Statements();
+	    while (token.value != TOKrcurly)
+	    {
+		statements->push(parseStatement(PSsemi | PScurlyscope));
+	    }
+	    endloc = this->loc;
+	    s = new CompoundStatement(loc, statements);
+	    if (flags & (PSscope | PScurlyscope))
+		s = new ScopeStatement(loc, s);
+	    nextToken();
+	    break;
+	}
+
+	case TOKwhile:
+	{   Expression *condition;
+	    Statement *body;
+
+	    nextToken();
+	    check(TOKlparen);
+	    condition = parseExpression();
+	    check(TOKrparen);
+	    body = parseStatement(PSscope);
+	    s = new WhileStatement(loc, condition, body);
+	    break;
+	}
+
+	case TOKsemicolon:
+	    if (!(flags & PSsemi))
+		error("use '{ }' for an empty statement, not a ';'");
+	    nextToken();
+	    s = new ExpStatement(loc, NULL);
+	    break;
+
+	case TOKdo:
+	{   Statement *body;
+	    Expression *condition;
+
+	    nextToken();
+	    body = parseStatement(PSscope);
+	    check(TOKwhile);
+	    check(TOKlparen);
+	    condition = parseExpression();
+	    check(TOKrparen);
+	    s = new DoStatement(loc, body, condition);
+	    break;
+	}
+
+	case TOKfor:
+	{
+	    Statement *init;
+	    Expression *condition;
+	    Expression *increment;
+	    Statement *body;
+
+	    nextToken();
+	    check(TOKlparen);
+	    if (token.value == TOKsemicolon)
+	    {	init = NULL;
+		nextToken();
+	    }
+	    else
+	    {	init = parseStatement(0);
+	    }
+	    if (token.value == TOKsemicolon)
+	    {
+		condition = NULL;
+		nextToken();
+	    }
+	    else
+	    {
+		condition = parseExpression();
+		check(TOKsemicolon, "for condition");
+	    }
+	    if (token.value == TOKrparen)
+	    {	increment = NULL;
+		nextToken();
+	    }
+	    else
+	    {	increment = parseExpression();
+		check(TOKrparen);
+	    }
+	    body = parseStatement(PSscope);
+	    s = new ForStatement(loc, init, condition, increment, body);
+	    if (init)
+		s = new ScopeStatement(loc, s);
+	    break;
+	}
+
+	case TOKforeach:
+	case TOKforeach_reverse:
+	{
+	    enum TOK op = token.value;
+	    Arguments *arguments;
+
+	    Statement *d;
+	    Statement *body;
+	    Expression *aggr;
+
+	    nextToken();
+	    check(TOKlparen);
+
+	    arguments = new Arguments();
+
+	    while (1)
+	    {
+		Type *tb;
+		Identifier *ai = NULL;
+		Type *at;
+		unsigned storageClass;
+		Argument *a;
+
+		storageClass = STCin;
+		if (token.value == TOKinout || token.value == TOKref)
+		{   storageClass = STCref;
+		    nextToken();
+		}
+		if (token.value == TOKidentifier)
+		{
+		    Token *t = peek(&token);
+		    if (t->value == TOKcomma || t->value == TOKsemicolon)
+		    {	ai = token.ident;
+			at = NULL;		// infer argument type
+			nextToken();
+			goto Larg;
+		    }
+		}
+		tb = parseBasicType();
+		at = parseDeclarator(tb, &ai);
+		if (!ai)
+		    error("no identifier for declarator %s", at->toChars());
+	      Larg:
+		a = new Argument(storageClass, at, ai, NULL);
+		arguments->push(a);
+		if (token.value == TOKcomma)
+		{   nextToken();
+		    continue;
+		}
+		break;
+	    }
+	    check(TOKsemicolon);
+
+	    aggr = parseExpression();
+	    check(TOKrparen);
+	    body = parseStatement(0);
+	    s = new ForeachStatement(loc, op, arguments, aggr, body);
+	    break;
+	}
+
+	case TOKif:
+	{   Argument *arg = NULL;
+	    Expression *condition;
+	    Statement *ifbody;
+	    Statement *elsebody;
+
+	    nextToken();
+	    check(TOKlparen);
+
+	    if (token.value == TOKauto)
+	    {
+		nextToken();
+		if (token.value == TOKidentifier)
+		{
+		    Token *t = peek(&token);
+		    if (t->value == TOKassign)
+		    {
+			arg = new Argument(STCin, NULL, token.ident, NULL);
+			nextToken();
+			nextToken();
+		    }
+		    else
+		    {   error("= expected following auto identifier");
+			goto Lerror;
+		    }
+		}
+		else
+		{   error("identifier expected following auto");
+		    goto Lerror;
+		}
+	    }
+	    else if (isDeclaration(&token, 2, TOKassign, NULL))
+	    {
+		Type *tb;
+		Type *at;
+		Identifier *ai;
+
+		tb = parseBasicType();
+		at = parseDeclarator(tb, &ai);
+		check(TOKassign);
+		arg = new Argument(STCin, at, ai, NULL);
+	    }
+
+	    // Check for " ident;"
+	    else if (token.value == TOKidentifier)
+	    {
+		Token *t = peek(&token);
+		if (t->value == TOKcomma || t->value == TOKsemicolon)
+		{
+		    arg = new Argument(STCin, NULL, token.ident, NULL);
+		    nextToken();
+		    nextToken();
+		    if (1 || !global.params.useDeprecated)
+			error("if (v; e) is deprecated, use if (auto v = e)");
+		}
+	    }
+
+	    condition = parseExpression();
+	    check(TOKrparen);
+	    ifbody = parseStatement(PSscope);
+	    if (token.value == TOKelse)
+	    {
+		nextToken();
+		elsebody = parseStatement(PSscope);
+	    }
+	    else
+		elsebody = NULL;
+	    s = new IfStatement(loc, arg, condition, ifbody, elsebody);
+	    break;
+	}
+
+	case TOKscope:
+	    if (peek(&token)->value != TOKlparen)
+		goto Ldeclaration;		// scope used as storage class
+	    nextToken();
+	    check(TOKlparen);
+	    if (token.value != TOKidentifier)
+	    {	error("scope identifier expected");
+		goto Lerror;
+	    }
+	    else
+	    {	TOK t = TOKon_scope_exit;
+		Identifier *id = token.ident;
+
+		if (id == Id::exit)
+		    t = TOKon_scope_exit;
+		else if (id == Id::failure)
+		    t = TOKon_scope_failure;
+		else if (id == Id::success)
+		    t = TOKon_scope_success;
+		else
+		    error("valid scope identifiers are exit, failure, or success, not %s", id->toChars());
+		nextToken();
+		check(TOKrparen);
+		Statement *st = parseStatement(PScurlyscope);
+		s = new OnScopeStatement(loc, t, st);
+		break;
+	    }
+
+	case TOKdebug:
+	    nextToken();
+	    condition = parseDebugCondition();
+	    goto Lcondition;
+
+	case TOKversion:
+	    nextToken();
+	    condition = parseVersionCondition();
+	    goto Lcondition;
+
+	Lcondition:
+	    ifbody = parseStatement(0 /*PSsemi*/);
+	    elsebody = NULL;
+	    if (token.value == TOKelse)
+	    {
+		nextToken();
+		elsebody = parseStatement(0 /*PSsemi*/);
+	    }
+	    s = new ConditionalStatement(loc, condition, ifbody, elsebody);
+	    break;
+
+	case TOKpragma:
+	{   Identifier *ident;
+	    Expressions *args = NULL;
+	    Statement *body;
+
+	    nextToken();
+	    check(TOKlparen);
+	    if (token.value != TOKidentifier)
+	    {   error("pragma(identifier expected");
+		goto Lerror;
+	    }
+	    ident = token.ident;
+	    nextToken();
+	    if (token.value == TOKcomma)
+		args = parseArguments();	// pragma(identifier, args...);
+	    else
+		check(TOKrparen);		// pragma(identifier);
+	    if (token.value == TOKsemicolon)
+	    {	nextToken();
+		body = NULL;
+	    }
+	    else
+		body = parseStatement(PSsemi);
+	    s = new PragmaStatement(loc, ident, args, body);
+	    break;
+	}
+
+	case TOKswitch:
+	{   Expression *condition;
+	    Statement *body;
+
+	    nextToken();
+	    check(TOKlparen);
+	    condition = parseExpression();
+	    check(TOKrparen);
+	    body = parseStatement(PSscope);
+	    s = new SwitchStatement(loc, condition, body);
+	    break;
+	}
+
+	case TOKcase:
+	{   Expression *exp;
+	    Statements *statements;
+	    Array cases;	// array of Expression's
+
+	    while (1)
+	    {
+		nextToken();
+		exp = parseAssignExp();
+		cases.push(exp);
+		if (token.value != TOKcomma)
+		    break;
+	    }
+	    check(TOKcolon);
+
+	    statements = new Statements();
+	    while (token.value != TOKcase &&
+		   token.value != TOKdefault &&
+		   token.value != TOKrcurly)
+	    {
+		statements->push(parseStatement(PSsemi | PScurlyscope));
+	    }
+	    s = new CompoundStatement(loc, statements);
+	    s = new ScopeStatement(loc, s);
+
+	    // Keep cases in order by building the case statements backwards
+	    for (int i = cases.dim; i; i--)
+	    {
+		exp = (Expression *)cases.data[i - 1];
+		s = new CaseStatement(loc, exp, s);
+	    }
+	    break;
+	}
+
+	case TOKdefault:
+	{
+	    Statements *statements;
+
+	    nextToken();
+	    check(TOKcolon);
+
+	    statements = new Statements();
+	    while (token.value != TOKcase &&
+		   token.value != TOKdefault &&
+		   token.value != TOKrcurly)
+	    {
+		statements->push(parseStatement(PSsemi | PScurlyscope));
+	    }
+	    s = new CompoundStatement(loc, statements);
+	    s = new ScopeStatement(loc, s);
+	    s = new DefaultStatement(loc, s);
+	    break;
+	}
+
+	case TOKreturn:
+	{   Expression *exp;
+
+	    nextToken();
+	    if (token.value == TOKsemicolon)
+		exp = NULL;
+	    else
+		exp = parseExpression();
+	    check(TOKsemicolon, "return statement");
+	    s = new ReturnStatement(loc, exp);
+	    break;
+	}
+
+	case TOKbreak:
+	{   Identifier *ident;
+
+	    nextToken();
+	    if (token.value == TOKidentifier)
+	    {	ident = token.ident;
+		nextToken();
+	    }
+	    else
+		ident = NULL;
+	    check(TOKsemicolon, "break statement");
+	    s = new BreakStatement(loc, ident);
+	    break;
+	}
+
+	case TOKcontinue:
+	{   Identifier *ident;
+
+	    nextToken();
+	    if (token.value == TOKidentifier)
+	    {	ident = token.ident;
+		nextToken();
+	    }
+	    else
+		ident = NULL;
+	    check(TOKsemicolon, "continue statement");
+	    s = new ContinueStatement(loc, ident);
+	    break;
+	}
+
+	case TOKgoto:
+	{   Identifier *ident;
+
+	    nextToken();
+	    if (token.value == TOKdefault)
+	    {
+		nextToken();
+		s = new GotoDefaultStatement(loc);
+	    }
+	    else if (token.value == TOKcase)
+	    {
+		Expression *exp = NULL;
+
+		nextToken();
+		if (token.value != TOKsemicolon)
+		    exp = parseExpression();
+		s = new GotoCaseStatement(loc, exp);
+	    }
+	    else
+	    {
+		if (token.value != TOKidentifier)
+		{   error("Identifier expected following goto");
+		    ident = NULL;
+		}
+		else
+		{   ident = token.ident;
+		    nextToken();
+		}
+		s = new GotoStatement(loc, ident);
+	    }
+	    check(TOKsemicolon, "goto statement");
+	    break;
+	}
+
+	case TOKsynchronized:
+	{   Expression *exp;
+	    Statement *body;
+
+	    nextToken();
+	    if (token.value == TOKlparen)
+	    {
+		nextToken();
+		exp = parseExpression();
+		check(TOKrparen);
+	    }
+	    else
+		exp = NULL;
+	    body = parseStatement(PSscope);
+	    s = new SynchronizedStatement(loc, exp, body);
+	    break;
+	}
+
+	case TOKwith:
+	{   Expression *exp;
+	    Statement *body;
+
+	    nextToken();
+	    check(TOKlparen);
+	    exp = parseExpression();
+	    check(TOKrparen);
+	    body = parseStatement(PSscope);
+	    s = new WithStatement(loc, exp, body);
+	    break;
+	}
+
+	case TOKtry:
+	{   Statement *body;
+	    Array *catches = NULL;
+	    Statement *finalbody = NULL;
+
+	    nextToken();
+	    body = parseStatement(PSscope);
+	    while (token.value == TOKcatch)
+	    {
+		Statement *handler;
+		Catch *c;
+		Type *t;
+		Identifier *id;
+		Loc loc = this->loc;
+
+		nextToken();
+		if (token.value == TOKlcurly)
+		{
+		    t = NULL;
+		    id = NULL;
+		}
+		else
+		{
+		    check(TOKlparen);
+		    t = parseBasicType();
+		    id = NULL;
+		    t = parseDeclarator(t, &id);
+		    check(TOKrparen);
+		}
+		handler = parseStatement(0);
+		c = new Catch(loc, t, id, handler);
+		if (!catches)
+		    catches = new Array();
+		catches->push(c);
+	    }
+
+	    if (token.value == TOKfinally)
+	    {	nextToken();
+		finalbody = parseStatement(0);
+	    }
+
+	    s = body;
+	    if (!catches && !finalbody)
+		error("catch or finally expected following try");
+	    else
+	    {	if (catches)
+		    s = new TryCatchStatement(loc, body, catches);
+		if (finalbody)
+		    s = new TryFinallyStatement(loc, s, finalbody);
+	    }
+	    break;
+	}
+
+	case TOKthrow:
+	{   Expression *exp;
+
+	    nextToken();
+	    exp = parseExpression();
+	    check(TOKsemicolon, "throw statement");
+	    s = new ThrowStatement(loc, exp);
+	    break;
+	}
+
+	case TOKvolatile:
+	    nextToken();
+	    s = parseStatement(PSsemi | PScurlyscope);
+	    s = new VolatileStatement(loc, s);
+	    break;
+
+	case TOKasm:
+	{   Statements *statements;
+	    Identifier *label;
+	    Loc labelloc;
+	    Token *toklist;
+	    Token **ptoklist;
+
+	    // Parse the asm block into a sequence of AsmStatements,
+	    // each AsmStatement is one instruction.
+	    // Separate out labels.
+	    // Defer parsing of AsmStatements until semantic processing.
+
+	    nextToken();
+	    check(TOKlcurly);
+	    toklist = NULL;
+	    ptoklist = &toklist;
+	    label = NULL;
+	    statements = new Statements();
+	    while (1)
+	    {
+		switch (token.value)
+		{
+		    case TOKidentifier:
+			if (!toklist)
+			{
+			    // Look ahead to see if it is a label
+			    t = peek(&token);
+			    if (t->value == TOKcolon)
+			    {   // It's a label
+				label = token.ident;
+				labelloc = this->loc;
+				nextToken();
+				nextToken();
+				continue;
+			    }
+			}
+			goto Ldefault;
+
+		    case TOKrcurly:
+			if (toklist || label)
+			{
+			    error("asm statements must end in ';'");
+			}
+			break;
+
+		    case TOKsemicolon:
+			s = NULL;
+			if (toklist || label)
+			{   // Create AsmStatement from list of tokens we've saved
+			    s = new AsmStatement(this->loc, toklist);
+			    toklist = NULL;
+			    ptoklist = &toklist;
+			    if (label)
+			    {   s = new LabelStatement(labelloc, label, s);
+				label = NULL;
+			    }
+			    statements->push(s);
+			}
+			nextToken();
+			continue;
+
+		    case TOKeof:
+			/* { */
+			error("matching '}' expected, not end of file");
+			break;
+
+		    default:
+		    Ldefault:
+			*ptoklist = new Token();
+			memcpy(*ptoklist, &token, sizeof(Token));
+			ptoklist = &(*ptoklist)->next;
+			*ptoklist = NULL;
+
+			nextToken();
+			continue;
+		}
+		break;
+	    }
+	    s = new CompoundStatement(loc, statements);
+	    nextToken();
+	    break;
+	}
+
+	default:
+	    error("found '%s' instead of statement", token.toChars());
+	    goto Lerror;
+
+	Lerror:
+	    while (token.value != TOKrcurly &&
+		   token.value != TOKsemicolon &&
+		   token.value != TOKeof)
+		nextToken();
+	    if (token.value == TOKsemicolon)
+		nextToken();
+	    s = NULL;
+	    break;
+    }
+
+    return s;
+}
+
+void Parser::check(enum TOK value)
+{
+    check(loc, value);
+}
+
+void Parser::check(Loc loc, enum TOK value)
+{
+    if (token.value != value)
+	error(loc, "found '%s' when expecting '%s'", token.toChars(), Token::toChars(value));
+    nextToken();
+}
+
+void Parser::check(enum TOK value, char *string)
+{
+    if (token.value != value)
+	error("found '%s' when expecting '%s' following '%s'",
+	    token.toChars(), Token::toChars(value), string);
+    nextToken();
+}
+
+/************************************
+ * Determine if the scanner is sitting on the start of a declaration.
+ * Input:
+ *	needId	0	no identifier
+ *		1	identifier optional
+ *		2	must have identifier
+ */
+
+int Parser::isDeclaration(Token *t, int needId, enum TOK endtok, Token **pt)
+{
+    int haveId = 0;
+
+    if (!isBasicType(&t))
+	return FALSE;
+    if (!isDeclarator(&t, &haveId, endtok))
+	return FALSE;
+    if ( needId == 1 ||
+	(needId == 0 && !haveId) ||
+	(needId == 2 &&  haveId))
+    {	if (pt)
+	    *pt = t;
+	return TRUE;
+    }
+    else
+	return FALSE;
+}
+
+int Parser::isBasicType(Token **pt)
+{
+    // This code parallels parseBasicType()
+    Token *t = *pt;
+    Token *t2;
+    int parens;
+
+    switch (t->value)
+    {
+	CASE_BASIC_TYPES:
+	    t = peek(t);
+	    break;
+
+	case TOKidentifier:
+	    t = peek(t);
+	    if (t->value == TOKnot)
+	    {
+		goto L4;
+	    }
+	    goto L3;
+	    while (1)
+	    {
+	L2:
+		t = peek(t);
+	L3:
+		if (t->value == TOKdot)
+		{
+	Ldot:
+		    t = peek(t);
+		    if (t->value != TOKidentifier)
+			goto Lfalse;
+		    t = peek(t);
+		    if (t->value != TOKnot)
+			goto L3;
+	L4:
+		    t = peek(t);
+		    if (t->value != TOKlparen)
+			goto Lfalse;
+		    if (!skipParens(t, &t))
+			goto Lfalse;
+		}
+		else
+		    break;
+	    }
+	    break;
+
+	case TOKdot:
+	    goto Ldot;
+
+	case TOKtypeof:
+	    /* typeof(exp).identifier...
+	     */
+	    t = peek(t);
+	    if (t->value != TOKlparen)
+		goto Lfalse;
+	    if (!skipParens(t, &t))
+		goto Lfalse;
+	    goto L2;
+
+	default:
+	    goto Lfalse;
+    }
+    *pt = t;
+    return TRUE;
+
+Lfalse:
+    return FALSE;
+}
+
+int Parser::isDeclarator(Token **pt, int *haveId, enum TOK endtok)
+{   // This code parallels parseDeclarator()
+    Token *t = *pt;
+    int parens;
+
+    //printf("Parser::isDeclarator()\n");
+    //t->print();
+    if (t->value == TOKassign)
+	return FALSE;
+
+    while (1)
+    {
+	parens = FALSE;
+	switch (t->value)
+	{
+	    case TOKmul:
+	    case TOKand:
+		t = peek(t);
+		continue;
+
+	    case TOKlbracket:
+		t = peek(t);
+		if (t->value == TOKrbracket)
+		{
+		    t = peek(t);
+		}
+		else if (isDeclaration(t, 0, TOKrbracket, &t))
+		{   // It's an associative array declaration
+		    t = peek(t);
+		}
+		else
+		{
+		    // [ expression ]
+		    // [ expression .. expression ]
+		    if (!isExpression(&t))
+			return FALSE;
+		    if (t->value == TOKslice)
+		    {	t = peek(t);
+			if (!isExpression(&t))
+			    return FALSE;
+		    }
+		    if (t->value != TOKrbracket)
+			return FALSE;
+		    t = peek(t);
+		}
+		continue;
+
+	    case TOKidentifier:
+		if (*haveId)
+		    return FALSE;
+		*haveId = TRUE;
+		t = peek(t);
+		break;
+
+	    case TOKlparen:
+		t = peek(t);
+
+		if (t->value == TOKrparen)
+		    return FALSE;		// () is not a declarator
+
+		/* Regard ( identifier ) as not a declarator
+		 * BUG: what about ( *identifier ) in
+		 *	f(*p)(x);
+		 * where f is a class instance with overloaded () ?
+		 * Should we just disallow C-style function pointer declarations?
+		 */
+		if (t->value == TOKidentifier)
+		{   Token *t2 = peek(t);
+		    if (t2->value == TOKrparen)
+			return FALSE;
+		}
+
+
+		if (!isDeclarator(&t, haveId, TOKrparen))
+		    return FALSE;
+		t = peek(t);
+		parens = TRUE;
+		break;
+
+	    case TOKdelegate:
+	    case TOKfunction:
+		t = peek(t);
+		if (!isParameters(&t))
+		    return FALSE;
+		continue;
+	}
+	break;
+    }
+
+    while (1)
+    {
+	switch (t->value)
+	{
+#if CARRAYDECL
+	    case TOKlbracket:
+		parens = FALSE;
+		t = peek(t);
+		if (t->value == TOKrbracket)
+		{
+		    t = peek(t);
+		}
+		else if (isDeclaration(t, 0, TOKrbracket, &t))
+		{   // It's an associative array declaration
+		    t = peek(t);
+		}
+		else
+		{
+		    // [ expression ]
+		    if (!isExpression(&t))
+			return FALSE;
+		    if (t->value != TOKrbracket)
+			return FALSE;
+		    t = peek(t);
+		}
+		continue;
+#endif
+
+	    case TOKlparen:
+		parens = FALSE;
+		if (!isParameters(&t))
+		    return FALSE;
+		continue;
+
+	    // Valid tokens that follow a declaration
+	    case TOKrparen:
+	    case TOKrbracket:
+	    case TOKassign:
+	    case TOKcomma:
+	    case TOKsemicolon:
+	    case TOKlcurly:
+	    case TOKin:
+		// The !parens is to disallow unnecessary parentheses
+		if (!parens && (endtok == TOKreserved || endtok == t->value))
+		{   *pt = t;
+		    return TRUE;
+		}
+		return FALSE;
+
+	    default:
+		return FALSE;
+	}
+    }
+}
+
+
+int Parser::isParameters(Token **pt)
+{   // This code parallels parseParameters()
+    Token *t = *pt;
+    int tmp;
+
+    //printf("isParameters()\n");
+    if (t->value != TOKlparen)
+	return FALSE;
+
+    t = peek(t);
+    while (1)
+    {
+	switch (t->value)
+	{
+	    case TOKrparen:
+		break;
+
+	    case TOKdotdotdot:
+		t = peek(t);
+		break;
+
+	    case TOKin:
+	    case TOKout:
+	    case TOKinout:
+	    case TOKref:
+	    case TOKlazy:
+		t = peek(t);
+	    default:
+		if (!isBasicType(&t))
+		    return FALSE;
+		tmp = FALSE;
+		if (t->value != TOKdotdotdot &&
+		    !isDeclarator(&t, &tmp, TOKreserved))
+		    return FALSE;
+		if (t->value == TOKassign)
+		{   t = peek(t);
+		    if (!isExpression(&t))
+			return FALSE;
+		}
+		if (t->value == TOKdotdotdot)
+		{
+		    t = peek(t);
+		    break;
+		}
+		if (t->value == TOKcomma)
+		{   t = peek(t);
+		    continue;
+		}
+		break;
+	}
+	break;
+    }
+    if (t->value != TOKrparen)
+	return FALSE;
+    t = peek(t);
+    *pt = t;
+    return TRUE;
+}
+
+int Parser::isExpression(Token **pt)
+{
+    // This is supposed to determine if something is an expression.
+    // What it actually does is scan until a closing right bracket
+    // is found.
+
+    Token *t = *pt;
+    int brnest = 0;
+    int panest = 0;
+
+    for (;; t = peek(t))
+    {
+	switch (t->value)
+	{
+	    case TOKlbracket:
+		brnest++;
+		continue;
+
+	    case TOKrbracket:
+		if (--brnest >= 0)
+		    continue;
+		break;
+
+	    case TOKlparen:
+		panest++;
+		continue;
+
+	    case TOKcomma:
+		if (brnest || panest)
+		    continue;
+		break;
+
+	    case TOKrparen:
+		if (--panest >= 0)
+		    continue;
+		break;
+
+	    case TOKslice:
+		if (brnest)
+		    continue;
+		break;
+
+	    case TOKeof:
+		return FALSE;
+
+	    default:
+		continue;
+	}
+	break;
+    }
+
+    *pt = t;
+    return TRUE;
+}
+
+/**********************************************
+ * Skip over
+ *	instance foo.bar(parameters...)
+ * Output:
+ *	if (pt), *pt is set to the token following the closing )
+ * Returns:
+ *	1	it's valid instance syntax
+ *	0	invalid instance syntax
+ */
+
+int Parser::isTemplateInstance(Token *t, Token **pt)
+{
+    t = peek(t);
+    if (t->value != TOKdot)
+    {
+	if (t->value != TOKidentifier)
+	    goto Lfalse;
+	t = peek(t);
+    }
+    while (t->value == TOKdot)
+    {
+	t = peek(t);
+	if (t->value != TOKidentifier)
+	    goto Lfalse;
+	t = peek(t);
+    }
+    if (t->value != TOKlparen)
+	goto Lfalse;
+
+    // Skip over the template arguments
+    while (1)
+    {
+	while (1)
+	{
+	    t = peek(t);
+	    switch (t->value)
+	    {
+		case TOKlparen:
+		    if (!skipParens(t, &t))
+			goto Lfalse;
+		    continue;
+		case TOKrparen:
+		    break;
+		case TOKcomma:
+		    break;
+		case TOKeof:
+		case TOKsemicolon:
+		    goto Lfalse;
+		default:
+		    continue;
+	    }
+	    break;
+	}
+
+	if (t->value != TOKcomma)
+	    break;
+    }
+    if (t->value != TOKrparen)
+	goto Lfalse;
+    t = peek(t);
+    if (pt)
+	*pt = t;
+    return 1;
+
+Lfalse:
+    return 0;
+}
+
+/*******************************************
+ * Skip parens, brackets.
+ * Input:
+ *	t is on opening (
+ * Output:
+ *	*pt is set to closing token, which is ')' on success
+ * Returns:
+ *	!=0	successful
+ *	0	some parsing error
+ */
+
+int Parser::skipParens(Token *t, Token **pt)
+{
+    int parens = 0;
+
+    while (1)
+    {
+	switch (t->value)
+	{
+	    case TOKlparen:
+		parens++;
+		break;
+
+	    case TOKrparen:
+		parens--;
+		if (parens < 0)
+		    goto Lfalse;
+		if (parens == 0)
+		    goto Ldone;
+		break;
+
+	    case TOKeof:
+	    case TOKsemicolon:
+		goto Lfalse;
+
+	     default:
+		break;
+	}
+	t = peek(t);
+    }
+
+  Ldone:
+    if (*pt)
+	*pt = t;
+    return 1;
+
+  Lfalse:
+    return 0;
+}
+
+/********************************* Expression Parser ***************************/
+
+Expression *Parser::parsePrimaryExp()
+{   Expression *e;
+    Type *t;
+    Identifier *id;
+    enum TOK save;
+    Loc loc = this->loc;
+
+    switch (token.value)
+    {
+	case TOKidentifier:
+	    id = token.ident;
+	    nextToken();
+	    if (token.value == TOKnot && peek(&token)->value == TOKlparen)
+	    {	// identifier!(template-argument-list)
+		TemplateInstance *tempinst;
+
+		tempinst = new TemplateInstance(loc, id);
+		nextToken();
+		tempinst->tiargs = parseTemplateArgumentList();
+		e = new ScopeExp(loc, tempinst);
+	    }
+	    else
+		e = new IdentifierExp(loc, id);
+	    break;
+
+	case TOKdollar:
+	    if (!inBrackets)
+		error("'$' is valid only inside [] of index or slice");
+	    e = new DollarExp(loc);
+	    nextToken();
+	    break;
+
+	case TOKdot:
+	    // Signal global scope '.' operator with "" identifier
+	    e = new IdentifierExp(loc, Id::empty);
+	    break;
+
+	case TOKthis:
+	    e = new ThisExp(loc);
+	    nextToken();
+	    break;
+
+	case TOKsuper:
+	    e = new SuperExp(loc);
+	    nextToken();
+	    break;
+
+	case TOKint32v:
+	    e = new IntegerExp(loc, token.int32value, Type::tint32);
+	    nextToken();
+	    break;
+
+	case TOKuns32v:
+	    e = new IntegerExp(loc, token.uns32value, Type::tuns32);
+	    nextToken();
+	    break;
+
+	case TOKint64v:
+	    e = new IntegerExp(loc, token.int64value, Type::tint64);
+	    nextToken();
+	    break;
+
+	case TOKuns64v:
+	    e = new IntegerExp(loc, token.uns64value, Type::tuns64);
+	    nextToken();
+	    break;
+
+	case TOKfloat32v:
+	    e = new RealExp(loc, token.float80value, Type::tfloat32);
+	    nextToken();
+	    break;
+
+	case TOKfloat64v:
+	    e = new RealExp(loc, token.float80value, Type::tfloat64);
+	    nextToken();
+	    break;
+
+	case TOKfloat80v:
+	    e = new RealExp(loc, token.float80value, Type::tfloat80);
+	    nextToken();
+	    break;
+
+	case TOKimaginary32v:
+	    e = new RealExp(loc, token.float80value, Type::timaginary32);
+	    nextToken();
+	    break;
+
+	case TOKimaginary64v:
+	    e = new RealExp(loc, token.float80value, Type::timaginary64);
+	    nextToken();
+	    break;
+
+	case TOKimaginary80v:
+	    e = new RealExp(loc, token.float80value, Type::timaginary80);
+	    nextToken();
+	    break;
+
+	case TOKnull:
+	    e = new NullExp(loc);
+	    nextToken();
+	    break;
+
+	case TOKtrue:
+	    e = new IntegerExp(loc, 1, Type::tbool);
+	    nextToken();
+	    break;
+
+	case TOKfalse:
+	    e = new IntegerExp(loc, 0, Type::tbool);
+	    nextToken();
+	    break;
+
+	case TOKcharv:
+	    e = new IntegerExp(loc, token.uns32value, Type::tchar);
+	    nextToken();
+	    break;
+
+	case TOKwcharv:
+	    e = new IntegerExp(loc, token.uns32value, Type::twchar);
+	    nextToken();
+	    break;
+
+	case TOKdcharv:
+	    e = new IntegerExp(loc, token.uns32value, Type::tdchar);
+	    nextToken();
+	    break;
+
+	case TOKstring:
+	{   unsigned char *s;
+	    unsigned len;
+	    unsigned char postfix;
+
+	    // cat adjacent strings
+	    s = token.ustring;
+	    len = token.len;
+	    postfix = token.postfix;
+	    while (1)
+	    {
+		nextToken();
+		if (token.value == TOKstring)
+		{   unsigned len1;
+		    unsigned len2;
+		    unsigned char *s2;
+
+		    if (token.postfix)
+		    {	if (token.postfix != postfix)
+			    error("mismatched string literal postfixes '%c' and '%c'", postfix, token.postfix);
+			postfix = token.postfix;
+		    }
+
+		    len1 = len;
+		    len2 = token.len;
+		    len = len1 + len2;
+		    s2 = (unsigned char *)mem.malloc((len + 1) * sizeof(unsigned char));
+		    memcpy(s2, s, len1 * sizeof(unsigned char));
+		    memcpy(s2 + len1, token.ustring, (len2 + 1) * sizeof(unsigned char));
+		    s = s2;
+		}
+		else
+		    break;
+	    }
+	    e = new StringExp(loc, s, len, postfix);
+	    break;
+	}
+
+	CASE_BASIC_TYPES_X(t):
+	    nextToken();
+	L1:
+	    check(TOKdot, t->toChars());
+	    if (token.value != TOKidentifier)
+	    {   error("found '%s' when expecting identifier following '%s.'", token.toChars(), t->toChars());
+		goto Lerr;
+	    }
+	    e = new TypeDotIdExp(loc, t, token.ident);
+	    nextToken();
+	    break;
+
+	case TOKtypeof:
+	{   Expression *exp;
+
+	    nextToken();
+	    check(TOKlparen);
+	    exp = parseExpression();
+	    check(TOKrparen);
+	    t = new TypeTypeof(loc, exp);
+	    if (token.value == TOKdot)
+		goto L1;
+	    e = new TypeExp(loc, t);
+	    break;
+	}
+
+	case TOKtypeid:
+	{   Type *t;
+
+	    nextToken();
+	    check(TOKlparen, "typeid");
+	    t = parseBasicType();
+	    t = parseDeclarator(t,NULL);	// ( type )
+	    check(TOKrparen);
+	    e = new TypeidExp(loc, t);
+	    break;
+	}
+
+	case TOKis:
+	{   Type *targ;
+	    Identifier *ident = NULL;
+	    Type *tspec = NULL;
+	    enum TOK tok = TOKreserved;
+	    enum TOK tok2 = TOKreserved;
+	    Loc loc = this->loc;
+
+	    nextToken();
+	    if (token.value == TOKlparen)
+	    {
+		nextToken();
+		targ = parseBasicType();
+		targ = parseDeclarator(targ, &ident);
+		if (token.value == TOKcolon || token.value == TOKequal)
+		{
+		    tok = token.value;
+		    nextToken();
+		    if (tok == TOKequal &&
+			(token.value == TOKtypedef ||
+			 token.value == TOKstruct ||
+			 token.value == TOKunion ||
+			 token.value == TOKclass ||
+			 token.value == TOKsuper ||
+			 token.value == TOKenum ||
+			 token.value == TOKinterface ||
+			 token.value == TOKfunction ||
+			 token.value == TOKdelegate ||
+			 token.value == TOKreturn))
+		    {
+			tok2 = token.value;
+			nextToken();
+		    }
+		    else
+		    {
+			tspec = parseBasicType();
+			tspec = parseDeclarator(tspec, NULL);
+		    }
+		}
+		check(TOKrparen);
+	    }
+	    else
+	    {   error("(type identifier : specialization) expected following is");
+		goto Lerr;
+	    }
+	    e = new IftypeExp(loc, targ, ident, tok, tspec, tok2);
+	    break;
+	}
+
+	case TOKassert:
+	{   Expression *msg = NULL;
+
+	    nextToken();
+	    check(TOKlparen, "assert");
+	    e = parseAssignExp();
+	    if (token.value == TOKcomma)
+	    {	nextToken();
+		msg = parseAssignExp();
+	    }
+	    check(TOKrparen);
+	    e = new AssertExp(loc, e, msg);
+	    break;
+	}
+
+	case TOKmixin:
+	{
+	    nextToken();
+	    check(TOKlparen, "mixin");
+	    e = parseAssignExp();
+	    check(TOKrparen);
+	    e = new CompileExp(loc, e);
+	    break;
+	}
+
+	case TOKimport:
+	{
+	    nextToken();
+	    check(TOKlparen, "import");
+	    e = parseAssignExp();
+	    check(TOKrparen);
+	    e = new FileExp(loc, e);
+	    break;
+	}
+
+	case TOKlparen:
+	    if (peekPastParen(&token)->value == TOKlcurly)
+	    {	// (arguments) { statements... }
+		save = TOKdelegate;
+		goto case_delegate;
+	    }
+	    // ( expression )
+	    nextToken();
+	    e = parseExpression();
+	    check(loc, TOKrparen);
+	    break;
+
+	case TOKlbracket:
+	{   /* Parse array literals and associative array literals:
+	     *	[ value, value, value ... ]
+	     *	[ key:value, key:value, key:value ... ]
+	     */
+	    Expressions *values = new Expressions();
+	    Expressions *keys = NULL;
+
+	    nextToken();
+	    if (token.value != TOKrbracket)
+	    {
+		while (1)
+		{
+		    Expression *e = parseAssignExp();
+		    if (token.value == TOKcolon && (keys || values->dim == 0))
+		    {	nextToken();
+			if (!keys)
+			    keys = new Expressions();
+			keys->push(e);
+			e = parseAssignExp();
+		    }
+		    else if (keys)
+		    {	error("'key:value' expected for associative array literal");
+			delete keys;
+			keys = NULL;
+		    }
+		    values->push(e);
+		    if (token.value == TOKrbracket)
+			break;
+		    check(TOKcomma);
+		}
+	    }
+	    check(TOKrbracket);
+
+	    if (keys)
+		e = new AssocArrayLiteralExp(loc, keys, values);
+	    else
+		e = new ArrayLiteralExp(loc, values);
+	    break;
+	}
+
+	case TOKlcurly:
+	    // { statements... }
+	    save = TOKdelegate;
+	    goto case_delegate;
+
+	case TOKfunction:
+	case TOKdelegate:
+	    save = token.value;
+	    nextToken();
+	case_delegate:
+	{
+	    /* function type(parameters) { body }
+	     * delegate type(parameters) { body }
+	     */
+	    Arguments *arguments;
+	    int varargs;
+	    FuncLiteralDeclaration *fd;
+	    Type *t;
+
+	    if (token.value == TOKlcurly)
+	    {
+		t = NULL;
+		varargs = 0;
+		arguments = new Arguments();
+	    }
+	    else
+	    {
+		if (token.value == TOKlparen)
+		    t = NULL;
+		else
+		{
+		    t = parseBasicType();
+		    t = parseBasicType2(t);	// function return type
+		}
+		arguments = parseParameters(&varargs);
+	    }
+	    t = new TypeFunction(arguments, t, varargs, linkage);
+	    fd = new FuncLiteralDeclaration(loc, 0, t, save, NULL);
+	    parseContracts(fd);
+	    e = new FuncExp(loc, fd);
+	    break;
+	}
+
+	default:
+	    error("expression expected, not '%s'", token.toChars());
+	Lerr:
+	    // Anything for e, as long as it's not NULL
+	    e = new IntegerExp(loc, 0, Type::tint32);
+	    nextToken();
+	    break;
+    }
+    return parsePostExp(e);
+}
+
+Expression *Parser::parsePostExp(Expression *e)
+{
+    Loc loc;
+
+    while (1)
+    {
+	loc = this->loc;
+	switch (token.value)
+	{
+	    case TOKdot:
+		nextToken();
+		if (token.value == TOKidentifier)
+		{   Identifier *id = token.ident;
+
+		    nextToken();
+		    if (token.value == TOKnot && peek(&token)->value == TOKlparen)
+		    {   // identifier!(template-argument-list)
+			TemplateInstance *tempinst;
+
+			tempinst = new TemplateInstance(loc, id);
+			nextToken();
+			tempinst->tiargs = parseTemplateArgumentList();
+			e = new DotTemplateInstanceExp(loc, e, tempinst);
+		    }
+		    else
+			e = new DotIdExp(loc, e, id);
+		    continue;
+		}
+		else if (token.value == TOKnew)
+		{
+		    e = parseNewExp(e);
+		    continue;
+		}
+		else
+		    error("identifier expected following '.', not '%s'", token.toChars());
+		break;
+
+	    case TOKplusplus:
+		e = new PostExp(TOKplusplus, loc, e);
+		break;
+
+	    case TOKminusminus:
+		e = new PostExp(TOKminusminus, loc, e);
+		break;
+
+	    case TOKlparen:
+		e = new CallExp(loc, e, parseArguments());
+		continue;
+
+	    case TOKlbracket:
+	    {	// array dereferences:
+		//	array[index]
+		//	array[]
+		//	array[lwr .. upr]
+		Expression *index;
+		Expression *upr;
+
+		inBrackets++;
+		nextToken();
+		if (token.value == TOKrbracket)
+		{   // array[]
+		    e = new SliceExp(loc, e, NULL, NULL);
+		    nextToken();
+		}
+		else
+		{
+		    index = parseAssignExp();
+		    if (token.value == TOKslice)
+		    {	// array[lwr .. upr]
+			nextToken();
+			upr = parseAssignExp();
+			e = new SliceExp(loc, e, index, upr);
+		    }
+		    else
+		    {	// array[index, i2, i3, i4, ...]
+			Expressions *arguments = new Expressions();
+			arguments->push(index);
+			if (token.value == TOKcomma)
+			{
+			    nextToken();
+			    while (1)
+			    {   Expression *arg;
+
+				arg = parseAssignExp();
+				arguments->push(arg);
+				if (token.value == TOKrbracket)
+				    break;
+				check(TOKcomma);
+			    }
+			}
+			e = new ArrayExp(loc, e, arguments);
+		    }
+		    check(TOKrbracket);
+		    inBrackets--;
+		}
+		continue;
+	    }
+
+	    default:
+		return e;
+	}
+	nextToken();
+    }
+}
+
+Expression *Parser::parseUnaryExp()
+{   Expression *e;
+    Loc loc = this->loc;
+
+    switch (token.value)
+    {
+	case TOKand:
+	    nextToken();
+	    e = parseUnaryExp();
+	    e = new AddrExp(loc, e);
+	    break;
+
+	case TOKplusplus:
+	    nextToken();
+	    e = parseUnaryExp();
+	    e = new AddAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
+	    break;
+
+	case TOKminusminus:
+	    nextToken();
+	    e = parseUnaryExp();
+	    e = new MinAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
+	    break;
+
+	case TOKmul:
+	    nextToken();
+	    e = parseUnaryExp();
+	    e = new PtrExp(loc, e);
+	    break;
+
+	case TOKmin:
+	    nextToken();
+	    e = parseUnaryExp();
+	    e = new NegExp(loc, e);
+	    break;
+
+	case TOKadd:
+	    nextToken();
+	    e = parseUnaryExp();
+	    e = new UAddExp(loc, e);
+	    break;
+
+	case TOKnot:
+	    nextToken();
+	    e = parseUnaryExp();
+	    e = new NotExp(loc, e);
+	    break;
+
+	case TOKtilde:
+	    nextToken();
+	    e = parseUnaryExp();
+	    e = new ComExp(loc, e);
+	    break;
+
+	case TOKdelete:
+	    nextToken();
+	    e = parseUnaryExp();
+	    e = new DeleteExp(loc, e);
+	    break;
+
+	case TOKnew:
+	    e = parseNewExp(NULL);
+	    break;
+
+	case TOKcast:				// cast(type) expression
+	{   Type *t;
+
+	    nextToken();
+	    check(TOKlparen);
+	    t = parseBasicType();
+	    t = parseDeclarator(t,NULL);	// ( type )
+	    check(TOKrparen);
+
+	    e = parseUnaryExp();
+	    e = new CastExp(loc, e, t);
+	    break;
+	}
+
+	case TOKlparen:
+	{   Token *tk;
+
+	    tk = peek(&token);
+#if CCASTSYNTAX
+	    // If cast
+	    if (isDeclaration(tk, 0, TOKrparen, &tk))
+	    {
+		tk = peek(tk);		// skip over right parenthesis
+		switch (tk->value)
+		{
+		    case TOKdot:
+		    case TOKplusplus:
+		    case TOKminusminus:
+		    case TOKnot:
+		    case TOKdelete:
+		    case TOKnew:
+		    case TOKlparen:
+		    case TOKidentifier:
+		    case TOKthis:
+		    case TOKsuper:
+		    case TOKint32v:
+		    case TOKuns32v:
+		    case TOKint64v:
+		    case TOKuns64v:
+		    case TOKfloat32v:
+		    case TOKfloat64v:
+		    case TOKfloat80v:
+		    case TOKimaginary32v:
+		    case TOKimaginary64v:
+		    case TOKimaginary80v:
+		    case TOKnull:
+		    case TOKtrue:
+		    case TOKfalse:
+		    case TOKcharv:
+		    case TOKwcharv:
+		    case TOKdcharv:
+		    case TOKstring:
+#if 0
+		    case TOKtilde:
+		    case TOKand:
+		    case TOKmul:
+		    case TOKmin:
+		    case TOKadd:
+#endif
+		    case TOKfunction:
+		    case TOKdelegate:
+		    case TOKtypeof:
+		    CASE_BASIC_TYPES:		// (type)int.size
+		    {	// (type) una_exp
+			Type *t;
+
+			nextToken();
+			t = parseBasicType();
+			t = parseDeclarator(t,NULL);
+			check(TOKrparen);
+
+			// if .identifier
+			if (token.value == TOKdot)
+			{
+			    nextToken();
+			    if (token.value != TOKidentifier)
+			    {   error("Identifier expected following (type).");
+				return NULL;
+			    }
+			    e = new TypeDotIdExp(loc, t, token.ident);
+			    nextToken();
+			    e = parsePostExp(e);
+			}
+			else
+			{
+			    e = parseUnaryExp();
+			    e = new CastExp(loc, e, t);
+			    error("C style cast illegal, use %s", e->toChars());
+			}
+			return e;
+		    }
+		}
+	    }
+#endif
+	    e = parsePrimaryExp();
+	    break;
+	}
+	default:
+	    e = parsePrimaryExp();
+	    break;
+    }
+    assert(e);
+    return e;
+}
+
+Expression *Parser::parseMulExp()
+{   Expression *e;
+    Expression *e2;
+    Loc loc = this->loc;
+
+    e = parseUnaryExp();
+    while (1)
+    {
+	switch (token.value)
+	{
+	    case TOKmul: nextToken(); e2 = parseUnaryExp(); e = new MulExp(loc,e,e2); continue;
+	    case TOKdiv:   nextToken(); e2 = parseUnaryExp(); e = new DivExp(loc,e,e2); continue;
+	    case TOKmod:  nextToken(); e2 = parseUnaryExp(); e = new ModExp(loc,e,e2); continue;
+
+	    default:
+		break;
+	}
+	break;
+    }
+    return e;
+}
+
+Expression *Parser::parseAddExp()
+{   Expression *e;
+    Expression *e2;
+    Loc loc = this->loc;
+
+    e = parseMulExp();
+    while (1)
+    {
+	switch (token.value)
+	{
+	    case TOKadd:    nextToken(); e2 = parseMulExp(); e = new AddExp(loc,e,e2); continue;
+	    case TOKmin:    nextToken(); e2 = parseMulExp(); e = new MinExp(loc,e,e2); continue;
+	    case TOKtilde:  nextToken(); e2 = parseMulExp(); e = new CatExp(loc,e,e2); continue;
+
+	    default:
+		break;
+	}
+	break;
+    }
+    return e;
+}
+
+Expression *Parser::parseShiftExp()
+{   Expression *e;
+    Expression *e2;
+    Loc loc = this->loc;
+
+    e = parseAddExp();
+    while (1)
+    {
+	switch (token.value)
+	{
+	    case TOKshl:  nextToken(); e2 = parseAddExp(); e = new ShlExp(loc,e,e2);  continue;
+	    case TOKshr:  nextToken(); e2 = parseAddExp(); e = new ShrExp(loc,e,e2);  continue;
+	    case TOKushr: nextToken(); e2 = parseAddExp(); e = new UshrExp(loc,e,e2); continue;
+
+	    default:
+		break;
+	}
+	break;
+    }
+    return e;
+}
+
+Expression *Parser::parseRelExp()
+{   Expression *e;
+    Expression *e2;
+    enum TOK op;
+    Loc loc = this->loc;
+
+    e = parseShiftExp();
+    while (1)
+    {
+	switch (token.value)
+	{
+	    case TOKlt:
+	    case TOKle:
+	    case TOKgt:
+	    case TOKge:
+	    case TOKunord:
+	    case TOKlg:
+	    case TOKleg:
+	    case TOKule:
+	    case TOKul:
+	    case TOKuge:
+	    case TOKug:
+	    case TOKue:
+		op = token.value;
+		nextToken();
+		e2 = parseShiftExp();
+		e = new CmpExp(op, loc, e, e2);
+		continue;
+
+	    case TOKin:
+		nextToken();
+		e2 = parseShiftExp();
+		e = new InExp(loc, e, e2);
+		continue;
+
+	    default:
+		break;
+	}
+	break;
+    }
+    return e;
+}
+
+Expression *Parser::parseEqualExp()
+{   Expression *e;
+    Expression *e2;
+    Token *t;
+    Loc loc = this->loc;
+
+    e = parseRelExp();
+    while (1)
+    {	enum TOK value = token.value;
+
+	switch (value)
+	{
+	    case TOKequal:
+	    case TOKnotequal:
+		nextToken();
+		e2 = parseRelExp();
+		e = new EqualExp(value, loc, e, e2);
+		continue;
+
+	    case TOKidentity:
+		error("'===' is no longer legal, use 'is' instead");
+		goto L1;
+
+	    case TOKnotidentity:
+		error("'!==' is no longer legal, use '!is' instead");
+		goto L1;
+
+	    case TOKis:
+		value = TOKidentity;
+		goto L1;
+
+	    case TOKnot:
+		// Attempt to identify '!is'
+		t = peek(&token);
+		if (t->value != TOKis)
+		    break;
+		nextToken();
+		value = TOKnotidentity;
+		goto L1;
+
+	    L1:
+		nextToken();
+		e2 = parseRelExp();
+		e = new IdentityExp(value, loc, e, e2);
+		continue;
+
+	    default:
+		break;
+	}
+	break;
+    }
+    return e;
+}
+
+Expression *Parser::parseCmpExp()
+{   Expression *e;
+    Expression *e2;
+    Token *t;
+    Loc loc = this->loc;
+
+    e = parseShiftExp();
+    enum TOK op = token.value;
+
+    switch (op)
+    {
+	case TOKequal:
+	case TOKnotequal:
+	    nextToken();
+	    e2 = parseShiftExp();
+	    e = new EqualExp(op, loc, e, e2);
+	    break;
+
+	case TOKis:
+	    op = TOKidentity;
+	    goto L1;
+
+	case TOKnot:
+	    // Attempt to identify '!is'
+	    t = peek(&token);
+	    if (t->value != TOKis)
+		break;
+	    nextToken();
+	    op = TOKnotidentity;
+	    goto L1;
+
+	L1:
+	    nextToken();
+	    e2 = parseShiftExp();
+	    e = new IdentityExp(op, loc, e, e2);
+	    break;
+
+	case TOKlt:
+	case TOKle:
+	case TOKgt:
+	case TOKge:
+	case TOKunord:
+	case TOKlg:
+	case TOKleg:
+	case TOKule:
+	case TOKul:
+	case TOKuge:
+	case TOKug:
+	case TOKue:
+	    nextToken();
+	    e2 = parseShiftExp();
+	    e = new CmpExp(op, loc, e, e2);
+	    break;
+
+	case TOKin:
+	    nextToken();
+	    e2 = parseShiftExp();
+	    e = new InExp(loc, e, e2);
+	    break;
+
+	default:
+	    break;
+    }
+    return e;
+}
+
+Expression *Parser::parseAndExp()
+{   Expression *e;
+    Expression *e2;
+    Loc loc = this->loc;
+
+    if (global.params.Dversion == 1)
+    {
+	e = parseEqualExp();
+	while (token.value == TOKand)
+	{
+	    nextToken();
+	    e2 = parseEqualExp();
+	    e = new AndExp(loc,e,e2);
+	    loc = this->loc;
+	}
+    }
+    else
+    {
+	e = parseCmpExp();
+	while (token.value == TOKand)
+	{
+	    nextToken();
+	    e2 = parseCmpExp();
+	    e = new AndExp(loc,e,e2);
+	    loc = this->loc;
+	}
+    }
+    return e;
+}
+
+Expression *Parser::parseXorExp()
+{   Expression *e;
+    Expression *e2;
+    Loc loc = this->loc;
+
+    e = parseAndExp();
+    while (token.value == TOKxor)
+    {
+	nextToken();
+	e2 = parseAndExp();
+	e = new XorExp(loc, e, e2);
+    }
+    return e;
+}
+
+Expression *Parser::parseOrExp()
+{   Expression *e;
+    Expression *e2;
+    Loc loc = this->loc;
+
+    e = parseXorExp();
+    while (token.value == TOKor)
+    {
+	nextToken();
+	e2 = parseXorExp();
+	e = new OrExp(loc, e, e2);
+    }
+    return e;
+}
+
+Expression *Parser::parseAndAndExp()
+{   Expression *e;
+    Expression *e2;
+    Loc loc = this->loc;
+
+    e = parseOrExp();
+    while (token.value == TOKandand)
+    {
+	nextToken();
+	e2 = parseOrExp();
+	e = new AndAndExp(loc, e, e2);
+    }
+    return e;
+}
+
+Expression *Parser::parseOrOrExp()
+{   Expression *e;
+    Expression *e2;
+    Loc loc = this->loc;
+
+    e = parseAndAndExp();
+    while (token.value == TOKoror)
+    {
+	nextToken();
+	e2 = parseAndAndExp();
+	e = new OrOrExp(loc, e, e2);
+    }
+    return e;
+}
+
+Expression *Parser::parseCondExp()
+{   Expression *e;
+    Expression *e1;
+    Expression *e2;
+    Loc loc = this->loc;
+
+    e = parseOrOrExp();
+    if (token.value == TOKquestion)
+    {
+	nextToken();
+	e1 = parseExpression();
+	check(TOKcolon);
+	e2 = parseCondExp();
+	e = new CondExp(loc, e, e1, e2);
+    }
+    return e;
+}
+
+Expression *Parser::parseAssignExp()
+{   Expression *e;
+    Expression *e2;
+    Loc loc;
+
+    e = parseCondExp();
+    while (1)
+    {
+	loc = this->loc;
+	switch (token.value)
+	{
+#define X(tok,ector) \
+	    case tok:  nextToken(); e2 = parseAssignExp(); e = new ector(loc,e,e2); continue;
+
+	    X(TOKassign,    AssignExp);
+	    X(TOKaddass,    AddAssignExp);
+	    X(TOKminass,    MinAssignExp);
+	    X(TOKmulass,    MulAssignExp);
+	    X(TOKdivass,    DivAssignExp);
+	    X(TOKmodass,    ModAssignExp);
+	    X(TOKandass,    AndAssignExp);
+	    X(TOKorass,     OrAssignExp);
+	    X(TOKxorass,    XorAssignExp);
+	    X(TOKshlass,    ShlAssignExp);
+	    X(TOKshrass,    ShrAssignExp);
+	    X(TOKushrass,   UshrAssignExp);
+	    X(TOKcatass,    CatAssignExp);
+
+#undef X
+	    default:
+		break;
+	}
+	break;
+    }
+    return e;
+}
+
+Expression *Parser::parseExpression()
+{   Expression *e;
+    Expression *e2;
+    Loc loc = this->loc;
+
+    //printf("Parser::parseExpression()\n");
+    e = parseAssignExp();
+    while (token.value == TOKcomma)
+    {
+	nextToken();
+	e2 = parseAssignExp();
+	e = new CommaExp(loc, e, e2);
+	loc = this->loc;
+    }
+    return e;
+}
+
+
+/*************************
+ * Collect argument list.
+ * Assume current token is '(' or '['.
+ */
+
+Expressions *Parser::parseArguments()
+{   // function call
+    Expressions *arguments;
+    Expression *arg;
+    enum TOK endtok;
+
+    arguments = new Expressions();
+    if (token.value == TOKlbracket)
+	endtok = TOKrbracket;
+    else
+	endtok = TOKrparen;
+
+    {
+	nextToken();
+	if (token.value != endtok)
+	{
+	    while (1)
+	    {
+		arg = parseAssignExp();
+		arguments->push(arg);
+		if (token.value == endtok)
+		    break;
+		check(TOKcomma);
+	    }
+	}
+	check(endtok);
+    }
+    return arguments;
+}
+
+/*******************************************
+ */
+
+Expression *Parser::parseNewExp(Expression *thisexp)
+{   Type *t;
+    Expressions *newargs;
+    Expressions *arguments = NULL;
+    Expression *e;
+    Loc loc = this->loc;
+
+    nextToken();
+    newargs = NULL;
+    if (token.value == TOKlparen)
+    {
+	newargs = parseArguments();
+    }
+
+    // An anonymous nested class starts with "class"
+    if (token.value == TOKclass)
+    {
+	nextToken();
+	if (token.value == TOKlparen)
+	    arguments = parseArguments();
+
+	BaseClasses *baseclasses = NULL;
+	if (token.value != TOKlcurly)
+	    baseclasses = parseBaseClasses();
+
+	Identifier *id = NULL;
+	ClassDeclaration *cd = new ClassDeclaration(loc, id, baseclasses);
+
+	if (token.value != TOKlcurly)
+	{   error("{ members } expected for anonymous class");
+	    cd->members = NULL;
+	}
+	else
+	{
+	    nextToken();
+	    Array *decl = parseDeclDefs(0);
+	    if (token.value != TOKrcurly)
+		error("class member expected");
+	    nextToken();
+	    cd->members = decl;
+	}
+
+	e = new NewAnonClassExp(loc, thisexp, newargs, cd, arguments);
+
+	return e;
+    }
+
+#if LTORARRAYDECL
+    t = parseBasicType();
+    t = parseBasicType2(t);
+    if (t->ty == Taarray)
+    {
+	Type *index = ((TypeAArray *)t)->index;
+
+	Expression *e = index->toExpression();
+	if (e)
+	{   arguments = new Expressions();
+	    arguments->push(e);
+	    t = new TypeDArray(t->next);
+	}
+	else
+	{
+	    error("need size of rightmost array, not type %s", index->toChars());
+	    return new NullExp(loc);
+	}
+    }
+    else if (t->ty == Tsarray)
+    {
+	TypeSArray *tsa = (TypeSArray *)t;
+	Expression *e = tsa->dim;
+
+	arguments = new Expressions();
+	arguments->push(e);
+	t = new TypeDArray(t->next);
+    }
+    else if (token.value == TOKlparen)
+    {
+	arguments = parseArguments();
+    }
+#else
+    t = parseBasicType();
+    while (token.value == TOKmul)
+    {   t = new TypePointer(t);
+	nextToken();
+    }
+    if (token.value == TOKlbracket)
+    {
+	Expression *e;
+
+	nextToken();
+	e = parseAssignExp();
+	arguments = new Array();
+	arguments->push(e);
+	check(TOKrbracket);
+	t = parseDeclarator(t, NULL);
+	t = new TypeDArray(t);
+    }
+    else if (token.value == TOKlparen)
+	arguments = parseArguments();
+#endif
+    e = new NewExp(loc, thisexp, newargs, t, arguments);
+    return e;
+}
+
+/**********************************************
+ */
+
+void Parser::addComment(Dsymbol *s, unsigned char *blockComment)
+{
+    s->addComment(combineComments(blockComment, token.lineComment));
+}
+
+
+/********************************* ***************************/
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/parse.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,135 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#ifndef DMD_PARSE_H
+#define DMD_PARSE_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include "arraytypes.h"
+#include "lexer.h"
+#include "enum.h"
+
+struct Type;
+struct Expression;
+struct Declaration;
+struct Statement;
+struct Import;
+struct Initializer;
+struct FuncDeclaration;
+struct CtorDeclaration;
+struct DtorDeclaration;
+struct StaticCtorDeclaration;
+struct StaticDtorDeclaration;
+struct ConditionalDeclaration;
+struct InvariantDeclaration;
+struct UnitTestDeclaration;
+struct NewDeclaration;
+struct DeleteDeclaration;
+struct Condition;
+struct Module;
+struct ModuleDeclaration;
+struct TemplateDeclaration;
+struct TemplateInstance;
+struct StaticAssert;
+
+/************************************
+ * These control how parseStatement() works.
+ */
+
+enum ParseStatementFlags
+{
+    PSsemi = 1,		// empty ';' statements are allowed
+    PSscope = 2,	// start a new scope
+    PScurly = 4,	// { } statement is required
+    PScurlyscope = 8,	// { } starts a new scope
+};
+
+
+struct Parser : Lexer
+{
+    ModuleDeclaration *md;
+    enum LINK linkage;
+    Loc endloc;			// set to location of last right curly
+    int inBrackets;		// inside [] of array index or slice
+
+    Parser(Module *module, unsigned char *base, unsigned length, int doDocComment);
+
+    Array *parseModule();
+    Array *parseDeclDefs(int once);
+    Array *parseBlock();
+    TemplateDeclaration *parseTemplateDeclaration();
+    TemplateParameters *parseTemplateParameterList();
+    Dsymbol *parseMixin();
+    Objects *parseTemplateArgumentList();
+    StaticAssert *parseStaticAssert();
+    enum LINK parseLinkage();
+    Condition *parseDebugCondition();
+    Condition *parseVersionCondition();
+    Condition *parseStaticIfCondition();
+    CtorDeclaration *parseCtor();
+    DtorDeclaration *parseDtor();
+    StaticCtorDeclaration *parseStaticCtor();
+    StaticDtorDeclaration *parseStaticDtor();
+    InvariantDeclaration *parseInvariant();
+    UnitTestDeclaration *parseUnitTest();
+    NewDeclaration *parseNew();
+    DeleteDeclaration *parseDelete();
+    Arguments *parseParameters(int *pvarargs);
+    EnumDeclaration *parseEnum();
+    Dsymbol *parseAggregate();
+    BaseClasses *parseBaseClasses();
+    Import *parseImport(Array *decldefs, int isstatic);
+    Type *parseBasicType();
+    Type *parseBasicType2(Type *t);
+    Type *parseDeclarator(Type *t, Identifier **pident, TemplateParameters **tpl = NULL);
+    Array *parseDeclarations();
+    void parseContracts(FuncDeclaration *f);
+    Statement *parseStatement(int flags);
+    Initializer *parseInitializer();
+    void check(Loc loc, enum TOK value);
+    void check(enum TOK value);
+    void check(enum TOK value, char *string);
+    int isDeclaration(Token *t, int needId, enum TOK endtok, Token **pt);
+    int isBasicType(Token **pt);
+    int isDeclarator(Token **pt, int *haveId, enum TOK endtok);
+    int isParameters(Token **pt);
+    int isExpression(Token **pt);
+    int isTemplateInstance(Token *t, Token **pt);
+    int skipParens(Token *t, Token **pt);
+
+    Expression *parseExpression();
+    Expression *parsePrimaryExp();
+    Expression *parseUnaryExp();
+    Expression *parsePostExp(Expression *e);
+    Expression *parseMulExp();
+    Expression *parseAddExp();
+    Expression *parseShiftExp();
+    Expression *parseRelExp();
+    Expression *parseEqualExp();
+    Expression *parseCmpExp();
+    Expression *parseAndExp();
+    Expression *parseXorExp();
+    Expression *parseOrExp();
+    Expression *parseAndAndExp();
+    Expression *parseOrOrExp();
+    Expression *parseCondExp();
+    Expression *parseAssignExp();
+
+    Expressions *parseArguments();
+
+    Expression *parseNewExp(Expression *thisexp);
+
+    void addComment(Dsymbol *s, unsigned char *blockComment);
+};
+
+#endif /* DMD_PARSE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/port.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,65 @@
+
+// Copyright (c) 1999-2002 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// www.digitalmars.com
+
+#ifndef PORT_H
+#define PORT_H
+
+// Portable wrapper around compiler/system specific things.
+// The idea is to minimize #ifdef's in the app code.
+
+#ifndef TYPEDEFS
+#define TYPEDEFS
+
+#include <wchar.h>
+
+#if _MSC_VER
+typedef __int64 longlong;
+typedef unsigned __int64 ulonglong;
+#else
+typedef long long longlong;
+typedef unsigned long long ulonglong;
+#endif
+
+#endif
+
+typedef double d_time;
+
+struct Port
+{
+    static double nan;
+    static double infinity;
+    static double dbl_max;
+    static double dbl_min;
+
+#if __GNUC__
+    // These conflict with macros in math.h, should rename them
+    #undef isnan
+    #undef isfinite
+    #undef isinfinity
+    #undef signbit
+#endif
+    static int isNan(double);
+    static int isFinite(double);
+    static int isInfinity(double);
+    static int Signbit(double);
+
+    static double floor(double);
+    static double pow(double x, double y);
+
+    static ulonglong strtoull(const char *p, char **pend, int base);
+
+    static char *ull_to_string(char *buffer, ulonglong ull);
+    static wchar_t *ull_to_string(wchar_t *buffer, ulonglong ull);
+
+    // Convert ulonglong to double
+    static double ull_to_double(ulonglong ull);
+
+    // Get locale-dependent list separator
+    static char *list_separator();
+    static wchar_t *wlist_separator();
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/readme.txt	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,27 @@
+
+		The D Programming Language
+		Compiler Front End Source
+		Copyright (c) 1999-2002, by Digital Mars
+		www.digitalmars.com
+		All Rights Reserved
+
+
+This is the source code to the front end Digital Mars D compiler.
+It covers the lexical analysis, parsing, and semantic analysis
+of the D Programming Language defined in the documents at
+www.digitalmars.com/d/
+
+The optimizer, code generator, and object file generator are not part
+of this source, hence the source does not currently constitute a complete,
+compilable program. However, many people have expressed a strong interested
+in producing a D compiler with the GNU compiler sources. This release should
+enable that.
+
+These sources are free, they are redistributable and modifiable
+under the terms of the GNU General Public License (attached as gpl.txt),
+or the Artistic License (attached as artistic.txt).
+
+It does not apply to anything else distributed by Digital Mars,
+including D compiler executables.
+
+-Walter Bright
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/root.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,1835 @@
+
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdint.h>
+#include <assert.h>
+
+#if _MSC_VER
+#include <malloc.h>
+#endif
+
+#if _WIN32
+#include <windows.h>
+#include <direct.h>
+#endif
+
+#if linux
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <utime.h>
+#endif
+
+#include "port.h"
+#include "root.h"
+#include "dchar.h"
+#include "mem.h"
+
+#if 0 //__SC__ //def DEBUG
+extern "C" void __cdecl _assert(void *e, void *f, unsigned line)
+{
+    printf("Assert('%s','%s',%d)\n",e,f,line);
+    fflush(stdout);
+    *(char *)0 = 0;
+}
+#endif
+
+/*************************************
+ * Convert wchar string to ascii string.
+ */
+
+char *wchar2ascii(wchar_t *us)
+{
+    return wchar2ascii(us, wcslen(us));
+}
+
+char *wchar2ascii(wchar_t *us, unsigned len)
+{
+    unsigned i;
+    char *p;
+
+    p = (char *)mem.malloc(len + 1);
+    for (i = 0; i <= len; i++)
+	p[i] = (char) us[i];
+    return p;
+}
+
+int wcharIsAscii(wchar_t *us)
+{
+    return wcharIsAscii(us, wcslen(us));
+}
+
+int wcharIsAscii(wchar_t *us, unsigned len)
+{
+    unsigned i;
+
+    for (i = 0; i <= len; i++)
+    {
+	if (us[i] & ~0xFF)	// if high bits set
+	    return 0;		// it's not ascii
+    }
+    return 1;
+}
+
+
+/***********************************
+ * Compare length-prefixed strings (bstr).
+ */
+
+int bstrcmp(unsigned char *b1, unsigned char *b2)
+{
+    return (*b1 == *b2 && memcmp(b1 + 1, b2 + 1, *b2) == 0) ? 0 : 1;
+}
+
+/***************************************
+ * Convert bstr into a malloc'd string.
+ */
+
+char *bstr2str(unsigned char *b)
+{
+    char *s;
+    unsigned len;
+
+    len = *b;
+    s = (char *) mem.malloc(len + 1);
+    s[len] = 0;
+    return (char *)memcpy(s,b + 1,len);
+}
+
+/**************************************
+ * Print error message and exit.
+ */
+
+void error(const char *format, ...)
+{
+    va_list ap;
+
+    va_start(ap, format);
+    printf("Error: ");
+    vprintf(format, ap);
+    va_end( ap );
+    printf("\n");
+    fflush(stdout);
+
+    exit(EXIT_FAILURE);
+}
+
+#if M_UNICODE
+void error(const dchar *format, ...)
+{
+    va_list ap;
+
+    va_start(ap, format);
+    printf("Error: ");
+    vwprintf(format, ap);
+    va_end( ap );
+    printf("\n");
+    fflush(stdout);
+
+    exit(EXIT_FAILURE);
+}
+#endif
+
+void error_mem()
+{
+    error("out of memory");
+}
+
+/**************************************
+ * Print warning message.
+ */
+
+void warning(const char *format, ...)
+{
+    va_list ap;
+
+    va_start(ap, format);
+    printf("Warning: ");
+    vprintf(format, ap);
+    va_end( ap );
+    printf("\n");
+    fflush(stdout);
+}
+
+/****************************** Object ********************************/
+
+int Object::equals(Object *o)
+{
+    return o == this;
+}
+
+hash_t Object::hashCode()
+{
+    return (hash_t) this;
+}
+
+int Object::compare(Object *obj)
+{
+    return this - obj;
+}
+
+void Object::print()
+{
+    printf("%s %p\n", toChars(), this);
+}
+
+char *Object::toChars()
+{
+    return "Object";
+}
+
+dchar *Object::toDchars()
+{
+#if M_UNICODE
+    return L"Object";
+#else
+    return toChars();
+#endif
+}
+
+int Object::dyncast()
+{
+    return 0;
+}
+
+void Object::toBuffer(OutBuffer *b)
+{
+    b->writestring("Object");
+}
+
+void Object::mark()
+{
+}
+
+/****************************** String ********************************/
+
+String::String(char *str, int ref)
+{
+    this->str = ref ? str : mem.strdup(str);
+    this->ref = ref;
+}
+
+String::~String()
+{
+    mem.free(str);
+}
+
+void String::mark()
+{
+    mem.mark(str);
+}
+
+hash_t String::calcHash(const char *str, size_t len)
+{
+    hash_t hash = 0;
+
+    for (;;)
+    {
+	switch (len)
+	{
+	    case 0:
+		return hash;
+
+	    case 1:
+		hash *= 37;
+		hash += *(uint8_t *)str;
+		return hash;
+
+	    case 2:
+		hash *= 37;
+		hash += *(uint16_t *)str;
+		return hash;
+
+	    case 3:
+		hash *= 37;
+		hash += (*(uint16_t *)str << 8) +
+			((uint8_t *)str)[2];
+		return hash;
+
+	    default:
+		hash *= 37;
+		hash += *(uint32_t *)str;
+		str += 4;
+		len -= 4;
+		break;
+	}
+    }
+}
+
+hash_t String::calcHash(const char *str)
+{
+    return calcHash(str, strlen(str));
+}
+
+hash_t String::hashCode()
+{
+    return calcHash(str, strlen(str));
+}
+
+unsigned String::len()
+{
+    return strlen(str);
+}
+
+int String::equals(Object *obj)
+{
+    return strcmp(str,((String *)obj)->str) == 0;
+}
+
+int String::compare(Object *obj)
+{
+    return strcmp(str,((String *)obj)->str);
+}
+
+char *String::toChars()
+{
+    return str;
+}
+
+void String::print()
+{
+    printf("String '%s'\n",str);
+}
+
+
+/****************************** FileName ********************************/
+
+FileName::FileName(char *str, int ref)
+    : String(str,ref)
+{
+}
+
+char *FileName::combine(char *path, char *name)
+{   char *f;
+    size_t pathlen;
+    size_t namelen;
+
+    if (!path || !*path)
+	return name;
+    pathlen = strlen(path);
+    namelen = strlen(name);
+    f = (char *)mem.malloc(pathlen + 1 + namelen + 1);
+    memcpy(f, path, pathlen);
+#if linux
+    if (path[pathlen - 1] != '/')
+    {	f[pathlen] = '/';
+	pathlen++;
+    }
+#endif
+#if _WIN32
+    if (path[pathlen - 1] != '\\' && path[pathlen - 1] != ':')
+    {	f[pathlen] = '\\';
+	pathlen++;
+    }
+#endif
+    memcpy(f + pathlen, name, namelen + 1);
+    return f;
+}
+
+FileName::FileName(char *path, char *name)
+    : String(combine(path,name),1)
+{
+}
+
+// Split a path into an Array of paths
+Array *FileName::splitPath(const char *path)
+{
+    char c = 0;				// unnecessary initializer is for VC /W4
+    const char *p;
+    OutBuffer buf;
+    Array *array;
+
+    array = new Array();
+    if (path)
+    {
+	p = path;
+	do
+	{   char instring = 0;
+
+	    while (isspace(*p))		// skip leading whitespace
+		p++;
+	    buf.reserve(strlen(p) + 1);	// guess size of path
+	    for (; ; p++)
+	    {
+		c = *p;
+		switch (c)
+		{
+		    case '"':
+			instring ^= 1;	// toggle inside/outside of string
+			continue;
+
+#if MACINTOSH
+		    case ',':
+#endif
+#if _WIN32
+		    case ';':
+#endif
+#if linux
+		    case ':':
+#endif
+			p++;
+			break;		// note that ; cannot appear as part
+					// of a path, quotes won't protect it
+
+		    case 0x1A:		// ^Z means end of file
+		    case 0:
+			break;
+
+		    case '\r':
+			continue;	// ignore carriage returns
+
+#if linux
+		    case '~':
+			buf.writestring(getenv("HOME"));
+			continue;
+#endif
+
+		    case ' ':
+		    case '\t':		// tabs in filenames?
+			if (!instring)	// if not in string
+			    break;	// treat as end of path
+		    default:
+			buf.writeByte(c);
+			continue;
+		}
+		break;
+	    }
+	    if (buf.offset)		// if path is not empty
+	    {
+		buf.writeByte(0);	// to asciiz
+		array->push(buf.extractData());
+	    }
+	} while (c);
+    }
+    return array;
+}
+
+hash_t FileName::hashCode()
+{
+#if _WIN32
+    // We need a different hashCode because it must be case-insensitive
+    size_t len = strlen(str);
+    hash_t hash = 0;
+    unsigned char *s = (unsigned char *)str;
+
+    for (;;)
+    {
+	switch (len)
+	{
+	    case 0:
+		return hash;
+
+	    case 1:
+		hash *= 37;
+		hash += *(uint8_t *)s | 0x20;
+		return hash;
+
+	    case 2:
+		hash *= 37;
+		hash += *(uint16_t *)s | 0x2020;
+		return hash;
+
+	    case 3:
+		hash *= 37;
+		hash += ((*(uint16_t *)s << 8) +
+			 ((uint8_t *)s)[2]) | 0x202020;
+		break;
+
+	    default:
+		hash *= 37;
+		hash += *(uint32_t *)s | 0x20202020;
+		s += 4;
+		len -= 4;
+		break;
+	}
+    }
+#else
+    // darwin HFS is case insensitive, though...
+    return String::hashCode();
+#endif
+}
+
+int FileName::compare(Object *obj)
+{
+#if _WIN32
+    return stricmp(str,((FileName *)obj)->str);
+#else
+    return String::compare(obj);
+#endif
+}
+
+int FileName::equals(Object *obj)
+{
+#if _WIN32
+    return stricmp(str,((FileName *)obj)->str) == 0;
+#else
+    return String::equals(obj);
+#endif
+}
+
+/************************************
+ * Return !=0 if absolute path name.
+ */
+
+int FileName::absolute(const char *name)
+{
+#if _WIN32
+    return (*name == '\\') ||
+	   (*name == '/')  ||
+	   (*name && name[1] == ':');
+#endif
+#if linux
+    return (*name == '/');
+#endif
+}
+
+/********************************
+ * Return filename extension (read-only).
+ * If there isn't one, return NULL.
+ */
+
+char *FileName::ext(const char *str)
+{
+    char *e;
+    size_t len = strlen(str);
+
+    e = (char *)str + len;
+    for (;;)
+    {
+	switch (*e)
+	{   case '.':
+		return e + 1;
+#if linux
+	    case '/':
+	        break;
+#endif
+#if _WIN32
+	    case '\\':
+	    case ':':
+		break;
+#endif
+	    default:
+		if (e == str)
+		    break;
+		e--;
+		continue;
+	}
+	return NULL;
+    }
+}
+
+char *FileName::ext()
+{
+    return ext(str);
+}
+
+/********************************
+ * Return filename name excluding path (read-only).
+ */
+
+char *FileName::name(const char *str)
+{
+    char *e;
+    size_t len = strlen(str);
+
+    e = (char *)str + len;
+    for (;;)
+    {
+	switch (*e)
+	{
+#if linux
+	    case '/':
+	       return e + 1;
+#endif
+#if _WIN32
+	    case '\\':
+	    case ':':
+		return e + 1;
+#endif
+	    default:
+		if (e == str)
+		    break;
+		e--;
+		continue;
+	}
+	return e;
+    }
+}
+
+char *FileName::name()
+{
+    return name(str);
+}
+
+/**************************************
+ * Return path portion of str.
+ * Path will does not include trailing path separator.
+ */
+
+char *FileName::path(const char *str)
+{
+    char *n = name(str);
+    char *path;
+    size_t pathlen;
+
+    if (n > str)
+    {
+#if linux
+	if (n[-1] == '/')
+	    n--;
+#endif
+#if _WIN32
+	if (n[-1] == '\\')
+	    n--;
+#endif
+    }
+    pathlen = n - str;
+    path = (char *)mem.malloc(pathlen + 1);
+    memcpy(path, str, pathlen);
+    path[pathlen] = 0;
+    return path;
+}
+
+/**************************************
+ * Replace filename portion of path.
+ */
+
+char *FileName::replaceName(char *path, char *name)
+{   char *f;
+    char *n;
+    size_t pathlen;
+    size_t namelen;
+
+    if (absolute(name))
+	return name;
+
+    n = FileName::name(path);
+    if (n == path)
+	return name;
+    pathlen = n - path;
+    namelen = strlen(name);
+    f = (char *)mem.malloc(pathlen + 1 + namelen + 1);
+    memcpy(f, path, pathlen);
+#if linux
+    if (path[pathlen - 1] != '/')
+    {	f[pathlen] = '/';
+	pathlen++;
+    }
+#endif
+#if _WIN32
+    if (path[pathlen - 1] != '\\' && path[pathlen - 1] != ':')
+    {	f[pathlen] = '\\';
+	pathlen++;
+    }
+#endif
+    memcpy(f + pathlen, name, namelen + 1);
+    return f;
+}
+
+/***************************
+ */
+
+FileName *FileName::defaultExt(const char *name, const char *ext)
+{
+    char *e;
+    char *s;
+    size_t len;
+    size_t extlen;
+
+    e = FileName::ext(name);
+    if (e)				// if already has an extension
+	return new FileName((char *)name, 0);
+
+    len = strlen(name);
+    extlen = strlen(ext);
+    s = (char *)alloca(len + 1 + extlen + 1);
+    memcpy(s,name,len);
+    s[len] = '.';
+    memcpy(s + len + 1, ext, extlen + 1);
+    return new FileName(s, 0);
+}
+
+/***************************
+ */
+
+FileName *FileName::forceExt(const char *name, const char *ext)
+{
+    char *e;
+    char *s;
+    size_t len;
+    size_t extlen;
+
+    e = FileName::ext(name);
+    if (e)				// if already has an extension
+    {
+	len = e - name;
+	extlen = strlen(ext);
+
+	s = (char *)alloca(len + extlen + 1);
+	memcpy(s,name,len);
+	memcpy(s + len, ext, extlen + 1);
+	return new FileName(s, 0);
+    }
+    else
+	return defaultExt(name, ext);	// doesn't have one
+}
+
+/******************************
+ * Return !=0 if extensions match.
+ */
+
+int FileName::equalsExt(const char *ext)
+{   const char *e;
+
+    e = FileName::ext();
+    if (!e && !ext)
+	return 1;
+    if (!e || !ext)
+	return 0;
+#if linux
+    return strcmp(e,ext) == 0;
+#endif
+#if _WIN32
+    return stricmp(e,ext) == 0;
+#endif
+}
+
+/*************************************
+ * Copy file from this to to.
+ */
+
+void FileName::CopyTo(FileName *to)
+{
+    File file(this);
+
+#if _WIN32
+    file.touchtime = mem.malloc(sizeof(WIN32_FIND_DATAA));	// keep same file time
+#endif
+#if linux
+    file.touchtime = mem.malloc(sizeof(struct stat)); // keep same file time
+#endif
+    file.readv();
+    file.name = to;
+    file.writev();
+}
+
+/*************************************
+ * Search Path for file.
+ * Input:
+ *	cwd	if !=0, search current directory before searching path
+ */
+
+char *FileName::searchPath(Array *path, char *name, int cwd)
+{
+    if (absolute(name))
+    {
+	return exists(name) ? name : NULL;
+    }
+    if (cwd)
+    {
+	if (exists(name))
+	    return name;
+    }
+    if (path)
+    {	unsigned i;
+
+	for (i = 0; i < path->dim; i++)
+	{
+	    char *p = (char *)path->data[i];
+	    char *n = combine(p, name);
+
+	    if (exists(n))
+		return n;
+	}
+    }
+    return NULL;
+}
+
+int FileName::exists(const char *name)
+{
+#if linux
+    struct stat st;
+
+    if (stat(name, &st) < 0)
+	return 0;
+    if (S_ISDIR(st.st_mode))
+	return 2;
+    return 1;
+#endif
+#if _WIN32
+    DWORD dw;
+    int result;
+
+    dw = GetFileAttributesA(name);
+    if (dw == -1L)
+	result = 0;
+    else if (dw & FILE_ATTRIBUTE_DIRECTORY)
+	result = 2;
+    else
+	result = 1;
+    return result;
+#endif
+}
+
+void FileName::ensurePathExists(const char *path)
+{
+    //printf("FileName::ensurePathExists(%s)\n", path ? path : "");
+    if (path && *path)
+    {
+	if (!exists(path))
+	{
+	    char *p = FileName::path(path);
+	    if (*p)
+	    {
+#if _WIN32
+		size_t len = strlen(p);
+		if (len > 2 && p[-1] == ':')
+		{   mem.free(p);
+		    return;
+		}
+#endif
+		ensurePathExists(p);
+		mem.free(p);
+	    }
+#if _WIN32
+	    if (path[strlen(path) - 1] != '\\')
+#endif
+#if linux
+	    if (path[strlen(path) - 1] != '\\')
+#endif
+	    {
+		//printf("mkdir(%s)\n", path);
+#if _WIN32
+		if (mkdir(path))
+#endif
+#if linux
+		if (mkdir(path, 0777))
+#endif
+		    error("cannot create directory %s", path);
+	    }
+	}
+    }
+}
+
+/****************************** File ********************************/
+
+File::File(FileName *n)
+{
+    ref = 0;
+    buffer = NULL;
+    len = 0;
+    touchtime = NULL;
+    name = n;
+}
+
+File::File(char *n)
+{
+    ref = 0;
+    buffer = NULL;
+    len = 0;
+    touchtime = NULL;
+    name = new FileName(n, 0);
+}
+
+File::~File()
+{
+    if (buffer)
+    {
+	if (ref == 0)
+	    mem.free(buffer);
+#if _WIN32
+	else if (ref == 2)
+	    UnmapViewOfFile(buffer);
+#endif
+    }
+    if (touchtime)
+	mem.free(touchtime);
+}
+
+void File::mark()
+{
+    mem.mark(buffer);
+    mem.mark(touchtime);
+    mem.mark(name);
+}
+
+/*************************************
+ */
+
+int File::read()
+{
+#if linux
+    off_t size;
+    ssize_t numread;
+    int fd;
+    struct stat buf;
+    int result = 0;
+    char *name;
+
+    name = this->name->toChars();
+    //printf("File::read('%s')\n",name);
+    fd = open(name, O_RDONLY);
+    if (fd == -1)
+    {	result = errno;
+	//printf("\topen error, errno = %d\n",errno);
+	goto err1;
+    }
+
+    if (!ref)
+	mem.free(buffer);
+    ref = 0;       // we own the buffer now
+
+    //printf("\tfile opened\n");
+    if (fstat(fd, &buf))
+    {
+	printf("\tfstat error, errno = %d\n",errno);
+        goto err2;
+    }
+    size = buf.st_size;
+    buffer = (unsigned char *) mem.malloc(size + 2);
+    if (!buffer)
+    {
+	printf("\tmalloc error, errno = %d\n",errno);
+	goto err2;
+    }
+
+    numread = ::read(fd, buffer, size);
+    if (numread != size)
+    {
+	printf("\tread error, errno = %d\n",errno);
+	goto err2;
+    }
+
+    if (touchtime)
+        memcpy(touchtime, &buf, sizeof(buf));
+
+    if (close(fd) == -1)
+    {
+	printf("\tclose error, errno = %d\n",errno);
+	goto err;
+    }
+
+    len = size;
+
+    // Always store a wchar ^Z past end of buffer so scanner has a sentinel
+    buffer[size] = 0;		// ^Z is obsolete, use 0
+    buffer[size + 1] = 0;
+    return 0;
+
+err2:
+    close(fd);
+err:
+    mem.free(buffer);
+    buffer = NULL;
+    len = 0;
+
+err1:
+    result = 1;
+    return result;
+#endif
+#if _WIN32
+    DWORD size;
+    DWORD numread;
+    HANDLE h;
+    int result = 0;
+    char *name;
+
+    name = this->name->toChars();
+    h = CreateFileA(name,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,
+	FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,0);
+    if (h == INVALID_HANDLE_VALUE)
+	goto err1;
+
+    if (!ref)
+	mem.free(buffer);
+    ref = 0;
+
+    size = GetFileSize(h,NULL);
+    buffer = (unsigned char *) mem.malloc(size + 2);
+    if (!buffer)
+	goto err2;
+
+    if (ReadFile(h,buffer,size,&numread,NULL) != TRUE)
+	goto err2;
+
+    if (numread != size)
+	goto err2;
+
+    if (touchtime)
+    {
+	if (!GetFileTime(h, NULL, NULL, &((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime))
+	    goto err2;
+    }
+
+    if (!CloseHandle(h))
+	goto err;
+
+    len = size;
+
+    // Always store a wchar ^Z past end of buffer so scanner has a sentinel
+    buffer[size] = 0;		// ^Z is obsolete, use 0
+    buffer[size + 1] = 0;
+    return 0;
+
+err2:
+    CloseHandle(h);
+err:
+    mem.free(buffer);
+    buffer = NULL;
+    len = 0;
+
+err1:
+    result = 1;
+    return result;
+#endif
+}
+
+/*****************************
+ * Read a file with memory mapped file I/O.
+ */
+
+int File::mmread()
+{
+#if linux
+    return read();
+#endif
+#if _WIN32
+    HANDLE hFile;
+    HANDLE hFileMap;
+    DWORD size;
+    char *name;
+
+    name = this->name->toChars();
+    hFile = CreateFile(name, GENERIC_READ,
+			FILE_SHARE_READ, NULL,
+			OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+    if (hFile == INVALID_HANDLE_VALUE)
+	goto Lerr;
+    size = GetFileSize(hFile, NULL);
+    //printf(" file created, size %d\n", size);
+
+    hFileMap = CreateFileMapping(hFile,NULL,PAGE_READONLY,0,size,NULL);
+    if (CloseHandle(hFile) != TRUE)
+	goto Lerr;
+
+    if (hFileMap == NULL)
+	goto Lerr;
+
+    //printf(" mapping created\n");
+
+    if (!ref)
+	mem.free(buffer);
+    ref = 2;
+    buffer = (unsigned char *)MapViewOfFileEx(hFileMap, FILE_MAP_READ,0,0,size,NULL);
+    if (CloseHandle(hFileMap) != TRUE)
+	goto Lerr;
+    if (buffer == NULL)			// mapping view failed
+	goto Lerr;
+
+    len = size;
+    //printf(" buffer = %p\n", buffer);
+
+    return 0;
+
+Lerr:
+    return GetLastError();			// failure
+#endif
+}
+
+/*********************************************
+ * Write a file.
+ * Returns:
+ *	0	success
+ */
+
+int File::write()
+{
+#if linux
+    int fd;
+    ssize_t numwritten;
+    char *name;
+
+    name = this->name->toChars();
+    fd = open(name, O_CREAT | O_WRONLY | O_TRUNC, 0660);
+    if (fd == -1)
+	goto err;
+
+    numwritten = ::write(fd, buffer, len);
+    if (len != numwritten)
+	goto err2;
+    
+    if (close(fd) == -1)
+	goto err;
+
+    if (touchtime)
+    {   struct utimbuf ubuf;
+
+        ubuf.actime = ((struct stat *)touchtime)->st_atime;
+        ubuf.modtime = ((struct stat *)touchtime)->st_mtime;
+	if (utime(name, &ubuf))
+	    goto err;
+    }
+    return 0;
+
+err2:
+    close(fd);
+    ::remove(name);
+err:
+    return 1;
+#endif
+#if _WIN32
+    HANDLE h;
+    DWORD numwritten;
+    char *name;
+
+    name = this->name->toChars();
+    h = CreateFileA(name,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,
+	FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL);
+    if (h == INVALID_HANDLE_VALUE)
+	goto err;
+
+    if (WriteFile(h,buffer,len,&numwritten,NULL) != TRUE)
+	goto err2;
+
+    if (len != numwritten)
+	goto err2;
+    
+    if (touchtime) {
+        SetFileTime(h, NULL, NULL, &((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime);
+    }
+    if (!CloseHandle(h))
+	goto err;
+    return 0;
+
+err2:
+    CloseHandle(h);
+    DeleteFileA(name);
+err:
+    return 1;
+#endif
+}
+
+/*********************************************
+ * Append to a file.
+ * Returns:
+ *	0	success
+ */
+
+int File::append()
+{
+#if linux
+    return 1;
+#endif
+#if _WIN32
+    HANDLE h;
+    DWORD numwritten;
+    char *name;
+
+    name = this->name->toChars();
+    h = CreateFileA(name,GENERIC_WRITE,0,NULL,OPEN_ALWAYS,
+	FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL);
+    if (h == INVALID_HANDLE_VALUE)
+	goto err;
+
+#if 1
+    SetFilePointer(h, 0, NULL, FILE_END);
+#else // INVALID_SET_FILE_POINTER doesn't seem to have a definition
+    if (SetFilePointer(h, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER)
+	goto err;
+#endif
+
+    if (WriteFile(h,buffer,len,&numwritten,NULL) != TRUE)
+	goto err2;
+
+    if (len != numwritten)
+	goto err2;
+    
+    if (touchtime) {
+        SetFileTime(h, NULL, NULL, &((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime);
+    }
+    if (!CloseHandle(h))
+	goto err;
+    return 0;
+
+err2:
+    CloseHandle(h);
+err:
+    return 1;
+#endif
+}
+
+/**************************************
+ */
+
+void File::readv()
+{
+    if (read())
+	error("Error reading file '%s'\n",name->toChars());
+}
+
+/**************************************
+ */
+
+void File::mmreadv()
+{
+    if (mmread())
+	readv();
+}
+
+void File::writev()
+{
+    if (write())
+	error("Error writing file '%s'\n",name->toChars());
+}
+
+void File::appendv()
+{
+    if (write())
+	error("Error appending to file '%s'\n",name->toChars());
+}
+
+/*******************************************
+ * Return !=0 if file exists.
+ *	0:	file doesn't exist
+ *	1:	normal file
+ *	2:	directory
+ */
+
+int File::exists()
+{
+#if linux
+    return 0;
+#endif
+#if _WIN32
+    DWORD dw;
+    int result;
+    char *name;
+
+    name = this->name->toChars();
+    if (touchtime)
+	dw = ((WIN32_FIND_DATAA *)touchtime)->dwFileAttributes;
+    else
+	dw = GetFileAttributesA(name);
+    if (dw == -1L)
+	result = 0;
+    else if (dw & FILE_ATTRIBUTE_DIRECTORY)
+	result = 2;
+    else
+	result = 1;
+    return result;
+#endif
+}
+
+void File::remove()
+{
+#if linux
+    ::remove(this->name->toChars());
+#endif
+#if _WIN32
+    DeleteFileA(this->name->toChars());
+#endif
+}
+
+Array *File::match(char *n)
+{
+    return match(new FileName(n, 0));
+}
+
+Array *File::match(FileName *n)
+{
+#if linux
+    return NULL;
+#endif
+#if _WIN32
+    HANDLE h;
+    WIN32_FIND_DATAA fileinfo;
+    Array *a;
+    char *c;
+    char *name;
+
+    a = new Array();
+    c = n->toChars();
+    name = n->name();
+    h = FindFirstFileA(c,&fileinfo);
+    if (h != INVALID_HANDLE_VALUE)
+    {
+	do
+	{
+	    // Glue path together with name
+	    char *fn;
+	    File *f;
+
+	    fn = (char *)mem.malloc(name - c + strlen(fileinfo.cFileName) + 1);
+	    memcpy(fn, c, name - c);
+	    strcpy(fn + (name - c), fileinfo.cFileName);
+	    f = new File(fn);
+	    f->touchtime = mem.malloc(sizeof(WIN32_FIND_DATAA));
+	    memcpy(f->touchtime, &fileinfo, sizeof(fileinfo));
+	    a->push(f);
+	} while (FindNextFileA(h,&fileinfo) != FALSE);
+	FindClose(h);
+    }
+    return a;
+#endif
+}
+
+int File::compareTime(File *f)
+{
+#if linux
+    return 0;
+#endif
+#if _WIN32
+    if (!touchtime)
+	stat();
+    if (!f->touchtime)
+	f->stat();
+    return CompareFileTime(&((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime, &((WIN32_FIND_DATAA *)f->touchtime)->ftLastWriteTime);
+#endif
+}
+
+void File::stat()
+{
+#if linux
+    if (!touchtime)
+    {
+	touchtime = mem.calloc(1, sizeof(struct stat));
+    }
+#endif
+#if _WIN32
+    HANDLE h;
+
+    if (!touchtime)
+    {
+	touchtime = mem.calloc(1, sizeof(WIN32_FIND_DATAA));
+    }
+    h = FindFirstFileA(name->toChars(),(WIN32_FIND_DATAA *)touchtime);
+    if (h != INVALID_HANDLE_VALUE)
+    {
+	FindClose(h);
+    }
+#endif
+}
+
+void File::checkoffset(size_t offset, size_t nbytes)
+{
+    if (offset > len || offset + nbytes > len)
+	error("Corrupt file '%s': offset x%zx off end of file",toChars(),offset);
+}
+
+char *File::toChars()
+{
+    return name->toChars();
+}
+
+
+/************************* OutBuffer *************************/
+
+OutBuffer::OutBuffer()
+{
+    data = NULL;
+    offset = 0;
+    size = 0;
+}
+
+OutBuffer::~OutBuffer()
+{
+    mem.free(data);
+}
+
+void *OutBuffer::extractData()
+{
+    void *p;
+
+    p = (void *)data;
+    data = NULL;
+    offset = 0;
+    size = 0;
+    return p;
+}
+
+void OutBuffer::mark()
+{
+    mem.mark(data);
+}
+
+void OutBuffer::reserve(unsigned nbytes)
+{
+    //printf("OutBuffer::reserve: size = %d, offset = %d, nbytes = %d\n", size, offset, nbytes);
+    if (size - offset < nbytes)
+    {
+	size = (offset + nbytes) * 2;
+	data = (unsigned char *)mem.realloc(data, size);
+    }
+}
+
+void OutBuffer::reset()
+{
+    offset = 0;
+}
+
+void OutBuffer::setsize(unsigned size)
+{
+    offset = size;
+}
+
+void OutBuffer::write(const void *data, unsigned nbytes)
+{
+    reserve(nbytes);
+    memcpy(this->data + offset, data, nbytes);
+    offset += nbytes;
+}
+
+void OutBuffer::writebstring(unsigned char *string)
+{
+    write(string,*string + 1);
+}
+
+void OutBuffer::writestring(char *string)
+{
+    write(string,strlen(string));
+}
+
+void OutBuffer::writedstring(const char *string)
+{
+#if M_UNICODE
+    for (; *string; string++)
+    {
+	writedchar(*string);
+    }
+#else
+    write(string,strlen(string));
+#endif
+}
+
+void OutBuffer::writedstring(const wchar_t *string)
+{
+#if M_UNICODE
+    write(string,wcslen(string) * sizeof(wchar_t));
+#else
+    for (; *string; string++)
+    {
+	writedchar(*string);
+    }
+#endif
+}
+
+void OutBuffer::prependstring(char *string)
+{   unsigned len;
+
+    len = strlen(string);
+    reserve(len);
+    memmove(data + len, data, offset);
+    memcpy(data, string, len);
+    offset += len;
+}
+
+void OutBuffer::writenl()
+{
+#if _WIN32
+#if M_UNICODE
+    write4(0x000A000D);		// newline is CR,LF on Microsoft OS's
+#else
+    writeword(0x0A0D);		// newline is CR,LF on Microsoft OS's
+#endif
+#else
+#if M_UNICODE
+    writeword('\n');
+#else
+    writeByte('\n');
+#endif
+#endif
+}
+
+void OutBuffer::writeByte(unsigned b)
+{
+    reserve(1);
+    this->data[offset] = (unsigned char)b;
+    offset++;
+}
+
+void OutBuffer::writeUTF8(unsigned b)
+{
+    reserve(6);
+    if (b <= 0x7F)
+    {
+	this->data[offset] = (unsigned char)b;
+	offset++;
+    }
+    else if (b <= 0x7FF)
+    {
+	this->data[offset + 0] = (unsigned char)((b >> 6) | 0xC0);
+	this->data[offset + 1] = (unsigned char)((b & 0x3F) | 0x80);
+	offset += 2;
+    }
+    else if (b <= 0xFFFF)
+    {
+	this->data[offset + 0] = (unsigned char)((b >> 12) | 0xE0);
+	this->data[offset + 1] = (unsigned char)(((b >> 6) & 0x3F) | 0x80);
+	this->data[offset + 2] = (unsigned char)((b & 0x3F) | 0x80);
+	offset += 3;
+    }
+    else if (b <= 0x1FFFFF)
+    {
+	this->data[offset + 0] = (unsigned char)((b >> 18) | 0xF0);
+	this->data[offset + 1] = (unsigned char)(((b >> 12) & 0x3F) | 0x80);
+	this->data[offset + 2] = (unsigned char)(((b >> 6) & 0x3F) | 0x80);
+	this->data[offset + 3] = (unsigned char)((b & 0x3F) | 0x80);
+	offset += 4;
+    }
+    else if (b <= 0x3FFFFFF)
+    {
+	this->data[offset + 0] = (unsigned char)((b >> 24) | 0xF8);
+	this->data[offset + 1] = (unsigned char)(((b >> 18) & 0x3F) | 0x80);
+	this->data[offset + 2] = (unsigned char)(((b >> 12) & 0x3F) | 0x80);
+	this->data[offset + 3] = (unsigned char)(((b >> 6) & 0x3F) | 0x80);
+	this->data[offset + 4] = (unsigned char)((b & 0x3F) | 0x80);
+	offset += 5;
+    }
+    else if (b <= 0x7FFFFFFF)
+    {
+	this->data[offset + 0] = (unsigned char)((b >> 30) | 0xFC);
+	this->data[offset + 1] = (unsigned char)(((b >> 24) & 0x3F) | 0x80);
+	this->data[offset + 2] = (unsigned char)(((b >> 18) & 0x3F) | 0x80);
+	this->data[offset + 3] = (unsigned char)(((b >> 12) & 0x3F) | 0x80);
+	this->data[offset + 4] = (unsigned char)(((b >> 6) & 0x3F) | 0x80);
+	this->data[offset + 5] = (unsigned char)((b & 0x3F) | 0x80);
+	offset += 6;
+    }
+    else
+	assert(0);
+}
+
+void OutBuffer::writedchar(unsigned b)
+{
+    reserve(Dchar_mbmax * sizeof(dchar));
+    offset = (unsigned char *)Dchar::put((dchar *)(this->data + offset), (dchar)b) -
+		this->data;
+}
+
+void OutBuffer::prependbyte(unsigned b)
+{
+    reserve(1);
+    memmove(data + 1, data, offset);
+    data[0] = (unsigned char)b;
+    offset++;
+}
+
+void OutBuffer::writeword(unsigned w)
+{
+    reserve(2);
+    *(unsigned short *)(this->data + offset) = (unsigned short)w;
+    offset += 2;
+}
+
+void OutBuffer::writeUTF16(unsigned w)
+{
+    reserve(4);
+    if (w <= 0xFFFF)
+    {
+	*(unsigned short *)(this->data + offset) = (unsigned short)w;
+	offset += 2;
+    }
+    else if (w <= 0x10FFFF)
+    {
+	*(unsigned short *)(this->data + offset) = (unsigned short)((w >> 10) + 0xD7C0);
+	*(unsigned short *)(this->data + offset + 2) = (unsigned short)((w & 0x3FF) | 0xDC00);
+	offset += 4;
+    }
+    else
+	assert(0);
+}
+
+void OutBuffer::write4(unsigned w)
+{
+    reserve(4);
+    *(unsigned long *)(this->data + offset) = w;
+    offset += 4;
+}
+
+void OutBuffer::write(OutBuffer *buf)
+{
+    if (buf)
+    {	reserve(buf->offset);
+	memcpy(data + offset, buf->data, buf->offset);
+	offset += buf->offset;
+    }
+}
+
+void OutBuffer::write(Object *obj)
+{
+    if (obj)
+    {
+	writestring(obj->toChars());
+    }
+}
+
+void OutBuffer::fill0(unsigned nbytes)
+{
+    reserve(nbytes);
+    memset(data + offset,0,nbytes);
+    offset += nbytes;
+}
+
+void OutBuffer::align(unsigned size)
+{   unsigned nbytes;
+
+    nbytes = ((offset + size - 1) & ~(size - 1)) - offset;
+    fill0(nbytes);
+}
+
+void OutBuffer::vprintf(const char *format, va_list args)
+{
+    char buffer[128];
+    char *p;
+    unsigned psize;
+    int count;
+
+    p = buffer;
+    psize = sizeof(buffer);
+    for (;;)
+    {
+#if _WIN32
+	count = _vsnprintf(p,psize,format,args);
+	if (count != -1)
+	    break;
+	psize *= 2;
+#endif
+#if linux
+	count = vsnprintf(p,psize,format,args);
+	if (count == -1)
+	    psize *= 2;
+	else if (count >= psize)
+	    psize = count + 1;
+	else
+	    break;
+#endif
+	p = (char *) alloca(psize);	// buffer too small, try again with larger size
+    }
+    write(p,count);
+}
+
+#if M_UNICODE
+void OutBuffer::vprintf(const wchar_t *format, va_list args)
+{
+    dchar buffer[128];
+    dchar *p;
+    unsigned psize;
+    int count;
+
+    p = buffer;
+    psize = sizeof(buffer) / sizeof(buffer[0]);
+    for (;;)
+    {
+#if _WIN32
+	count = _vsnwprintf(p,psize,format,args);
+	if (count != -1)
+	    break;
+	psize *= 2;
+#endif
+#if linux
+	count = vsnwprintf(p,psize,format,args);
+	if (count == -1)
+	    psize *= 2;
+	else if (count >= psize)
+	    psize = count + 1;
+	else
+	    break;
+#endif
+	p = (dchar *) alloca(psize * 2);	// buffer too small, try again with larger size
+    }
+    write(p,count * 2);
+}
+#endif
+
+void OutBuffer::printf(const char *format, ...)
+{
+    va_list ap;
+    va_start(ap, format);
+    vprintf(format,ap);
+    va_end(ap);
+}
+
+#if M_UNICODE
+void OutBuffer::printf(const wchar_t *format, ...)
+{
+    va_list ap;
+    va_start(ap, format);
+    vprintf(format,ap);
+    va_end(ap);
+}
+#endif
+
+void OutBuffer::bracket(char left, char right)
+{
+    reserve(2);
+    memmove(data + 1, data, offset);
+    data[0] = left;
+    data[offset + 1] = right;
+    offset += 2;
+}
+
+/******************
+ * Insert left at i, and right at j.
+ * Return index just past right.
+ */
+
+unsigned OutBuffer::bracket(unsigned i, char *left, unsigned j, char *right)
+{
+    size_t leftlen = strlen(left);
+    size_t rightlen = strlen(right);
+    reserve(leftlen + rightlen);
+    insert(i, left, leftlen);
+    insert(j + leftlen, right, rightlen);
+    return j + leftlen + rightlen;
+}
+
+void OutBuffer::spread(unsigned offset, unsigned nbytes)
+{
+    reserve(nbytes);
+    memmove(data + offset + nbytes, data + offset,
+	this->offset - offset);
+    this->offset += nbytes;
+}
+
+/****************************************
+ * Returns: offset + nbytes
+ */
+
+unsigned OutBuffer::insert(unsigned offset, const void *p, unsigned nbytes)
+{
+    spread(offset, nbytes);
+    memmove(data + offset, p, nbytes);
+    return offset + nbytes;
+}
+
+void OutBuffer::remove(unsigned offset, unsigned nbytes)
+{
+    memmove(data + offset, data + offset + nbytes, this->offset - (offset + nbytes));
+    this->offset -= nbytes;
+}
+
+char *OutBuffer::toChars()
+{
+    writeByte(0);
+    return (char *)data;
+}
+
+/********************************* Bits ****************************/
+
+Bits::Bits()
+{
+    data = NULL;
+    bitdim = 0;
+    allocdim = 0;
+}
+
+Bits::~Bits()
+{
+    mem.free(data);
+}
+
+void Bits::mark()
+{
+    mem.mark(data);
+}
+
+void Bits::resize(unsigned bitdim)
+{
+    unsigned allocdim;
+    unsigned mask;
+
+    allocdim = (bitdim + 31) / 32;
+    data = (unsigned *)mem.realloc(data, allocdim * sizeof(data[0]));
+    if (this->allocdim < allocdim)
+	memset(data + this->allocdim, 0, (allocdim - this->allocdim) * sizeof(data[0]));
+
+    // Clear other bits in last word
+    mask = (1 << (bitdim & 31)) - 1;
+    if (mask)
+	data[allocdim - 1] &= ~mask;
+
+    this->bitdim = bitdim;
+    this->allocdim = allocdim;
+}
+
+void Bits::set(unsigned bitnum)
+{
+    data[bitnum / 32] |= 1 << (bitnum & 31);
+}
+
+void Bits::clear(unsigned bitnum)
+{
+    data[bitnum / 32] &= ~(1 << (bitnum & 31));
+}
+
+int Bits::test(unsigned bitnum)
+{
+    return data[bitnum / 32] & (1 << (bitnum & 31));
+}
+
+void Bits::set()
+{   unsigned mask;
+
+    memset(data, ~0, allocdim * sizeof(data[0]));
+
+    // Clear other bits in last word
+    mask = (1 << (bitdim & 31)) - 1;
+    if (mask)
+	data[allocdim - 1] &= mask;
+}
+
+void Bits::clear()
+{
+    memset(data, 0, allocdim * sizeof(data[0]));
+}
+
+void Bits::copy(Bits *from)
+{
+    assert(bitdim == from->bitdim);
+    memcpy(data, from->data, allocdim * sizeof(data[0]));
+}
+
+Bits *Bits::clone()
+{
+    Bits *b;
+
+    b = new Bits();
+    b->resize(bitdim);
+    b->copy(this);
+    return b;
+}
+
+void Bits::sub(Bits *b)
+{
+    unsigned u;
+
+    for (u = 0; u < allocdim; u++)
+	data[u] &= ~b->data[u];
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/root.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,349 @@
+
+
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#ifndef ROOT_H
+#define ROOT_H
+
+#include <stdlib.h>
+#include <stdarg.h>
+
+#if __DMC__
+#pragma once
+#endif
+
+typedef size_t hash_t;
+
+#include "dchar.h"
+
+char *wchar2ascii(wchar_t *);
+int wcharIsAscii(wchar_t *);
+char *wchar2ascii(wchar_t *, unsigned len);
+int wcharIsAscii(wchar_t *, unsigned len);
+
+int bstrcmp(unsigned char *s1, unsigned char *s2);
+char *bstr2str(unsigned char *b);
+void error(const char *format, ...);
+void error(const wchar_t *format, ...);
+void warning(const char *format, ...);
+
+#ifndef TYPEDEFS
+#define TYPEDEFS
+
+#if _MSC_VER
+typedef __int64 longlong;
+typedef unsigned __int64 ulonglong;
+#else
+typedef long long longlong;
+typedef unsigned long long ulonglong;
+#endif
+
+#endif
+
+longlong randomx();
+
+/*
+ * Root of our class library.
+ */
+
+struct OutBuffer;
+struct Array;
+
+struct Object
+{
+    Object() { }
+    virtual ~Object() { }
+
+    virtual int equals(Object *o);
+
+    /**
+     * Returns a hash code, useful for things like building hash tables of Objects.
+     */
+    virtual hash_t hashCode();
+
+    /**
+     * Return <0, ==0, or >0 if this is less than, equal to, or greater than obj.
+     * Useful for sorting Objects.
+     */
+    virtual int compare(Object *obj);
+
+    /**
+     * Pretty-print an Object. Useful for debugging the old-fashioned way.
+     */
+    virtual void print();
+
+    virtual char *toChars();
+    virtual dchar *toDchars();
+    virtual void toBuffer(OutBuffer *buf);
+
+    /**
+     * Used as a replacement for dynamic_cast. Returns a unique number
+     * defined by the library user. For Object, the return value is 0.
+     */
+    virtual int dyncast();
+
+    /**
+     * Marks pointers for garbage collector by calling mem.mark() for all pointers into heap.
+     */
+    /*virtual*/		// not used, disable for now
+	void mark();
+};
+
+struct String : Object
+{
+    int ref;			// != 0 if this is a reference to someone else's string
+    char *str;			// the string itself
+
+    String(char *str, int ref = 1);
+
+    ~String();
+
+    static hash_t calcHash(const char *str, size_t len);
+    static hash_t calcHash(const char *str);
+    hash_t hashCode();
+    unsigned len();
+    int equals(Object *obj);
+    int compare(Object *obj);
+    char *toChars();
+    void print();
+    void mark();
+};
+
+struct FileName : String
+{
+    FileName(char *str, int ref);
+    FileName(char *path, char *name);
+    hash_t hashCode();
+    int equals(Object *obj);
+    int compare(Object *obj);
+    static int absolute(const char *name);
+    static char *ext(const char *);
+    char *ext();
+    static char *name(const char *);
+    char *name();
+    static char *path(const char *);
+    static char *replaceName(char *path, char *name);
+
+    static char *combine(char *path, char *name);
+    static Array *splitPath(const char *path);
+    static FileName *defaultExt(const char *name, const char *ext);
+    static FileName *forceExt(const char *name, const char *ext);
+    int equalsExt(const char *ext);
+
+    void CopyTo(FileName *to);
+    static char *searchPath(Array *path, char *name, int cwd);
+    static int exists(const char *name);
+    static void ensurePathExists(const char *path);
+};
+
+struct File : Object
+{
+    int ref;			// != 0 if this is a reference to someone else's buffer
+    unsigned char *buffer;	// data for our file
+    unsigned len;		// amount of data in buffer[]
+    void *touchtime;		// system time to use for file
+
+    FileName *name;		// name of our file
+
+    File(char *);
+    File(FileName *);
+    ~File();
+
+    void mark();
+
+    char *toChars();
+
+    /* Read file, return !=0 if error
+     */
+
+    int read();
+
+    /* Write file, either succeed or fail
+     * with error message & exit.
+     */
+
+    void readv();
+
+    /* Read file, return !=0 if error
+     */
+
+    int mmread();
+
+    /* Write file, either succeed or fail
+     * with error message & exit.
+     */
+
+    void mmreadv();
+
+    /* Write file, return !=0 if error
+     */
+
+    int write();
+
+    /* Write file, either succeed or fail
+     * with error message & exit.
+     */
+
+    void writev();
+
+    /* Return !=0 if file exists.
+     *	0:	file doesn't exist
+     *	1:	normal file
+     *	2:	directory
+     */
+
+    /* Append to file, return !=0 if error
+     */
+
+    int append();
+
+    /* Append to file, either succeed or fail
+     * with error message & exit.
+     */
+
+    void appendv();
+
+    /* Return !=0 if file exists.
+     *	0:	file doesn't exist
+     *	1:	normal file
+     *	2:	directory
+     */
+
+    int exists();
+
+    /* Given wildcard filespec, return an array of
+     * matching File's.
+     */
+
+    static Array *match(char *);
+    static Array *match(FileName *);
+
+    // Compare file times.
+    // Return	<0	this < f
+    //		=0	this == f
+    //		>0	this > f
+    int compareTime(File *f);
+
+    // Read system file statistics
+    void stat();
+
+    /* Set buffer
+     */
+
+    void setbuffer(void *buffer, unsigned len)
+    {
+	this->buffer = (unsigned char *)buffer;
+	this->len = len;
+    }
+
+    void checkoffset(size_t offset, size_t nbytes);
+
+    void remove();		// delete file
+};
+
+struct OutBuffer : Object
+{
+    unsigned char *data;
+    unsigned offset;
+    unsigned size;
+
+    OutBuffer();
+    ~OutBuffer();
+    void *extractData();
+    void mark();
+
+    void reserve(unsigned nbytes);
+    void setsize(unsigned size);
+    void reset();
+    void write(const void *data, unsigned nbytes);
+    void writebstring(unsigned char *string);
+    void writestring(char *string);
+    void writedstring(const char *string);
+    void writedstring(const wchar_t *string);
+    void prependstring(char *string);
+    void writenl();			// write newline
+    void writeByte(unsigned b);
+    void writebyte(unsigned b) { writeByte(b); }
+    void writeUTF8(unsigned b);
+    void writedchar(unsigned b);
+    void prependbyte(unsigned b);
+    void writeword(unsigned w);
+    void writeUTF16(unsigned w);
+    void write4(unsigned w);
+    void write(OutBuffer *buf);
+    void write(Object *obj);
+    void fill0(unsigned nbytes);
+    void align(unsigned size);
+    void vprintf(const char *format, va_list args);
+    void printf(const char *format, ...);
+#if M_UNICODE
+    void vprintf(const unsigned short *format, va_list args);
+    void printf(const unsigned short *format, ...);
+#endif
+    void bracket(char left, char right);
+    unsigned bracket(unsigned i, char *left, unsigned j, char *right);
+    void spread(unsigned offset, unsigned nbytes);
+    unsigned insert(unsigned offset, const void *data, unsigned nbytes);
+    void remove(unsigned offset, unsigned nbytes);
+    char *toChars();
+    char *extractString();
+};
+
+struct Array : Object
+{
+    unsigned dim;
+    unsigned allocdim;
+    void **data;
+
+    Array();
+    ~Array();
+    void mark();
+    char *toChars();
+
+    void reserve(unsigned nentries);
+    void setDim(unsigned newdim);
+    void fixDim();
+    void push(void *ptr);
+    void *pop();
+    void shift(void *ptr);
+    void insert(unsigned index, void *ptr);
+    void insert(unsigned index, Array *a);
+    void append(Array *a);
+    void remove(unsigned i);
+    void zero();
+    void *tos();
+    void sort();
+    Array *copy();
+};
+
+struct Bits : Object
+{
+    unsigned bitdim;
+    unsigned allocdim;
+    unsigned *data;
+
+    Bits();
+    ~Bits();
+    void mark();
+
+    void resize(unsigned bitdim);
+
+    void set(unsigned bitnum);
+    void clear(unsigned bitnum);
+    int test(unsigned bitnum);
+
+    void set();
+    void clear();
+    void copy(Bits *from);
+    Bits *clone();
+
+    void sub(Bits *b);
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/scope.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,357 @@
+
+// Copyright (c) 1999-2005 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "root.h"
+
+#include "mars.h"
+#include "init.h"
+#include "identifier.h"
+#include "attrib.h"
+#include "dsymbol.h"
+#include "scope.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "module.h"
+#include "id.h"
+
+Scope *Scope::freelist = NULL;
+
+void *Scope::operator new(size_t size)
+{
+    if (freelist)
+    {
+	Scope *s = freelist;
+	freelist = s->enclosing;
+	//printf("freelist %p\n", s);
+	assert(s->flags & SCOPEfree);
+	s->flags &= ~SCOPEfree;
+	return s;
+    }
+
+    void *p = ::operator new(size);
+    //printf("new %p\n", p);
+    return p;
+}
+
+Scope::Scope()
+{   // Create root scope
+
+    //printf("Scope::Scope() %p\n", this);
+    this->module = NULL;
+    this->scopesym = NULL;
+    this->sd = NULL;
+    this->enclosing = NULL;
+    this->parent = NULL;
+    this->sw = NULL;
+    this->tf = NULL;
+    this->sbreak = NULL;
+    this->scontinue = NULL;
+    this->fes = NULL;
+    this->structalign = global.structalign;
+    this->func = NULL;
+    this->slabel = NULL;
+    this->linkage = LINKd;
+    this->protection = PROTpublic;
+    this->explicitProtection = 0;
+    this->stc = 0;
+    this->offset = 0;
+    this->inunion = 0;
+    this->incontract = 0;
+    this->nofree = 0;
+    this->noctor = 0;
+    this->intypeof = 0;
+    this->parameterSpecialization = 0;
+    this->callSuper = 0;
+    this->flags = 0;
+    this->anonAgg = NULL;
+    this->lastdc = NULL;
+    this->lastoffset = 0;
+    this->docbuf = NULL;
+}
+
+Scope::Scope(Scope *enclosing)
+{
+    //printf("Scope::Scope(enclosing = %p) %p\n", enclosing, this);
+    assert(!(enclosing->flags & SCOPEfree));
+    this->module = enclosing->module;
+    this->func   = enclosing->func;
+    this->parent = enclosing->parent;
+    this->scopesym = NULL;
+    this->sd = NULL;
+    this->sw = enclosing->sw;
+    this->tf = enclosing->tf;
+    this->sbreak = enclosing->sbreak;
+    this->scontinue = enclosing->scontinue;
+    this->fes = enclosing->fes;
+    this->structalign = enclosing->structalign;
+    this->enclosing = enclosing;
+#ifdef DEBUG
+    if (enclosing->enclosing)
+	assert(!(enclosing->enclosing->flags & SCOPEfree));
+    if (this == enclosing->enclosing)
+    {
+	printf("this = %p, enclosing = %p, enclosing->enclosing = %p\n", this, enclosing, enclosing->enclosing);
+    }
+    assert(this != enclosing->enclosing);
+#endif
+    this->slabel = NULL;
+    this->linkage = enclosing->linkage;
+    this->protection = enclosing->protection;
+    this->explicitProtection = enclosing->explicitProtection;
+    this->stc = enclosing->stc;
+    this->offset = 0;
+    this->inunion = enclosing->inunion;
+    this->incontract = enclosing->incontract;
+    this->nofree = 0;
+    this->noctor = enclosing->noctor;
+    this->intypeof = enclosing->intypeof;
+    this->parameterSpecialization = enclosing->parameterSpecialization;
+    this->callSuper = enclosing->callSuper;
+    this->flags = 0;
+    this->anonAgg = NULL;
+    this->lastdc = NULL;
+    this->lastoffset = 0;
+    this->docbuf = enclosing->docbuf;
+    assert(this != enclosing);
+}
+
+Scope *Scope::createGlobal(Module *module)
+{
+    Scope *sc;
+
+    sc = new Scope();
+    sc->module = module;
+    sc->scopesym = new ScopeDsymbol();
+    sc->scopesym->symtab = new DsymbolTable();
+
+    // Add top level package as member of this global scope
+    Dsymbol *m = module;
+    while (m->parent)
+	m = m->parent;
+    m->addMember(NULL, sc->scopesym, 1);
+    m->parent = NULL;			// got changed by addMember()
+
+    // Create the module scope underneath the global scope
+    sc = sc->push(module);
+    sc->parent = module;
+    return sc;
+}
+
+Scope *Scope::push()
+{
+    //printf("Scope::push()\n");
+    Scope *s = new Scope(this);
+    assert(this != s);
+    return s;
+}
+
+Scope *Scope::push(ScopeDsymbol *ss)
+{
+    //printf("Scope::push(%s)\n", ss->toChars());
+    Scope *s = push();
+    s->scopesym = ss;
+    return s;
+}
+
+Scope *Scope::pop()
+{
+    //printf("Scope::pop() %p nofree = %d\n", this, nofree);
+    Scope *enc = enclosing;
+
+    if (enclosing)
+	enclosing->callSuper |= callSuper;
+
+    if (!nofree)
+    {	enclosing = freelist;
+	freelist = this;
+	flags |= SCOPEfree;
+    }
+
+    return enc;
+}
+
+void Scope::mergeCallSuper(Loc loc, unsigned cs)
+{
+    // This does a primitive flow analysis to support the restrictions
+    // regarding when and how constructors can appear.
+    // It merges the results of two paths.
+    // The two paths are callSuper and cs; the result is merged into callSuper.
+
+    if (cs != callSuper)
+    {	int a;
+	int b;
+
+	callSuper |= cs & (CSXany_ctor | CSXlabel);
+	if (cs & CSXreturn)
+	{
+	}
+	else if (callSuper & CSXreturn)
+	{
+	    callSuper = cs | (callSuper & (CSXany_ctor | CSXlabel));
+	}
+	else
+	{
+	    a = (cs        & (CSXthis_ctor | CSXsuper_ctor)) != 0;
+	    b = (callSuper & (CSXthis_ctor | CSXsuper_ctor)) != 0;
+	    if (a != b)
+		error(loc, "one path skips constructor");
+	    callSuper |= cs;
+	}
+    }
+}
+
+Dsymbol *Scope::search(Loc loc, Identifier *ident, Dsymbol **pscopesym)
+{   Dsymbol *s;
+    Scope *sc;
+
+    //printf("Scope::search(%p, '%s')\n", this, ident->toChars());
+    if (ident == Id::empty)
+    {
+	// Look for module scope
+	for (sc = this; sc; sc = sc->enclosing)
+	{
+	    assert(sc != sc->enclosing);
+	    if (sc->scopesym)
+	    {
+		s = sc->scopesym->isModule();
+		if (s)
+		{
+		    //printf("\tfound %s.%s\n", s->parent ? s->parent->toChars() : "", s->toChars());
+		    if (pscopesym)
+			*pscopesym = sc->scopesym;
+		    return s;
+		}
+	    }
+	}
+	return NULL;
+    }
+
+    for (sc = this; sc; sc = sc->enclosing)
+    {
+	assert(sc != sc->enclosing);
+	if (sc->scopesym)
+	{
+	    //printf("\tlooking in scopesym '%s', kind = '%s'\n", sc->scopesym->toChars(), sc->scopesym->kind());
+	    s = sc->scopesym->search(loc, ident, 0);
+	    if (s)
+	    {
+		if ((global.params.warnings ||
+		    global.params.Dversion > 1) &&
+		    ident == Id::length &&
+		    sc->scopesym->isArrayScopeSymbol() &&
+		    sc->enclosing &&
+		    sc->enclosing->search(loc, ident, NULL))
+		{
+		    if (global.params.warnings)
+			fprintf(stdmsg, "warning - ");
+		    error(s->loc, "array 'length' hides other 'length' name in outer scope");
+		}
+
+		//printf("\tfound %s.%s, kind = '%s'\n", s->parent ? s->parent->toChars() : "", s->toChars(), s->kind());
+		if (pscopesym)
+		    *pscopesym = sc->scopesym;
+		return s;
+	    }
+	}
+    }
+
+    return NULL;
+}
+
+Dsymbol *Scope::insert(Dsymbol *s)
+{   Scope *sc;
+
+    for (sc = this; sc; sc = sc->enclosing)
+    {
+	//printf("\tsc = %p\n", sc);
+	if (sc->scopesym)
+	{
+	    //printf("\t\tsc->scopesym = %p\n", sc->scopesym);
+	    if (!sc->scopesym->symtab)
+		sc->scopesym->symtab = new DsymbolTable();
+	    return sc->scopesym->symtab->insert(s);
+	}
+    }
+    assert(0);
+    return NULL;
+}
+
+/********************************************
+ * Search enclosing scopes for ClassDeclaration.
+ */
+
+ClassDeclaration *Scope::getClassScope()
+{   Scope *sc;
+
+    for (sc = this; sc; sc = sc->enclosing)
+    {
+	ClassDeclaration *cd;
+
+	if (sc->scopesym)
+	{
+	    cd = sc->scopesym->isClassDeclaration();
+	    if (cd)
+		return cd;
+	}
+    }
+    return NULL;
+}
+
+/********************************************
+ * Search enclosing scopes for ClassDeclaration.
+ */
+
+AggregateDeclaration *Scope::getStructClassScope()
+{   Scope *sc;
+
+    for (sc = this; sc; sc = sc->enclosing)
+    {
+	AggregateDeclaration *ad;
+
+	if (sc->scopesym)
+	{
+	    ad = sc->scopesym->isClassDeclaration();
+	    if (ad)
+		return ad;
+	    else
+	    {	ad = sc->scopesym->isStructDeclaration();
+		if (ad)
+		    return ad;
+	    }
+	}
+    }
+    return NULL;
+}
+
+/*******************************************
+ * For TemplateDeclarations, we need to remember the Scope
+ * where it was declared. So mark the Scope as not
+ * to be free'd.
+ */
+
+void Scope::setNoFree()
+{   Scope *sc;
+    //int i = 0;
+
+    //printf("Scope::setNoFree(this = %p)\n", this);
+    for (sc = this; sc; sc = sc->enclosing)
+    {
+	//printf("\tsc = %p\n", sc);
+	sc->nofree = 1;
+
+	assert(!(flags & SCOPEfree));
+	//assert(sc != sc->enclosing);
+	//assert(!sc->enclosing || sc != sc->enclosing->enclosing);
+	//if (++i == 10)
+	    //assert(0);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/scope.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,109 @@
+
+// Copyright (c) 1999-2005 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#ifndef DMD_SCOPE_H
+#define DMD_SCOPE_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+struct Dsymbol;
+struct ScopeDsymbol;
+struct Array;
+struct Identifier;
+struct Module;
+struct Statement;
+struct SwitchStatement;
+struct TryFinallyStatement;
+struct LabelStatement;
+struct ForeachStatement;
+struct ClassDeclaration;
+struct AggregateDeclaration;
+struct AnonymousAggregateDeclaration;
+struct FuncDeclaration;
+struct DocComment;
+enum LINK;
+enum PROT;
+
+struct Scope
+{
+    Scope *enclosing;		// enclosing Scope
+
+    Module *module;		// Root module
+    ScopeDsymbol *scopesym;	// current symbol
+    ScopeDsymbol *sd;		// if in static if, and declaring new symbols,
+				// sd gets the addMember()
+    FuncDeclaration *func;	// function we are in
+    Dsymbol *parent;		// parent to use
+    LabelStatement *slabel;	// enclosing labelled statement
+    SwitchStatement *sw;	// enclosing switch statement
+    TryFinallyStatement *tf;	// enclosing try finally statement
+    Statement *sbreak;		// enclosing statement that supports "break"
+    Statement *scontinue;	// enclosing statement that supports "continue"
+    ForeachStatement *fes;	// if nested function for ForeachStatement, this is it
+    unsigned offset;		// next offset to use in aggregate
+    int inunion;		// we're processing members of a union
+    int incontract;		// we're inside contract code
+    int nofree;			// set if shouldn't free it
+    int noctor;			// set if constructor calls aren't allowed
+    int intypeof;		// in typeof(exp)
+    int parameterSpecialization; // if in template parameter specialization
+
+    unsigned callSuper;		// primitive flow analysis for constructors
+#define	CSXthis_ctor	1	// called this()
+#define CSXsuper_ctor	2	// called super()
+#define CSXthis		4	// referenced this
+#define CSXsuper	8	// referenced super
+#define CSXlabel	0x10	// seen a label
+#define CSXreturn	0x20	// seen a return statement
+#define CSXany_ctor	0x40	// either this() or super() was called
+
+    unsigned structalign;	// alignment for struct members
+    enum LINK linkage;		// linkage for external functions
+
+    enum PROT protection;	// protection for class members
+    int explicitProtection;	// set if in an explicit protection attribute
+
+    unsigned stc;		// storage class
+
+    unsigned flags;
+#define SCOPEctor	1	// constructor type
+#define SCOPEstaticif	2	// inside static if
+#define SCOPEfree	4	// is on free list
+
+    AnonymousAggregateDeclaration *anonAgg;	// for temporary analysis
+
+    DocComment *lastdc;		// documentation comment for last symbol at this scope
+    unsigned lastoffset;	// offset in docbuf of where to insert next dec
+    OutBuffer *docbuf;		// buffer for documentation output
+
+    static Scope *freelist;
+    static void *operator new(size_t sz);
+    static Scope *createGlobal(Module *module);
+
+    Scope();
+    Scope(Module *module);
+    Scope(Scope *enclosing);
+
+    Scope *push();
+    Scope *push(ScopeDsymbol *ss);
+    Scope *pop();
+
+    void mergeCallSuper(Loc loc, unsigned cs);
+
+    Dsymbol *search(Loc loc, Identifier *ident, Dsymbol **pscopesym);
+    Dsymbol *insert(Dsymbol *s);
+
+    ClassDeclaration *getClassScope();
+    AggregateDeclaration *getStructClassScope();
+    void setNoFree();
+};
+
+#endif /* DMD_SCOPE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/statement.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,3564 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "mem.h"
+
+#include "statement.h"
+#include "expression.h"
+#include "cond.h"
+#include "init.h"
+#include "staticassert.h"
+#include "mtype.h"
+#include "scope.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "id.h"
+#include "hdrgen.h"
+#include "parse.h"
+
+/******************************** Statement ***************************/
+
+Statement::Statement(Loc loc)
+    : loc(loc)
+{
+#ifdef _DH
+    // If this is an in{} contract scope statement (skip for determining
+    //  inlineStatus of a function body for header content)
+    incontract = 0;
+#endif
+}
+
+Statement *Statement::syntaxCopy()
+{
+    assert(0);
+    return NULL;
+}
+
+void Statement::print()
+{
+    fprintf(stdmsg, "%s\n", toChars());
+    fflush(stdmsg);
+}
+
+char *Statement::toChars()
+{   OutBuffer *buf;
+    HdrGenState hgs;
+
+    buf = new OutBuffer();
+    toCBuffer(buf, &hgs);
+    return buf->toChars();
+}
+
+void Statement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->printf("Statement::toCBuffer()");
+    buf->writenl();
+}
+
+Statement *Statement::semantic(Scope *sc)
+{
+    return this;
+}
+
+// Same as semantic(), but do create a new scope
+
+Statement *Statement::semanticScope(Scope *sc, Statement *sbreak, Statement *scontinue)
+{   Scope *scd;
+    Statement *s;
+
+    scd = sc->push();
+    if (sbreak)
+	scd->sbreak = sbreak;
+    if (scontinue)
+	scd->scontinue = scontinue;
+    s = semantic(scd);
+    scd->pop();
+    return s;
+}
+
+void Statement::error(const char *format, ...)
+{
+    va_list ap;
+    va_start(ap, format);
+    ::verror(loc, format, ap);
+    va_end( ap );
+}
+
+int Statement::hasBreak()
+{
+    //printf("Statement::hasBreak()\n");
+    return FALSE;
+}
+
+int Statement::hasContinue()
+{
+    return FALSE;
+}
+
+// TRUE if statement uses exception handling
+
+int Statement::usesEH()
+{
+    return FALSE;
+}
+
+// TRUE if statement may fall off the end without a throw or return
+
+int Statement::fallOffEnd()
+{
+    return TRUE;
+}
+
+// TRUE if statement 'comes from' somewhere else, like a goto
+
+int Statement::comeFrom()
+{
+    //printf("Statement::comeFrom()\n");
+    return FALSE;
+}
+
+/****************************************
+ * If this statement has code that needs to run in a finally clause
+ * at the end of the current scope, return that code in the form of
+ * a Statement.
+ * Output:
+ *	*sentry		code executed upon entry to the scope
+ *	*sexception	code executed upon exit from the scope via exception
+ *	*sfinally	code executed in finally block
+ */
+
+void Statement::scopeCode(Statement **sentry, Statement **sexception, Statement **sfinally)
+{
+    //printf("Statement::scopeCode()\n");
+    //print();
+    *sentry = NULL;
+    *sexception = NULL;
+    *sfinally = NULL;
+}
+
+/*********************************
+ * Flatten out the scope by presenting the statement
+ * as an array of statements.
+ * Returns NULL if no flattening necessary.
+ */
+
+Statements *Statement::flatten(Scope *sc)
+{
+    return NULL;
+}
+
+
+/******************************** ExpStatement ***************************/
+
+ExpStatement::ExpStatement(Loc loc, Expression *exp)
+    : Statement(loc)
+{
+    this->exp = exp;
+}
+
+Statement *ExpStatement::syntaxCopy()
+{
+    Expression *e = exp ? exp->syntaxCopy() : NULL;
+    ExpStatement *es = new ExpStatement(loc, e);
+    return es;
+}
+
+void ExpStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    if (exp)
+	exp->toCBuffer(buf, hgs);
+    buf->writeByte(';');
+    if (!hgs->FLinit.init)
+        buf->writenl();
+}
+
+Statement *ExpStatement::semantic(Scope *sc)
+{
+    if (exp)
+    {
+	//printf("ExpStatement::semantic() %s\n", exp->toChars());
+	exp = exp->semantic(sc);
+	exp = resolveProperties(sc, exp);
+	exp->checkSideEffect(0);
+	exp = exp->optimize(0);
+	//exp = exp->optimize(isDeclarationStatement() ? WANTvalue : 0);
+    }
+    return this;
+}
+
+int ExpStatement::fallOffEnd()
+{
+    if (exp)
+    {
+	if (exp->op == TOKassert)
+	{   AssertExp *a = (AssertExp *)exp;
+
+	    if (a->e1->isBool(FALSE))	// if it's an assert(0)
+		return FALSE;
+	}
+	else if (exp->op == TOKhalt)
+	    return FALSE;
+    }
+    return TRUE;
+}
+
+/******************************** CompileStatement ***************************/
+
+CompileStatement::CompileStatement(Loc loc, Expression *exp)
+    : Statement(loc)
+{
+    this->exp = exp;
+}
+
+Statement *CompileStatement::syntaxCopy()
+{
+    Expression *e = exp->syntaxCopy();
+    CompileStatement *es = new CompileStatement(loc, e);
+    return es;
+}
+
+void CompileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("mixin(");
+    exp->toCBuffer(buf, hgs);
+    buf->writestring(");");
+    if (!hgs->FLinit.init)
+        buf->writenl();
+}
+
+Statement *CompileStatement::semantic(Scope *sc)
+{
+    //printf("CompileStatement::semantic() %s\n", exp->toChars());
+    exp = exp->semantic(sc);
+    exp = resolveProperties(sc, exp);
+    exp = exp->optimize(WANTvalue | WANTinterpret);
+    if (exp->op != TOKstring)
+    {	error("argument to mixin must be a string, not (%s)", exp->toChars());
+	return this;
+    }
+    StringExp *se = (StringExp *)exp;
+    se = se->toUTF8(sc);
+    Parser p(sc->module, (unsigned char *)se->string, se->len, 0);
+    p.loc = loc;
+    p.nextToken();
+
+    Statements *statements = new Statements();
+    while (p.token.value != TOKeof)
+    {
+	Statement *s = p.parseStatement(PSsemi | PScurlyscope);
+	statements->push(s);
+    }
+
+    Statement *s = new CompoundStatement(loc, statements);
+    return s->semantic(sc);
+}
+
+
+/******************************** DeclarationStatement ***************************/
+
+DeclarationStatement::DeclarationStatement(Loc loc, Dsymbol *declaration)
+    : ExpStatement(loc, new DeclarationExp(loc, declaration))
+{
+}
+
+DeclarationStatement::DeclarationStatement(Loc loc, Expression *exp)
+    : ExpStatement(loc, exp)
+{
+}
+
+Statement *DeclarationStatement::syntaxCopy()
+{
+    DeclarationStatement *ds = new DeclarationStatement(loc, exp->syntaxCopy());
+    return ds;
+}
+
+void DeclarationStatement::scopeCode(Statement **sentry, Statement **sexception, Statement **sfinally)
+{
+    //printf("DeclarationStatement::scopeCode()\n");
+    //print();
+
+    *sentry = NULL;
+    *sexception = NULL;
+    *sfinally = NULL;
+
+    if (exp)
+    {
+	if (exp->op == TOKdeclaration)
+	{
+	    DeclarationExp *de = (DeclarationExp *)(exp);
+	    VarDeclaration *v = de->declaration->isVarDeclaration();
+	    if (v)
+	    {	Expression *e;
+
+		e = v->callAutoDtor();
+		if (e)
+		{
+		    //printf("dtor is: "); e->print();
+		    *sfinally = new ExpStatement(loc, e);
+		}
+	    }
+	}
+    }
+}
+
+void DeclarationStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    exp->toCBuffer(buf, hgs);
+}
+
+
+/******************************** CompoundStatement ***************************/
+
+CompoundStatement::CompoundStatement(Loc loc, Statements *s)
+    : Statement(loc)
+{
+    statements = s;
+}
+
+CompoundStatement::CompoundStatement(Loc loc, Statement *s1, Statement *s2)
+    : Statement(loc)
+{
+    statements = new Statements();
+    statements->reserve(2);
+    statements->push(s1);
+    statements->push(s2);
+}
+
+Statement *CompoundStatement::syntaxCopy()
+{
+    Statements *a = new Statements();
+    a->setDim(statements->dim);
+    for (size_t i = 0; i < statements->dim; i++)
+    {	Statement *s = (Statement *)statements->data[i];
+	if (s)
+	    s = s->syntaxCopy();
+	a->data[i] = s;
+    }
+    CompoundStatement *cs = new CompoundStatement(loc, a);
+    return cs;
+}
+
+
+Statement *CompoundStatement::semantic(Scope *sc)
+{   Statement *s;
+
+    //printf("CompoundStatement::semantic(this = %p, sc = %p)\n", this, sc);
+
+    for (size_t i = 0; i < statements->dim; )
+    {
+	s = (Statement *) statements->data[i];
+	if (s)
+	{   Statements *a = s->flatten(sc);
+
+	    if (a)
+	    {
+		statements->remove(i);
+		statements->insert(i, a);
+		continue;
+	    }
+	    s = s->semantic(sc);
+	    statements->data[i] = s;
+	    if (s)
+	    {
+		Statement *sentry;
+		Statement *sexception;
+		Statement *sfinally;
+
+		s->scopeCode(&sentry, &sexception, &sfinally);
+		if (sentry)
+		{
+		    sentry = sentry->semantic(sc);
+		    statements->data[i] = sentry;
+		}
+		if (sexception)
+		{
+		    if (i + 1 == statements->dim && !sfinally)
+		    {
+#if 1
+			sexception = sexception->semantic(sc);
+#else
+			statements->push(sexception);
+			if (sfinally)
+			    // Assume sexception does not throw
+			    statements->push(sfinally);
+#endif
+		    }
+		    else
+		    {
+			/* Rewrite:
+			 *	s; s1; s2;
+			 * As:
+			 *	s;
+			 *	try { s1; s2; }
+			 *	catch (Object __o)
+			 *	{ sexception; throw __o; }
+			 */
+			Statement *body;
+			Statements *a = new Statements();
+
+			for (int j = i + 1; j < statements->dim; j++)
+			{
+			    a->push(statements->data[j]);
+			}
+			body = new CompoundStatement(0, a);
+			body = new ScopeStatement(0, body);
+
+			static int num;
+			char name[3 + sizeof(num) * 3 + 1];
+			sprintf(name, "__o%d", ++num);
+			Identifier *id = Lexer::idPool(name);
+
+			Statement *handler = new ThrowStatement(0, new IdentifierExp(0, id));
+			handler = new CompoundStatement(0, sexception, handler);
+
+			Array *catches = new Array();
+			Catch *ctch = new Catch(0, NULL, id, handler);
+			catches->push(ctch);
+			s = new TryCatchStatement(0, body, catches);
+
+			if (sfinally)
+			    s = new TryFinallyStatement(0, s, sfinally);
+			s = s->semantic(sc);
+			statements->setDim(i + 1);
+			statements->push(s);
+			break;
+		    }
+		}
+		else if (sfinally)
+		{
+		    if (0 && i + 1 == statements->dim)
+		    {
+			statements->push(sfinally);
+		    }
+		    else
+		    {
+			/* Rewrite:
+			 *	s; s1; s2;
+			 * As:
+			 *	s; try { s1; s2; } finally { sfinally; }
+			 */
+			Statement *body;
+			Statements *a = new Statements();
+
+			for (int j = i + 1; j < statements->dim; j++)
+			{
+			    a->push(statements->data[j]);
+			}
+			body = new CompoundStatement(0, a);
+			s = new TryFinallyStatement(0, body, sfinally);
+			s = s->semantic(sc);
+			statements->setDim(i + 1);
+			statements->push(s);
+			break;
+		    }
+		}
+	    }
+	}
+	i++;
+    }
+    if (statements->dim == 1)
+	return s;
+    return this;
+}
+
+Statements *CompoundStatement::flatten(Scope *sc)
+{
+    return statements;
+}
+
+ReturnStatement *CompoundStatement::isReturnStatement()
+{   int i;
+    ReturnStatement *rs = NULL;
+
+    for (i = 0; i < statements->dim; i++)
+    {	Statement *s;
+
+	s = (Statement *) statements->data[i];
+	if (s)
+	{
+	    rs = s->isReturnStatement();
+	    if (rs)
+		break;
+	}
+    }
+    return rs;
+}
+
+void CompoundStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{   int i;
+
+    for (i = 0; i < statements->dim; i++)
+    {	Statement *s;
+
+	s = (Statement *) statements->data[i];
+	if (s)
+	    s->toCBuffer(buf, hgs);
+    }
+}
+
+int CompoundStatement::usesEH()
+{
+    for (int i = 0; i < statements->dim; i++)
+    {	Statement *s;
+
+	s = (Statement *) statements->data[i];
+	if (s && s->usesEH())
+	    return TRUE;
+    }
+    return FALSE;
+}
+
+int CompoundStatement::fallOffEnd()
+{   int falloff = TRUE;
+
+    //printf("CompoundStatement::fallOffEnd()\n");
+    for (int i = 0; i < statements->dim; i++)
+    {	Statement *s = (Statement *)statements->data[i];
+
+	if (!s)
+	    continue;
+
+	if (!falloff && global.params.warnings && !s->comeFrom())
+	{
+	    fprintf(stdmsg, "warning - ");
+	    s->error("statement is not reachable");
+	}
+	falloff = s->fallOffEnd();
+    }
+    return falloff;
+}
+
+int CompoundStatement::comeFrom()
+{   int comefrom = FALSE;
+
+    //printf("CompoundStatement::comeFrom()\n");
+    for (int i = 0; i < statements->dim; i++)
+    {	Statement *s = (Statement *)statements->data[i];
+
+	if (!s)
+	    continue;
+
+	comefrom |= s->comeFrom();
+    }
+    return comefrom;
+}
+
+
+/**************************** UnrolledLoopStatement ***************************/
+
+UnrolledLoopStatement::UnrolledLoopStatement(Loc loc, Statements *s)
+    : Statement(loc)
+{
+    statements = s;
+}
+
+Statement *UnrolledLoopStatement::syntaxCopy()
+{
+    Statements *a = new Statements();
+    a->setDim(statements->dim);
+    for (size_t i = 0; i < statements->dim; i++)
+    {	Statement *s = (Statement *)statements->data[i];
+	if (s)
+	    s = s->syntaxCopy();
+	a->data[i] = s;
+    }
+    UnrolledLoopStatement *cs = new UnrolledLoopStatement(loc, a);
+    return cs;
+}
+
+
+Statement *UnrolledLoopStatement::semantic(Scope *sc)
+{
+    //printf("UnrolledLoopStatement::semantic(this = %p, sc = %p)\n", this, sc);
+
+    sc->noctor++;
+    Scope *scd = sc->push();
+    scd->sbreak = this;
+    scd->scontinue = this;
+
+    for (size_t i = 0; i < statements->dim; i++)
+    {
+	Statement *s = (Statement *) statements->data[i];
+	if (s)
+	{
+	    s = s->semantic(scd);
+	    statements->data[i] = s;
+	}
+    }
+
+    scd->pop();
+    sc->noctor--;
+    return this;
+}
+
+void UnrolledLoopStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("unrolled {");
+    buf->writenl();
+
+    for (size_t i = 0; i < statements->dim; i++)
+    {	Statement *s;
+
+	s = (Statement *) statements->data[i];
+	if (s)
+	    s->toCBuffer(buf, hgs);
+    }
+
+    buf->writeByte('}');
+    buf->writenl();
+}
+
+int UnrolledLoopStatement::hasBreak()
+{
+    return TRUE;
+}
+
+int UnrolledLoopStatement::hasContinue()
+{
+    return TRUE;
+}
+
+int UnrolledLoopStatement::usesEH()
+{
+    for (size_t i = 0; i < statements->dim; i++)
+    {	Statement *s;
+
+	s = (Statement *) statements->data[i];
+	if (s && s->usesEH())
+	    return TRUE;
+    }
+    return FALSE;
+}
+
+int UnrolledLoopStatement::fallOffEnd()
+{   int falloff = TRUE;
+
+    //printf("UnrolledLoopStatement::fallOffEnd()\n");
+    for (size_t i = 0; i < statements->dim; i++)
+    {	Statement *s = (Statement *)statements->data[i];
+
+	if (!s)
+	    continue;
+
+	if (!falloff && global.params.warnings && !s->comeFrom())
+	{
+	    fprintf(stdmsg, "warning - ");
+	    s->error("statement is not reachable");
+	}
+	falloff = s->fallOffEnd();
+    }
+    return falloff;
+}
+
+int UnrolledLoopStatement::comeFrom()
+{   int comefrom = FALSE;
+
+    //printf("UnrolledLoopStatement::comeFrom()\n");
+    for (size_t i = 0; i < statements->dim; i++)
+    {	Statement *s = (Statement *)statements->data[i];
+
+	if (!s)
+	    continue;
+
+	comefrom |= s->comeFrom();
+    }
+    return comefrom;
+}
+
+
+/******************************** ScopeStatement ***************************/
+
+ScopeStatement::ScopeStatement(Loc loc, Statement *s)
+    : Statement(loc)
+{
+    this->statement = s;
+}
+
+Statement *ScopeStatement::syntaxCopy()
+{
+    Statement *s;
+
+    s = statement ? statement->syntaxCopy() : NULL;
+    s = new ScopeStatement(loc, s);
+    return s;
+}
+
+
+Statement *ScopeStatement::semantic(Scope *sc)
+{   ScopeDsymbol *sym;
+
+    //printf("ScopeStatement::semantic(sc = %p)\n", sc);
+    if (statement)
+    {	Statements *a;
+
+	sym = new ScopeDsymbol();
+	sym->parent = sc->scopesym;
+	sc = sc->push(sym);
+
+	a = statement->flatten(sc);
+	if (a)
+	{
+	    statement = new CompoundStatement(loc, a);
+	}
+
+	statement = statement->semantic(sc);
+	if (statement)
+	{
+	    Statement *sentry;
+	    Statement *sexception;
+	    Statement *sfinally;
+
+	    statement->scopeCode(&sentry, &sexception, &sfinally);
+	    if (sfinally)
+	    {
+		//printf("adding sfinally\n");
+		statement = new CompoundStatement(loc, statement, sfinally);
+	    }
+	}
+
+	sc->pop();
+    }
+    return this;
+}
+
+int ScopeStatement::hasBreak()
+{
+    //printf("ScopeStatement::hasBreak() %s\n", toChars());
+    return statement ? statement->hasBreak() : FALSE;
+}
+
+int ScopeStatement::hasContinue()
+{
+    return statement ? statement->hasContinue() : FALSE;
+}
+
+int ScopeStatement::usesEH()
+{
+    return statement ? statement->usesEH() : FALSE;
+}
+
+int ScopeStatement::fallOffEnd()
+{
+    return statement ? statement->fallOffEnd() : TRUE;
+}
+
+int ScopeStatement::comeFrom()
+{
+    //printf("ScopeStatement::comeFrom()\n");
+    return statement ? statement->comeFrom() : FALSE;
+}
+
+void ScopeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writeByte('{');
+    buf->writenl();
+
+    if (statement)
+	statement->toCBuffer(buf, hgs);
+
+    buf->writeByte('}');
+    buf->writenl();
+}
+
+/******************************** WhileStatement ***************************/
+
+WhileStatement::WhileStatement(Loc loc, Expression *c, Statement *b)
+    : Statement(loc)
+{
+    condition = c;
+    body = b;
+}
+
+Statement *WhileStatement::syntaxCopy()
+{
+    WhileStatement *s = new WhileStatement(loc, condition->syntaxCopy(), body ? body->syntaxCopy() : NULL);
+    return s;
+}
+
+
+Statement *WhileStatement::semantic(Scope *sc)
+{
+#if 0
+    if (condition->op == TOKmatch)
+    {
+	/* Rewrite while (condition) body as:
+	 *   if (condition)
+	 *     do
+	 *       body
+	 *     while ((_match = _match.opNext), _match);
+	 */
+
+	Expression *ew = new IdentifierExp(0, Id::_match);
+	ew = new DotIdExp(0, ew, Id::next);
+	ew = new AssignExp(0, new IdentifierExp(0, Id::_match), ew);
+	////ew = new EqualExp(TOKnotequal, 0, ew, new NullExp(0));
+	Expression *ev = new IdentifierExp(0, Id::_match);
+	//ev = new CastExp(0, ev, Type::tvoidptr);
+	ew = new CommaExp(0, ew, ev);
+	Statement *sw = new DoStatement(loc, body, ew);
+	Statement *si = new IfStatement(loc, condition, sw, NULL);
+	return si->semantic(sc);
+    }
+#endif
+
+    condition = condition->semantic(sc);
+    condition = resolveProperties(sc, condition);
+    condition = condition->optimize(WANTvalue);
+    condition = condition->checkToBoolean();
+
+    sc->noctor++;
+
+    Scope *scd = sc->push();
+    scd->sbreak = this;
+    scd->scontinue = this;
+    if (body)
+	body = body->semantic(scd);
+    scd->pop();
+
+    sc->noctor--;
+
+    return this;
+}
+
+int WhileStatement::hasBreak()
+{
+    return TRUE;
+}
+
+int WhileStatement::hasContinue()
+{
+    return TRUE;
+}
+
+int WhileStatement::usesEH()
+{
+    return body ? body->usesEH() : 0;
+}
+
+int WhileStatement::fallOffEnd()
+{
+    if (body)
+	body->fallOffEnd();
+    return TRUE;
+}
+
+int WhileStatement::comeFrom()
+{
+    if (body)
+	return body->comeFrom();
+    return FALSE;
+}
+
+void WhileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("while (");
+    condition->toCBuffer(buf, hgs);
+    buf->writebyte(')');
+    buf->writenl();
+    if (body)
+	body->toCBuffer(buf, hgs);
+}
+
+/******************************** DoStatement ***************************/
+
+DoStatement::DoStatement(Loc loc, Statement *b, Expression *c)
+    : Statement(loc)
+{
+    body = b;
+    condition = c;
+}
+
+Statement *DoStatement::syntaxCopy()
+{
+    DoStatement *s = new DoStatement(loc, body ? body->syntaxCopy() : NULL, condition->syntaxCopy());
+    return s;
+}
+
+
+Statement *DoStatement::semantic(Scope *sc)
+{
+    sc->noctor++;
+    if (body)
+	body = body->semanticScope(sc, this, this);
+    sc->noctor--;
+    condition = condition->semantic(sc);
+    condition = resolveProperties(sc, condition);
+
+    condition = condition->checkToBoolean();
+
+    return this;
+}
+
+int DoStatement::hasBreak()
+{
+    return TRUE;
+}
+
+int DoStatement::hasContinue()
+{
+    return TRUE;
+}
+
+int DoStatement::usesEH()
+{
+    return body ? body->usesEH() : 0;
+}
+
+int DoStatement::fallOffEnd()
+{
+    if (body)
+	body->fallOffEnd();
+    return TRUE;
+}
+
+int DoStatement::comeFrom()
+{
+    if (body)
+	return body->comeFrom();
+    return FALSE;
+}
+
+void DoStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("do");
+    buf->writenl();
+    if (body)
+	body->toCBuffer(buf, hgs);
+    buf->writestring("while (");
+    condition->toCBuffer(buf, hgs);
+    buf->writebyte(')');
+}
+
+/******************************** ForStatement ***************************/
+
+ForStatement::ForStatement(Loc loc, Statement *init, Expression *condition, Expression *increment, Statement *body)
+    : Statement(loc)
+{
+    this->init = init;
+    this->condition = condition;
+    this->increment = increment;
+    this->body = body;
+}
+
+Statement *ForStatement::syntaxCopy()
+{
+    Statement *i = NULL;
+    if (init)
+	i = init->syntaxCopy();
+    Expression *c = NULL;
+    if (condition)
+	c = condition->syntaxCopy();
+    Expression *inc = NULL;
+    if (increment)
+	inc = increment->syntaxCopy();
+    ForStatement *s = new ForStatement(loc, i, c, inc, body->syntaxCopy());
+    return s;
+}
+
+Statement *ForStatement::semantic(Scope *sc)
+{
+    ScopeDsymbol *sym = new ScopeDsymbol();
+    sym->parent = sc->scopesym;
+    sc = sc->push(sym);
+    if (init)
+	init = init->semantic(sc);
+    if (!condition)
+	// Use a default value
+	condition = new IntegerExp(loc, 1, Type::tboolean);
+    sc->noctor++;
+    condition = condition->semantic(sc);
+    condition = resolveProperties(sc, condition);
+    condition = condition->checkToBoolean();
+    if (increment)
+	increment = increment->semantic(sc);
+
+    sc->sbreak = this;
+    sc->scontinue = this;
+    body = body->semantic(sc);
+    sc->noctor--;
+
+    sc->pop();
+    return this;
+}
+
+void ForStatement::scopeCode(Statement **sentry, Statement **sexception, Statement **sfinally)
+{
+    //printf("ForStatement::scopeCode()\n");
+    //print();
+    if (init)
+	init->scopeCode(sentry, sexception, sfinally);
+    else
+	Statement::scopeCode(sentry, sexception, sfinally);
+}
+
+int ForStatement::hasBreak()
+{
+    //printf("ForStatement::hasBreak()\n");
+    return TRUE;
+}
+
+int ForStatement::hasContinue()
+{
+    return TRUE;
+}
+
+int ForStatement::usesEH()
+{
+    return (init && init->usesEH()) || body->usesEH();
+}
+
+int ForStatement::fallOffEnd()
+{
+    if (body)
+	body->fallOffEnd();
+    return TRUE;
+}
+
+int ForStatement::comeFrom()
+{
+    //printf("ForStatement::comeFrom()\n");
+    if (body)
+    {	int result = body->comeFrom();
+	//printf("result = %d\n", result);
+	return result;
+    }
+    return FALSE;
+}
+
+void ForStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("for (");
+    if (init)
+    {
+        hgs->FLinit.init++;
+        hgs->FLinit.decl = 0;
+        init->toCBuffer(buf, hgs);
+        if (hgs->FLinit.decl > 0)
+            buf->writebyte(';');
+        hgs->FLinit.decl = 0;
+        hgs->FLinit.init--;
+    }
+    else
+        buf->writebyte(';');
+    if (condition)
+    {   buf->writebyte(' ');
+        condition->toCBuffer(buf, hgs);
+    }
+    buf->writebyte(';');
+    if (increment)
+    {   buf->writebyte(' ');
+        increment->toCBuffer(buf, hgs);
+    }
+    buf->writebyte(')');
+    buf->writenl();
+    buf->writebyte('{');
+    buf->writenl();
+    body->toCBuffer(buf, hgs);
+    buf->writebyte('}');
+    buf->writenl();
+}
+
+/******************************** ForeachStatement ***************************/
+
+ForeachStatement::ForeachStatement(Loc loc, enum TOK op, Arguments *arguments,
+	Expression *aggr, Statement *body)
+    : Statement(loc)
+{
+    this->op = op;
+    this->arguments = arguments;
+    this->aggr = aggr;
+    this->body = body;
+
+    this->key = NULL;
+    this->value = NULL;
+
+    this->func = NULL;
+}
+
+Statement *ForeachStatement::syntaxCopy()
+{
+    Arguments *args = Argument::arraySyntaxCopy(arguments);
+    Expression *exp = aggr->syntaxCopy();
+    ForeachStatement *s = new ForeachStatement(loc, op, args, exp, body->syntaxCopy());
+    return s;
+}
+
+Statement *ForeachStatement::semantic(Scope *sc)
+{
+    //printf("ForeachStatement::semantic() %p\n", this);
+    ScopeDsymbol *sym;
+    Statement *s = this;
+    int dim = arguments->dim;
+    int i;
+    TypeAArray *taa = NULL;
+
+    Type *tn = NULL;
+    Type *tnv = NULL;
+
+    func = sc->func;
+    if (func->fes)
+	func = func->fes->func;
+
+    aggr = aggr->semantic(sc);
+    aggr = resolveProperties(sc, aggr);
+    if (!aggr->type)
+    {
+	error("invalid foreach aggregate %s", aggr->toChars());
+	return this;
+    }
+
+    inferApplyArgTypes(op, arguments, aggr);
+
+    /* Check for inference errors
+     */
+    if (dim != arguments->dim)
+    {
+	//printf("dim = %d, arguments->dim = %d\n", dim, arguments->dim);
+	error("cannot uniquely infer foreach argument types");
+	return this;
+    }
+
+    Type *tab = aggr->type->toBasetype();
+
+    if (tab->ty == Ttuple)	// don't generate new scope for tuple loops
+    {
+	if (dim < 1 || dim > 2)
+	{
+	    error("only one (value) or two (key,value) arguments for tuple foreach");
+	    return s;
+	}
+
+	TypeTuple *tuple = (TypeTuple *)tab;
+	Statements *statements = new Statements();
+	//printf("aggr: op = %d, %s\n", aggr->op, aggr->toChars());
+	size_t n;
+	TupleExp *te = NULL;
+	if (aggr->op == TOKtuple)	// expression tuple
+	{   te = (TupleExp *)aggr;
+	    n = te->exps->dim;
+	}
+	else if (aggr->op == TOKtype)	// type tuple
+	{
+	    n = Argument::dim(tuple->arguments);
+	}
+	else
+	    assert(0);
+	for (size_t j = 0; j < n; j++)
+	{   size_t k = (op == TOKforeach) ? j : n - 1 - j;
+	    Expression *e;
+	    Type *t;
+	    if (te)
+		e = (Expression *)te->exps->data[k];
+	    else
+		t = Argument::getNth(tuple->arguments, k)->type;
+	    Argument *arg = (Argument *)arguments->data[0];
+	    Statements *st = new Statements();
+
+	    if (dim == 2)
+	    {   // Declare key
+		if (arg->storageClass & (STCout | STCref | STClazy))
+		    error("no storage class for key %s", arg->ident->toChars());
+		TY keyty = arg->type->ty;
+		if ((keyty != Tint32 && keyty != Tuns32) ||
+		    (global.params.is64bit &&
+			    keyty != Tint64 && keyty != Tuns64)
+		   )
+		{
+		    error("foreach: key type must be int or uint, not %s", arg->type->toChars());
+		}
+		Initializer *ie = new ExpInitializer(0, new IntegerExp(k));
+		VarDeclaration *var = new VarDeclaration(loc, arg->type, arg->ident, ie);
+		var->storage_class |= STCconst;
+		DeclarationExp *de = new DeclarationExp(loc, var);
+		st->push(new ExpStatement(loc, de));
+		arg = (Argument *)arguments->data[1];	// value
+	    }
+	    // Declare value
+	    if (arg->storageClass & (STCout | STCref | STClazy))
+		error("no storage class for value %s", arg->ident->toChars());
+	    Dsymbol *var;
+	    if (te)
+	    {
+		if (e->type->toBasetype()->ty == Tfunction &&
+		    e->op == TOKvar)
+		{   VarExp *ve = (VarExp *)e;
+		    var = new AliasDeclaration(loc, arg->ident, ve->var);
+		}
+		else
+		{
+		    arg->type = e->type;
+		    Initializer *ie = new ExpInitializer(0, e);
+		    VarDeclaration *v = new VarDeclaration(loc, arg->type, arg->ident, ie);
+		    if (e->isConst())
+			v->storage_class |= STCconst;
+#if V2
+		    else
+			v->storage_class |= STCfinal;
+#endif
+		    var = v;
+		}
+	    }
+	    else
+	    {
+		var = new AliasDeclaration(loc, arg->ident, t);
+	    }
+	    DeclarationExp *de = new DeclarationExp(loc, var);
+	    st->push(new ExpStatement(loc, de));
+
+	    st->push(body->syntaxCopy());
+	    s = new CompoundStatement(loc, st);
+	    s = new ScopeStatement(loc, s);
+	    statements->push(s);
+	}
+
+	s = new UnrolledLoopStatement(loc, statements);
+	s = s->semantic(sc);
+	return s;
+    }
+
+    for (i = 0; i < dim; i++)
+    {	Argument *arg = (Argument *)arguments->data[i];
+	if (!arg->type)
+	{
+	    error("cannot infer type for %s", arg->ident->toChars());
+	    return this;
+	}
+    }
+
+    sym = new ScopeDsymbol();
+    sym->parent = sc->scopesym;
+    sc = sc->push(sym);
+
+    sc->noctor++;
+
+    switch (tab->ty)
+    {
+	case Tarray:
+	case Tsarray:
+	    if (dim < 1 || dim > 2)
+	    {
+		error("only one or two arguments for array foreach");
+		break;
+	    }
+
+	    /* Look for special case of parsing char types out of char type
+	     * array.
+	     */
+	    tn = tab->next->toBasetype();
+	    if (tn->ty == Tchar || tn->ty == Twchar || tn->ty == Tdchar)
+	    {	Argument *arg;
+
+		i = (dim == 1) ? 0 : 1;	// index of value
+		arg = (Argument *)arguments->data[i];
+		arg->type = arg->type->semantic(loc, sc);
+		tnv = arg->type->toBasetype();
+		if (tnv->ty != tn->ty &&
+		    (tnv->ty == Tchar || tnv->ty == Twchar || tnv->ty == Tdchar))
+		{
+		    if (arg->storageClass & STCref)
+			error("foreach: value of UTF conversion cannot be ref");
+		    if (dim == 2)
+		    {	arg = (Argument *)arguments->data[0];
+			if (arg->storageClass & STCref)
+			    error("foreach: key cannot be ref");
+		    }
+		    goto Lapply;
+		}
+	    }
+
+	    for (i = 0; i < dim; i++)
+	    {	// Declare args
+		Argument *arg = (Argument *)arguments->data[i];
+		VarDeclaration *var;
+
+		var = new VarDeclaration(loc, arg->type, arg->ident, NULL);
+		var->storage_class |= STCforeach;
+		var->storage_class |= arg->storageClass & (STCin | STCout | STCref);
+#if 1
+		DeclarationExp *de = new DeclarationExp(loc, var);
+		de->semantic(sc);
+#else
+		var->semantic(sc);
+		if (!sc->insert(var))
+		    error("%s already defined", var->ident->toChars());
+#endif
+		if (dim == 2 && i == 0)
+		    key = var;
+		else
+		    value = var;
+	    }
+
+	    sc->sbreak = this;
+	    sc->scontinue = this;
+	    body = body->semantic(sc);
+
+	    if (!value->type->equals(tab->next))
+	    {
+		if (aggr->op == TOKstring)
+		    aggr = aggr->implicitCastTo(sc, value->type->arrayOf());
+		else
+		    error("foreach: %s is not an array of %s", tab->toChars(), value->type->toChars());
+	    }
+
+	    if (value->storage_class & STCout && value->type->toBasetype()->ty == Tbit)
+		error("foreach: value cannot be out and type bit");
+
+	    if (key &&
+		((key->type->ty != Tint32 && key->type->ty != Tuns32) ||
+		 (global.params.is64bit &&
+			key->type->ty != Tint64 && key->type->ty != Tuns64)
+	        )
+	       )
+	    {
+		error("foreach: key type must be int or uint, not %s", key->type->toChars());
+	    }
+
+	    if (key && key->storage_class & (STCout | STCref))
+		error("foreach: key cannot be out or ref");
+	    break;
+
+	case Taarray:
+	    taa = (TypeAArray *)tab;
+	    if (dim < 1 || dim > 2)
+	    {
+		error("only one or two arguments for associative array foreach");
+		break;
+	    }
+	    if (op == TOKforeach_reverse)
+	    {
+		error("no reverse iteration on associative arrays");
+	    }
+	    goto Lapply;
+
+	case Tclass:
+	case Tstruct:
+	case Tdelegate:
+	Lapply:
+	{   FuncDeclaration *fdapply;
+	    Arguments *args;
+	    Expression *ec;
+	    Expression *e;
+	    FuncLiteralDeclaration *fld;
+	    Argument *a;
+	    Type *t;
+	    Expression *flde;
+	    Identifier *id;
+	    Type *tret;
+
+	    tret = func->type->next;
+
+	    // Need a variable to hold value from any return statements in body.
+	    if (!sc->func->vresult && tret && tret != Type::tvoid)
+	    {	VarDeclaration *v;
+
+		v = new VarDeclaration(loc, tret, Id::result, NULL);
+		v->noauto = 1;
+		v->semantic(sc);
+		if (!sc->insert(v))
+		    assert(0);
+		v->parent = sc->func;
+		sc->func->vresult = v;
+	    }
+
+	    /* Turn body into the function literal:
+	     *	int delegate(ref T arg) { body }
+	     */
+	    args = new Arguments();
+	    for (i = 0; i < dim; i++)
+	    {	Argument *arg = (Argument *)arguments->data[i];
+
+		arg->type = arg->type->semantic(loc, sc);
+		if (arg->storageClass & STCref)
+		    id = arg->ident;
+		else
+		{   // Make a copy of the ref argument so it isn't
+		    // a reference.
+		    VarDeclaration *v;
+		    Initializer *ie;
+		    char applyArg[10 + sizeof(i)*3 + 1];
+
+		    sprintf(applyArg, "__applyArg%d", i);
+		    id = Lexer::idPool(applyArg);
+
+		    ie = new ExpInitializer(0, new IdentifierExp(0, id));
+		    v = new VarDeclaration(0, arg->type, arg->ident, ie);
+		    s = new DeclarationStatement(0, v);
+		    body = new CompoundStatement(loc, s, body);
+		}
+		a = new Argument(STCref, arg->type, id, NULL);
+		args->push(a);
+	    }
+	    t = new TypeFunction(args, Type::tint32, 0, LINKd);
+	    fld = new FuncLiteralDeclaration(loc, 0, t, TOKdelegate, this);
+	    fld->fbody = body;
+	    flde = new FuncExp(loc, fld);
+	    flde = flde->semantic(sc);
+
+	    // Resolve any forward referenced goto's
+	    for (int i = 0; i < gotos.dim; i++)
+	    {	CompoundStatement *cs = (CompoundStatement *)gotos.data[i];
+		GotoStatement *gs = (GotoStatement *)cs->statements->data[0];
+
+		if (!gs->label->statement)
+		{   // 'Promote' it to this scope, and replace with a return
+		    cases.push(gs);
+		    s = new ReturnStatement(0, new IntegerExp(cases.dim + 1));
+		    cs->statements->data[0] = (void *)s;
+		}
+	    }
+
+	    if (tab->ty == Taarray)
+	    {
+		// Check types
+		Argument *arg = (Argument *)arguments->data[0];
+		if (dim == 2)
+		{
+		    if (arg->storageClass & STCref)
+			error("foreach: index cannot be ref");
+		    if (!arg->type->equals(taa->index))
+			error("foreach: index must be type %s, not %s", taa->index->toChars(), arg->type->toChars());
+		    arg = (Argument *)arguments->data[1];
+		}
+		if (!arg->type->equals(taa->next))
+		    error("foreach: value must be type %s, not %s", taa->next->toChars(), arg->type->toChars());
+
+		/* Call:
+		 *	_aaApply(aggr, keysize, flde)
+		 */
+		if (dim == 2)
+		    fdapply = FuncDeclaration::genCfunc(Type::tindex, "_aaApply2");
+		else
+		    fdapply = FuncDeclaration::genCfunc(Type::tindex, "_aaApply");
+		ec = new VarExp(0, fdapply);
+		Expressions *exps = new Expressions();
+		exps->push(aggr);
+		size_t keysize = taa->key->size();
+		keysize = (keysize + 3) & ~3;
+		exps->push(new IntegerExp(0, keysize, Type::tint32));
+		exps->push(flde);
+		e = new CallExp(loc, ec, exps);
+		e->type = Type::tindex;	// don't run semantic() on e
+	    }
+	    else if (tab->ty == Tarray || tab->ty == Tsarray)
+	    {
+		/* Call:
+		 *	_aApply(aggr, flde)
+		 */
+		static char fntab[9][3] =
+		{ "cc","cw","cd",
+		  "wc","cc","wd",
+		  "dc","dw","dd"
+		};
+		char fdname[7+1+2+ sizeof(dim)*3 + 1];
+		int flag;
+
+		switch (tn->ty)
+		{
+		    case Tchar:		flag = 0; break;
+		    case Twchar:	flag = 3; break;
+		    case Tdchar:	flag = 6; break;
+		    default:		assert(0);
+		}
+		switch (tnv->ty)
+		{
+		    case Tchar:		flag += 0; break;
+		    case Twchar:	flag += 1; break;
+		    case Tdchar:	flag += 2; break;
+		    default:		assert(0);
+		}
+		const char *r = (op == TOKforeach_reverse) ? "R" : "";
+		int j = sprintf(fdname, "_aApply%s%.*s%d", r, 2, fntab[flag], dim);
+		assert(j < sizeof(fdname));
+		fdapply = FuncDeclaration::genCfunc(Type::tindex, fdname);
+
+		ec = new VarExp(0, fdapply);
+		Expressions *exps = new Expressions();
+		if (tab->ty == Tsarray)
+		   aggr = aggr->castTo(sc, tn->arrayOf());
+		exps->push(aggr);
+		exps->push(flde);
+		e = new CallExp(loc, ec, exps);
+		e->type = Type::tindex;	// don't run semantic() on e
+	    }
+	    else if (tab->ty == Tdelegate)
+	    {
+		/* Call:
+		 *	aggr(flde)
+		 */
+		Expressions *exps = new Expressions();
+		exps->push(flde);
+		e = new CallExp(loc, aggr, exps);
+		e = e->semantic(sc);
+		if (e->type != Type::tint32)
+		    error("opApply() function for %s must return an int", tab->toChars());
+	    }
+	    else
+	    {
+		/* Call:
+		 *	aggr.apply(flde)
+		 */
+		ec = new DotIdExp(loc, aggr,
+			(op == TOKforeach_reverse) ? Id::applyReverse
+						   : Id::apply);
+		Expressions *exps = new Expressions();
+		exps->push(flde);
+		e = new CallExp(loc, ec, exps);
+		e = e->semantic(sc);
+		if (e->type != Type::tint32)
+		    error("opApply() function for %s must return an int", tab->toChars());
+	    }
+
+	    if (!cases.dim)
+		// Easy case, a clean exit from the loop
+		s = new ExpStatement(loc, e);
+	    else
+	    {	// Construct a switch statement around the return value
+		// of the apply function.
+		Statements *a = new Statements();
+
+		// default: break; takes care of cases 0 and 1
+		s = new BreakStatement(0, NULL);
+		s = new DefaultStatement(0, s);
+		a->push(s);
+
+		// cases 2...
+		for (int i = 0; i < cases.dim; i++)
+		{
+		    s = (Statement *)cases.data[i];
+		    s = new CaseStatement(0, new IntegerExp(i + 2), s);
+		    a->push(s);
+		}
+
+		s = new CompoundStatement(loc, a);
+		s = new SwitchStatement(loc, e, s);
+		s = s->semantic(sc);
+	    }
+	    break;
+	}
+
+	default:
+	    error("foreach: %s is not an aggregate type", aggr->type->toChars());
+	    break;
+    }
+    sc->noctor--;
+    sc->pop();
+    return s;
+}
+
+int ForeachStatement::hasBreak()
+{
+    return TRUE;
+}
+
+int ForeachStatement::hasContinue()
+{
+    return TRUE;
+}
+
+int ForeachStatement::usesEH()
+{
+    return body->usesEH();
+}
+
+int ForeachStatement::fallOffEnd()
+{
+    if (body)
+	body->fallOffEnd();
+    return TRUE;
+}
+
+int ForeachStatement::comeFrom()
+{
+    if (body)
+	return body->comeFrom();
+    return FALSE;
+}
+
+void ForeachStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring(Token::toChars(op));
+    buf->writestring(" (");
+    int i;
+    for (int i = 0; i < arguments->dim; i++)
+    {
+	Argument *a = (Argument *)arguments->data[i];
+	if (i)
+	    buf->writestring(", ");
+	if (a->storageClass & STCref)
+	    buf->writestring((global.params.Dversion == 1)
+		? (char*)"inout " : (char*)"ref ");
+	if (a->type)
+	    a->type->toCBuffer(buf, a->ident, hgs);
+	else
+	    buf->writestring(a->ident->toChars());
+    }
+    buf->writestring("; ");
+    aggr->toCBuffer(buf, hgs);
+    buf->writebyte(')');
+    buf->writenl();
+    buf->writebyte('{');
+    buf->writenl();
+    if (body)
+	body->toCBuffer(buf, hgs);
+    buf->writebyte('}');
+    buf->writenl();
+}
+
+/******************************** IfStatement ***************************/
+
+IfStatement::IfStatement(Loc loc, Argument *arg, Expression *condition, Statement *ifbody, Statement *elsebody)
+    : Statement(loc)
+{
+    this->arg = arg;
+    this->condition = condition;
+    this->ifbody = ifbody;
+    this->elsebody = elsebody;
+    this->match = NULL;
+}
+
+Statement *IfStatement::syntaxCopy()
+{
+    Statement *i = NULL;
+    if (ifbody)
+        i = ifbody->syntaxCopy();
+
+    Statement *e = NULL;
+    if (elsebody)
+	e = elsebody->syntaxCopy();
+
+    Argument *a = arg ? arg->syntaxCopy() : NULL;
+    IfStatement *s = new IfStatement(loc, a, condition->syntaxCopy(), i, e);
+    return s;
+}
+
+Statement *IfStatement::semantic(Scope *sc)
+{
+    condition = condition->semantic(sc);
+    condition = resolveProperties(sc, condition);
+    condition = condition->checkToBoolean();
+
+    // If we can short-circuit evaluate the if statement, don't do the
+    // semantic analysis of the skipped code.
+    // This feature allows a limited form of conditional compilation.
+    condition = condition->optimize(WANTflags);
+
+    // Evaluate at runtime
+    unsigned cs0 = sc->callSuper;
+    unsigned cs1;
+
+    Scope *scd;
+    if (arg)
+    {	/* Declare arg, which we will set to be the
+	 * result of condition.
+	 */
+	ScopeDsymbol *sym = new ScopeDsymbol();
+	sym->parent = sc->scopesym;
+	scd = sc->push(sym);
+
+	Type *t = arg->type ? arg->type : condition->type;
+	match = new VarDeclaration(loc, t, arg->ident, NULL);
+	match->noauto = 1;
+	match->semantic(scd);
+	if (!scd->insert(match))
+	    assert(0);
+	match->parent = sc->func;
+
+	/* Generate:
+	 *  (arg = condition)
+	 */
+	VarExp *v = new VarExp(0, match);
+	condition = new AssignExp(loc, v, condition);
+	condition = condition->semantic(scd);
+    }
+    else
+	scd = sc->push();
+    ifbody = ifbody->semantic(scd);
+    scd->pop();
+
+    cs1 = sc->callSuper;
+    sc->callSuper = cs0;
+    if (elsebody)
+	elsebody = elsebody->semanticScope(sc, NULL, NULL);
+    sc->mergeCallSuper(loc, cs1);
+
+    return this;
+}
+
+int IfStatement::usesEH()
+{
+    return (ifbody && ifbody->usesEH()) || (elsebody && elsebody->usesEH());
+}
+
+int IfStatement::fallOffEnd()
+{
+    if (!ifbody || ifbody->fallOffEnd() ||
+	!elsebody || elsebody->fallOffEnd())
+	return TRUE;
+    return FALSE;
+}
+
+
+void IfStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("if (");
+    if (arg)
+    {
+	if (arg->type)
+	    arg->type->toCBuffer(buf, arg->ident, hgs);
+	else
+	    buf->writestring(arg->ident->toChars());
+	buf->writebyte(';');
+    }
+    condition->toCBuffer(buf, hgs);
+    buf->writebyte(')');
+    buf->writenl();
+    ifbody->toCBuffer(buf, hgs);
+    if (elsebody)
+    {   buf->writestring("else");
+        buf->writenl();
+        elsebody->toCBuffer(buf, hgs);
+    }
+}
+
+/******************************** ConditionalStatement ***************************/
+
+ConditionalStatement::ConditionalStatement(Loc loc, Condition *condition, Statement *ifbody, Statement *elsebody)
+    : Statement(loc)
+{
+    this->condition = condition;
+    this->ifbody = ifbody;
+    this->elsebody = elsebody;
+}
+
+Statement *ConditionalStatement::syntaxCopy()
+{
+    Statement *e = NULL;
+    if (elsebody)
+	e = elsebody->syntaxCopy();
+    ConditionalStatement *s = new ConditionalStatement(loc,
+		condition->syntaxCopy(), ifbody->syntaxCopy(), e);
+    return s;
+}
+
+Statement *ConditionalStatement::semantic(Scope *sc)
+{
+    //printf("ConditionalStatement::semantic()\n");
+
+    // If we can short-circuit evaluate the if statement, don't do the
+    // semantic analysis of the skipped code.
+    // This feature allows a limited form of conditional compilation.
+    if (condition->include(sc, NULL))
+    {
+	ifbody = ifbody->semantic(sc);
+	return ifbody;
+    }
+    else
+    {
+	if (elsebody)
+	    elsebody = elsebody->semantic(sc);
+	return elsebody;
+    }
+}
+
+Statements *ConditionalStatement::flatten(Scope *sc)
+{
+    Statement *s;
+
+    if (condition->include(sc, NULL))
+	s = ifbody;
+    else
+	s = elsebody;
+
+    Statements *a = new Statements();
+    a->push(s);
+    return a;
+}
+
+int ConditionalStatement::usesEH()
+{
+    return (ifbody && ifbody->usesEH()) || (elsebody && elsebody->usesEH());
+}
+
+void ConditionalStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    condition->toCBuffer(buf, hgs);
+    buf->writenl();
+    if (ifbody)
+	ifbody->toCBuffer(buf, hgs);
+    if (elsebody)
+    {
+	buf->writestring("else");
+	buf->writenl();
+	elsebody->toCBuffer(buf, hgs);
+    }
+    buf->writenl();
+}
+
+
+/******************************** PragmaStatement ***************************/
+
+PragmaStatement::PragmaStatement(Loc loc, Identifier *ident, Expressions *args, Statement *body)
+    : Statement(loc)
+{
+    this->ident = ident;
+    this->args = args;
+    this->body = body;
+}
+
+Statement *PragmaStatement::syntaxCopy()
+{
+    Statement *b = NULL;
+    if (body)
+	b = body->syntaxCopy();
+    PragmaStatement *s = new PragmaStatement(loc,
+		ident, Expression::arraySyntaxCopy(args), b);
+    return s;
+}
+
+Statement *PragmaStatement::semantic(Scope *sc)
+{   // Should be merged with PragmaDeclaration
+    //printf("PragmaStatement::semantic() %s\n", toChars());
+    //printf("body = %p\n", body);
+    if (ident == Id::msg)
+    {
+        if (args)
+        {
+            for (size_t i = 0; i < args->dim; i++)
+            {
+                Expression *e = (Expression *)args->data[i];
+
+                e = e->semantic(sc);
+		e = e->optimize(WANTvalue | WANTinterpret);
+                if (e->op == TOKstring)
+                {
+                    StringExp *se = (StringExp *)e;
+                    fprintf(stdmsg, "%.*s", (int)se->len, se->string);
+                }
+                else
+		    error("string expected for message, not '%s'", e->toChars());
+            }
+            fprintf(stdmsg, "\n");
+        }
+    }
+    else if (ident == Id::lib)
+    {
+	if (!args || args->dim != 1)
+	    error("string expected for library name");
+	else
+	{
+	    Expression *e = (Expression *)args->data[0];
+
+	    e = e->semantic(sc);
+	    e = e->optimize(WANTvalue | WANTinterpret);
+	    args->data[0] = (void *)e;
+	    if (e->op != TOKstring)
+		error("string expected for library name, not '%s'", e->toChars());
+	    else if (global.params.verbose)
+	    {
+		StringExp *se = (StringExp *)e;
+		char *name = (char *)mem.malloc(se->len + 1);
+		memcpy(name, se->string, se->len);
+		name[se->len] = 0;
+		printf("library   %s\n", name);
+		mem.free(name);
+	    }
+	}
+    }
+    else
+        error("unrecognized pragma(%s)", ident->toChars());
+
+    if (body)
+    {
+	body = body->semantic(sc);
+    }
+    return body;
+}
+
+int PragmaStatement::usesEH()
+{
+    return body && body->usesEH();
+}
+
+int PragmaStatement::fallOffEnd()
+{
+    if (body)
+	return body->fallOffEnd();
+    return TRUE;
+}
+
+void PragmaStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("pragma (");
+    buf->writestring(ident->toChars());
+    if (args && args->dim)
+    {
+	buf->writestring(", ");
+	argsToCBuffer(buf, args, hgs);
+    }
+    buf->writeByte(')');
+    if (body)
+    {
+	buf->writenl();
+	buf->writeByte('{');
+	buf->writenl();
+
+	body->toCBuffer(buf, hgs);
+
+	buf->writeByte('}');
+	buf->writenl();
+    }
+    else
+    {
+	buf->writeByte(';');
+	buf->writenl();
+    }
+}
+
+
+/******************************** StaticAssertStatement ***************************/
+
+StaticAssertStatement::StaticAssertStatement(StaticAssert *sa)
+    : Statement(sa->loc)
+{
+    this->sa = sa;
+}
+
+Statement *StaticAssertStatement::syntaxCopy()
+{
+    StaticAssertStatement *s = new StaticAssertStatement((StaticAssert *)sa->syntaxCopy(NULL));
+    return s;
+}
+
+Statement *StaticAssertStatement::semantic(Scope *sc)
+{
+    sa->semantic2(sc);
+    return NULL;
+}
+
+void StaticAssertStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    sa->toCBuffer(buf, hgs);
+}
+
+
+/******************************** SwitchStatement ***************************/
+
+SwitchStatement::SwitchStatement(Loc loc, Expression *c, Statement *b)
+    : Statement(loc)
+{
+    condition = c;
+    body = b;
+    sdefault = NULL;
+    cases = NULL;
+    hasNoDefault = 0;
+}
+
+Statement *SwitchStatement::syntaxCopy()
+{
+    SwitchStatement *s = new SwitchStatement(loc,
+	condition->syntaxCopy(), body->syntaxCopy());
+    return s;
+}
+
+Statement *SwitchStatement::semantic(Scope *sc)
+{
+    //printf("SwitchStatement::semantic(%p)\n", this);
+    assert(!cases);		// ensure semantic() is only run once
+    condition = condition->semantic(sc);
+    condition = resolveProperties(sc, condition);
+    if (condition->type->isString())
+    {
+	// If it's not an array, cast it to one
+	if (condition->type->ty != Tarray)
+	{
+	    condition = condition->implicitCastTo(sc, condition->type->next->arrayOf());
+	}
+    }
+    else
+    {	condition = condition->integralPromotions(sc);
+	condition->checkIntegral();
+    }
+
+    sc = sc->push();
+    sc->sbreak = this;
+    sc->sw = this;
+
+    cases = new Array();
+    sc->noctor++;	// BUG: should use Scope::mergeCallSuper() for each case instead
+    body = body->semantic(sc);
+    sc->noctor--;
+
+    // Resolve any goto case's with exp
+    for (int i = 0; i < gotoCases.dim; i++)
+    {
+	GotoCaseStatement *gcs = (GotoCaseStatement *)gotoCases.data[i];
+
+	if (!gcs->exp)
+	{
+	    gcs->error("no case statement following goto case;");
+	    break;
+	}
+
+	for (Scope *scx = sc; scx; scx = scx->enclosing)
+	{
+	    if (!scx->sw)
+		continue;
+	    for (int j = 0; j < scx->sw->cases->dim; j++)
+	    {
+		CaseStatement *cs = (CaseStatement *)scx->sw->cases->data[j];
+
+		if (cs->exp->equals(gcs->exp))
+		{
+		    gcs->cs = cs;
+		    goto Lfoundcase;
+		}
+	    }
+	}
+	gcs->error("case %s not found", gcs->exp->toChars());
+
+     Lfoundcase:
+	;
+    }
+
+    if (!sc->sw->sdefault)
+    {	hasNoDefault = 1;
+
+	if (global.params.warnings)
+	{   fprintf(stdmsg, "warning - ");
+	    error("switch statement has no default");
+	}
+
+	// Generate runtime error if the default is hit
+	Statements *a = new Statements();
+	CompoundStatement *cs;
+	Statement *s;
+
+	if (global.params.useSwitchError)
+	    s = new SwitchErrorStatement(loc);
+	else
+	{   Expression *e = new HaltExp(loc);
+	    s = new ExpStatement(loc, e);
+	}
+
+	a->reserve(4);
+	a->push(body);
+	a->push(new BreakStatement(loc, NULL));
+	sc->sw->sdefault = new DefaultStatement(loc, s);
+	a->push(sc->sw->sdefault);
+	cs = new CompoundStatement(loc, a);
+	body = cs;
+    }
+
+    sc->pop();
+    return this;
+}
+
+int SwitchStatement::hasBreak()
+{
+    return TRUE;
+}
+
+int SwitchStatement::usesEH()
+{
+    return body ? body->usesEH() : 0;
+}
+
+int SwitchStatement::fallOffEnd()
+{
+    if (body)
+	body->fallOffEnd();
+    return TRUE;	// need to do this better
+}
+
+void SwitchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("switch (");
+    condition->toCBuffer(buf, hgs);
+    buf->writebyte(')');
+    buf->writenl();
+    if (body)
+    {
+	if (!body->isScopeStatement())
+        {   buf->writebyte('{');
+            buf->writenl();
+            body->toCBuffer(buf, hgs);
+            buf->writebyte('}');
+            buf->writenl();
+        }
+        else
+        {
+            body->toCBuffer(buf, hgs);
+        }
+    }
+}
+
+/******************************** CaseStatement ***************************/
+
+CaseStatement::CaseStatement(Loc loc, Expression *exp, Statement *s)
+    : Statement(loc)
+{
+    this->exp = exp;
+    this->statement = s;
+    cblock = NULL;
+}
+
+Statement *CaseStatement::syntaxCopy()
+{
+    CaseStatement *s = new CaseStatement(loc, exp->syntaxCopy(), statement->syntaxCopy());
+    return s;
+}
+
+Statement *CaseStatement::semantic(Scope *sc)
+{   SwitchStatement *sw = sc->sw;
+
+    exp = exp->semantic(sc);
+    if (sw)
+    {	int i;
+
+	exp = exp->implicitCastTo(sc, sw->condition->type);
+	exp = exp->optimize(WANTvalue | WANTinterpret);
+	if (exp->op != TOKstring && exp->op != TOKint64)
+	{
+	    error("case must be a string or an integral constant, not %s", exp->toChars());
+	    exp = new IntegerExp(0);
+	}
+
+	for (i = 0; i < sw->cases->dim; i++)
+	{
+	    CaseStatement *cs = (CaseStatement *)sw->cases->data[i];
+
+	    //printf("comparing '%s' with '%s'\n", exp->toChars(), cs->exp->toChars());
+	    if (cs->exp->equals(exp))
+	    {	error("duplicate case %s in switch statement", exp->toChars());
+		break;
+	    }
+	}
+
+	sw->cases->push(this);
+
+	// Resolve any goto case's with no exp to this case statement
+	for (i = 0; i < sw->gotoCases.dim; i++)
+	{
+	    GotoCaseStatement *gcs = (GotoCaseStatement *)sw->gotoCases.data[i];
+
+	    if (!gcs->exp)
+	    {
+		gcs->cs = this;
+		sw->gotoCases.remove(i);	// remove from array
+	    }
+	}
+    }
+    else
+	error("case not in switch statement");
+    statement = statement->semantic(sc);
+    return this;
+}
+
+int CaseStatement::compare(Object *obj)
+{
+    // Sort cases so we can do an efficient lookup
+    CaseStatement *cs2 = (CaseStatement *)(obj);
+
+    return exp->compare(cs2->exp);
+}
+
+int CaseStatement::usesEH()
+{
+    return statement->usesEH();
+}
+
+int CaseStatement::fallOffEnd()
+{
+    return statement->fallOffEnd();
+}
+
+int CaseStatement::comeFrom()
+{
+    return TRUE;
+}
+
+void CaseStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("case ");
+    exp->toCBuffer(buf, hgs);
+    buf->writebyte(':');
+    buf->writenl();
+    statement->toCBuffer(buf, hgs);
+}
+
+/******************************** DefaultStatement ***************************/
+
+DefaultStatement::DefaultStatement(Loc loc, Statement *s)
+    : Statement(loc)
+{
+    this->statement = s;
+#if IN_GCC
++    cblock = NULL;
+#endif
+}
+
+Statement *DefaultStatement::syntaxCopy()
+{
+    DefaultStatement *s = new DefaultStatement(loc, statement->syntaxCopy());
+    return s;
+}
+
+Statement *DefaultStatement::semantic(Scope *sc)
+{
+    if (sc->sw)
+    {
+	if (sc->sw->sdefault)
+	{
+	    error("switch statement already has a default");
+	}
+	sc->sw->sdefault = this;
+    }
+    else
+	error("default not in switch statement");
+    statement = statement->semantic(sc);
+    return this;
+}
+
+int DefaultStatement::usesEH()
+{
+    return statement->usesEH();
+}
+
+int DefaultStatement::fallOffEnd()
+{
+    return statement->fallOffEnd();
+}
+
+int DefaultStatement::comeFrom()
+{
+    return TRUE;
+}
+
+void DefaultStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("default:\n");
+    statement->toCBuffer(buf, hgs);
+}
+
+/******************************** GotoDefaultStatement ***************************/
+
+GotoDefaultStatement::GotoDefaultStatement(Loc loc)
+    : Statement(loc)
+{
+    sw = NULL;
+}
+
+Statement *GotoDefaultStatement::syntaxCopy()
+{
+    GotoDefaultStatement *s = new GotoDefaultStatement(loc);
+    return s;
+}
+
+Statement *GotoDefaultStatement::semantic(Scope *sc)
+{
+    sw = sc->sw;
+    if (!sw)
+	error("goto default not in switch statement");
+    return this;
+}
+
+int GotoDefaultStatement::fallOffEnd()
+{
+    return FALSE;
+}
+
+void GotoDefaultStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("goto default;\n");
+}
+
+/******************************** GotoCaseStatement ***************************/
+
+GotoCaseStatement::GotoCaseStatement(Loc loc, Expression *exp)
+    : Statement(loc)
+{
+    cs = NULL;
+    this->exp = exp;
+}
+
+Statement *GotoCaseStatement::syntaxCopy()
+{
+    Expression *e = exp ? exp->syntaxCopy() : NULL;
+    GotoCaseStatement *s = new GotoCaseStatement(loc, e);
+    return s;
+}
+
+Statement *GotoCaseStatement::semantic(Scope *sc)
+{
+    if (exp)
+	exp = exp->semantic(sc);
+
+    if (!sc->sw)
+	error("goto case not in switch statement");
+    else
+    {
+	sc->sw->gotoCases.push(this);
+	if (exp)
+	{
+	    exp = exp->implicitCastTo(sc, sc->sw->condition->type);
+	    exp = exp->optimize(WANTvalue);
+	}
+    }
+    return this;
+}
+
+int GotoCaseStatement::fallOffEnd()
+{
+    return FALSE;
+}
+
+void GotoCaseStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("goto case");
+    if (exp)
+    {   buf->writebyte(' ');
+        exp->toCBuffer(buf, hgs);
+    }
+    buf->writebyte(';');
+    buf->writenl();
+}
+
+/******************************** SwitchErrorStatement ***************************/
+
+SwitchErrorStatement::SwitchErrorStatement(Loc loc)
+    : Statement(loc)
+{
+}
+
+int SwitchErrorStatement::fallOffEnd()
+{
+    return FALSE;
+}
+
+void SwitchErrorStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("SwitchErrorStatement::toCBuffer()");
+    buf->writenl();
+}
+
+/******************************** ReturnStatement ***************************/
+
+ReturnStatement::ReturnStatement(Loc loc, Expression *exp)
+    : Statement(loc)
+{
+    this->exp = exp;
+}
+
+Statement *ReturnStatement::syntaxCopy()
+{
+    Expression *e = NULL;
+    if (exp)
+	e = exp->syntaxCopy();
+    ReturnStatement *s = new ReturnStatement(loc, e);
+    return s;
+}
+
+Statement *ReturnStatement::semantic(Scope *sc)
+{
+    //printf("ReturnStatement::semantic() %s\n", toChars());
+
+    FuncDeclaration *fd = sc->parent->isFuncDeclaration();
+    Scope *scx = sc;
+    int implicit0 = 0;
+
+    if (sc->fes)
+    {
+	// Find scope of function foreach is in
+	for (; 1; scx = scx->enclosing)
+	{
+	    assert(scx);
+	    if (scx->func != fd)
+	    {	fd = scx->func;		// fd is now function enclosing foreach
+		break;
+	    }
+	}
+    }
+
+    Type *tret = fd->type->next;
+    if (fd->tintro)
+	tret = fd->tintro->next;
+    Type *tbret = NULL;
+
+    if (tret)
+	tbret = tret->toBasetype();
+
+    // main() returns 0, even if it returns void
+    if (!exp && (!tbret || tbret->ty == Tvoid) && fd->isMain())
+    {	implicit0 = 1;
+	exp = new IntegerExp(0);
+    }
+
+    if (sc->incontract || scx->incontract)
+	error("return statements cannot be in contracts");
+    if (sc->tf || scx->tf)
+	error("return statements cannot be in finally, scope(exit) or scope(success) bodies");
+
+    if (fd->isCtorDeclaration())
+    {
+	// Constructors implicitly do:
+	//	return this;
+	if (exp && exp->op != TOKthis)
+	    error("cannot return expression from constructor");
+	exp = new ThisExp(0);
+    }
+
+    if (!exp)
+	fd->nrvo_can = 0;
+
+    if (exp)
+    {
+	fd->hasReturnExp |= 1;
+
+	exp = exp->semantic(sc);
+	exp = resolveProperties(sc, exp);
+	exp = exp->optimize(WANTvalue);
+
+	if (fd->nrvo_can && exp->op == TOKvar)
+	{   VarExp *ve = (VarExp *)exp;
+	    VarDeclaration *v = ve->var->isVarDeclaration();
+
+	    if (!v || v->isOut() || v->isRef())
+		fd->nrvo_can = 0;
+	    else if (fd->nrvo_var == NULL)
+	    {	if (!v->isDataseg() && !v->isParameter() && v->toParent2() == fd)
+		    fd->nrvo_var = v;
+		else
+		    fd->nrvo_can = 0;
+	    }
+	    else if (fd->nrvo_var != v)
+		fd->nrvo_can = 0;
+	}
+	else
+	    fd->nrvo_can = 0;
+
+	if (fd->returnLabel && tbret->ty != Tvoid)
+	{
+	}
+	else if (fd->inferRetType)
+	{
+	    if (fd->type->next)
+	    {
+		if (!exp->type->equals(fd->type->next))
+		    error("mismatched function return type inference of %s and %s",
+			exp->type->toChars(), fd->type->next->toChars());
+	    }
+	    else
+	    {
+		fd->type->next = exp->type;
+		fd->type = fd->type->semantic(loc, sc);
+		if (!fd->tintro)
+		{   tret = fd->type->next;
+		    tbret = tret->toBasetype();
+		}
+	    }
+	}
+	else if (tbret->ty != Tvoid)
+	{
+	    exp = exp->implicitCastTo(sc, tret);
+	}
+    }
+    else if (fd->inferRetType)
+    {
+	if (fd->type->next)
+	{
+	    if (fd->type->next->ty != Tvoid)
+		error("mismatched function return type inference of void and %s",
+		    fd->type->next->toChars());
+	}
+	else
+	{
+	    fd->type->next = Type::tvoid;
+	    fd->type = fd->type->semantic(loc, sc);
+	    if (!fd->tintro)
+	    {   tret = Type::tvoid;
+		tbret = tret;
+	    }
+	}
+    }
+    else if (tbret->ty != Tvoid)	// if non-void return
+	error("return expression expected");
+
+    if (sc->fes)
+    {
+	Statement *s;
+
+	if (exp && !implicit0)
+	{
+	    exp = exp->implicitCastTo(sc, tret);
+	}
+	if (!exp || exp->op == TOKint64 || exp->op == TOKfloat64 ||
+	    exp->op == TOKimaginary80 || exp->op == TOKcomplex80 ||
+	    exp->op == TOKthis || exp->op == TOKsuper || exp->op == TOKnull ||
+	    exp->op == TOKstring)
+	{
+	    sc->fes->cases.push(this);
+	    s = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
+	}
+	else if (fd->type->next->toBasetype() == Type::tvoid)
+	{
+	    Statement *s1;
+	    Statement *s2;
+
+	    s = new ReturnStatement(0, NULL);
+	    sc->fes->cases.push(s);
+
+	    // Construct: { exp; return cases.dim + 1; }
+	    s1 = new ExpStatement(loc, exp);
+	    s2 = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
+	    s = new CompoundStatement(loc, s1, s2);
+	}
+	else
+	{
+	    VarExp *v;
+	    Statement *s1;
+	    Statement *s2;
+
+	    // Construct: return vresult;
+	    if (!fd->vresult)
+	    {	VarDeclaration *v;
+
+		v = new VarDeclaration(loc, tret, Id::result, NULL);
+		v->noauto = 1;
+		v->semantic(scx);
+		if (!scx->insert(v))
+		    assert(0);
+		v->parent = fd;
+		fd->vresult = v;
+	    }
+
+	    v = new VarExp(0, fd->vresult);
+	    s = new ReturnStatement(0, v);
+	    sc->fes->cases.push(s);
+
+	    // Construct: { vresult = exp; return cases.dim + 1; }
+	    v = new VarExp(0, fd->vresult);
+	    exp = new AssignExp(loc, v, exp);
+	    exp = exp->semantic(sc);
+	    s1 = new ExpStatement(loc, exp);
+	    s2 = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
+	    s = new CompoundStatement(loc, s1, s2);
+	}
+	return s;
+    }
+
+    if (exp)
+    {
+	if (fd->returnLabel && tbret->ty != Tvoid)
+	{
+	    assert(fd->vresult);
+	    VarExp *v = new VarExp(0, fd->vresult);
+
+	    exp = new AssignExp(loc, v, exp);
+	    exp = exp->semantic(sc);
+	}
+	//exp->dump(0);
+	//exp->print();
+	exp->checkEscape();
+    }
+
+    /* BUG: need to issue an error on:
+     *	this
+     *	{   if (x) return;
+     *	    super();
+     *	}
+     */
+
+    if (sc->callSuper & CSXany_ctor &&
+	!(sc->callSuper & (CSXthis_ctor | CSXsuper_ctor)))
+	error("return without calling constructor");
+
+    sc->callSuper |= CSXreturn;
+
+    // See if all returns are instead to be replaced with a goto returnLabel;
+    if (fd->returnLabel)
+    {
+	GotoStatement *gs = new GotoStatement(loc, Id::returnLabel);
+
+	gs->label = fd->returnLabel;
+	if (exp)
+	{   Statement *s;
+
+	    s = new ExpStatement(0, exp);
+	    return new CompoundStatement(loc, s, gs);
+	}
+	return gs;
+    }
+
+    if (exp && tbret->ty == Tvoid && !fd->isMain())
+    {   Statement *s;
+
+	s = new ExpStatement(loc, exp);
+	loc = 0;
+	exp = NULL;
+	return new CompoundStatement(loc, s, this);
+    }
+
+    return this;
+}
+
+int ReturnStatement::fallOffEnd()
+{
+    return FALSE;
+}
+
+void ReturnStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->printf("return ");
+    if (exp)
+	exp->toCBuffer(buf, hgs);
+    buf->writeByte(';');
+    buf->writenl();
+}
+
+/******************************** BreakStatement ***************************/
+
+BreakStatement::BreakStatement(Loc loc, Identifier *ident)
+    : Statement(loc)
+{
+    this->ident = ident;
+}
+
+Statement *BreakStatement::syntaxCopy()
+{
+    BreakStatement *s = new BreakStatement(loc, ident);
+    return s;
+}
+
+Statement *BreakStatement::semantic(Scope *sc)
+{
+    // If:
+    //	break Identifier;
+    if (ident)
+    {
+	Scope *scx;
+	FuncDeclaration *thisfunc = sc->func;
+
+	for (scx = sc; scx; scx = scx->enclosing)
+	{
+	    LabelStatement *ls;
+
+	    if (scx->func != thisfunc)	// if in enclosing function
+	    {
+		if (sc->fes)		// if this is the body of a foreach
+		{
+		    /* Post this statement to the fes, and replace
+		     * it with a return value that caller will put into
+		     * a switch. Caller will figure out where the break
+		     * label actually is.
+		     * Case numbers start with 2, not 0, as 0 is continue
+		     * and 1 is break.
+		     */
+		    Statement *s;
+		    sc->fes->cases.push(this);
+		    s = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
+		    return s;
+		}
+		break;			// can't break to it
+	    }
+
+	    ls = scx->slabel;
+	    if (ls && ls->ident == ident)
+	    {
+		Statement *s = ls->statement;
+
+		if (!s->hasBreak())
+		    error("label '%s' has no break", ident->toChars());
+		if (ls->tf != sc->tf)
+		    error("cannot break out of finally block");
+		return this;
+	    }
+	}
+	error("enclosing label '%s' for break not found", ident->toChars());
+    }
+    else if (!sc->sbreak)
+    {
+	if (sc->fes)
+	{   Statement *s;
+
+	    // Replace break; with return 1;
+	    s = new ReturnStatement(0, new IntegerExp(1));
+	    return s;
+	}
+	error("break is not inside a loop or switch");
+    }
+    return this;
+}
+
+int BreakStatement::fallOffEnd()
+{
+    return FALSE;
+}
+
+void BreakStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("break");
+    if (ident)
+    {   buf->writebyte(' ');
+        buf->writestring(ident->toChars());
+    }
+    buf->writebyte(';');
+    buf->writenl();
+}
+
+/******************************** ContinueStatement ***************************/
+
+ContinueStatement::ContinueStatement(Loc loc, Identifier *ident)
+    : Statement(loc)
+{
+    this->ident = ident;
+}
+
+Statement *ContinueStatement::syntaxCopy()
+{
+    ContinueStatement *s = new ContinueStatement(loc, ident);
+    return s;
+}
+
+Statement *ContinueStatement::semantic(Scope *sc)
+{
+    //printf("ContinueStatement::semantic() %p\n", this);
+    if (ident)
+    {
+	Scope *scx;
+	FuncDeclaration *thisfunc = sc->func;
+
+	for (scx = sc; scx; scx = scx->enclosing)
+	{
+	    LabelStatement *ls;
+
+	    if (scx->func != thisfunc)	// if in enclosing function
+	    {
+		if (sc->fes)		// if this is the body of a foreach
+		{
+		    for (; scx; scx = scx->enclosing)
+		    {
+			ls = scx->slabel;
+			if (ls && ls->ident == ident && ls->statement == sc->fes)
+			{
+			    // Replace continue ident; with return 0;
+			    return new ReturnStatement(0, new IntegerExp(0));
+			}
+		    }
+
+		    /* Post this statement to the fes, and replace
+		     * it with a return value that caller will put into
+		     * a switch. Caller will figure out where the break
+		     * label actually is.
+		     * Case numbers start with 2, not 0, as 0 is continue
+		     * and 1 is break.
+		     */
+		    Statement *s;
+		    sc->fes->cases.push(this);
+		    s = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
+		    return s;
+		}
+		break;			// can't continue to it
+	    }
+
+	    ls = scx->slabel;
+	    if (ls && ls->ident == ident)
+	    {
+		Statement *s = ls->statement;
+
+		if (!s->hasContinue())
+		    error("label '%s' has no continue", ident->toChars());
+		if (ls->tf != sc->tf)
+		    error("cannot continue out of finally block");
+		return this;
+	    }
+	}
+	error("enclosing label '%s' for continue not found", ident->toChars());
+    }
+    else if (!sc->scontinue)
+    {
+	if (sc->fes)
+	{   Statement *s;
+
+	    // Replace continue; with return 0;
+	    s = new ReturnStatement(0, new IntegerExp(0));
+	    return s;
+	}
+	error("continue is not inside a loop");
+    }
+    return this;
+}
+
+int ContinueStatement::fallOffEnd()
+{
+    return FALSE;
+}
+
+void ContinueStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("continue");
+    if (ident)
+    {   buf->writebyte(' ');
+        buf->writestring(ident->toChars());
+    }
+    buf->writebyte(';');
+    buf->writenl();
+}
+
+/******************************** SynchronizedStatement ***************************/
+
+SynchronizedStatement::SynchronizedStatement(Loc loc, Expression *exp, Statement *body)
+    : Statement(loc)
+{
+    this->exp = exp;
+    this->body = body;
+    this->esync = NULL;
+}
+
+SynchronizedStatement::SynchronizedStatement(Loc loc, elem *esync, Statement *body)
+    : Statement(loc)
+{
+    this->exp = NULL;
+    this->body = body;
+    this->esync = esync;
+}
+
+Statement *SynchronizedStatement::syntaxCopy()
+{
+    Expression *e = exp ? exp->syntaxCopy() : NULL;
+    SynchronizedStatement *s = new SynchronizedStatement(loc, e, body ? body->syntaxCopy() : NULL);
+    return s;
+}
+
+Statement *SynchronizedStatement::semantic(Scope *sc)
+{
+    if (exp)
+    {	ClassDeclaration *cd;
+
+	exp = exp->semantic(sc);
+	exp = resolveProperties(sc, exp);
+	cd = exp->type->isClassHandle();
+	if (!cd)
+	    error("can only synchronize on class objects, not '%s'", exp->type->toChars());
+	else if (cd->isInterfaceDeclaration())
+	{   Type *t = new TypeIdentifier(0, Id::Object);
+
+	    t = t->semantic(0, sc);
+	    exp = new CastExp(loc, exp, t);
+	    exp = exp->semantic(sc);
+	}
+    }
+    if (body)
+	body = body->semantic(sc);
+    return this;
+}
+
+int SynchronizedStatement::hasBreak()
+{
+    return FALSE; //TRUE;
+}
+
+int SynchronizedStatement::hasContinue()
+{
+    return FALSE; //TRUE;
+}
+
+int SynchronizedStatement::usesEH()
+{
+    return TRUE;
+}
+
+int SynchronizedStatement::fallOffEnd()
+{
+    return body ? body->fallOffEnd() : TRUE;
+}
+
+void SynchronizedStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("synchronized");
+    if (exp)
+    {   buf->writebyte('(');
+	exp->toCBuffer(buf, hgs);
+	buf->writebyte(')');
+    }
+    if (body)
+    {
+	buf->writebyte(' ');
+	body->toCBuffer(buf, hgs);
+    }
+}
+
+/******************************** WithStatement ***************************/
+
+WithStatement::WithStatement(Loc loc, Expression *exp, Statement *body)
+    : Statement(loc)
+{
+    this->exp = exp;
+    this->body = body;
+    wthis = NULL;
+}
+
+Statement *WithStatement::syntaxCopy()
+{
+    WithStatement *s = new WithStatement(loc, exp->syntaxCopy(), body ? body->syntaxCopy() : NULL);
+    return s;
+}
+
+Statement *WithStatement::semantic(Scope *sc)
+{   ScopeDsymbol *sym;
+    Initializer *init;
+
+    //printf("WithStatement::semantic()\n");
+    exp = exp->semantic(sc);
+    exp = resolveProperties(sc, exp);
+    if (exp->op == TOKimport)
+    {	ScopeExp *es = (ScopeExp *)exp;
+
+	sym = es->sds;
+    }
+    else if (exp->op == TOKtype)
+    {	TypeExp *es = (TypeExp *)exp;
+
+	sym = es->type->toDsymbol(sc)->isScopeDsymbol();
+	if (!sym)
+	{   error("%s has no members", es->toChars());
+	    body = body->semantic(sc);
+	    return this;
+	}
+    }
+    else
+    {	Type *t = exp->type;
+
+	assert(t);
+	t = t->toBasetype();
+	if (t->isClassHandle())
+	{
+	    init = new ExpInitializer(loc, exp);
+	    wthis = new VarDeclaration(loc, exp->type, Id::withSym, init);
+	    wthis->semantic(sc);
+
+	    sym = new WithScopeSymbol(this);
+	    sym->parent = sc->scopesym;
+	}
+	else if (t->ty == Tstruct)
+	{
+	    Expression *e = exp->addressOf(sc);
+	    init = new ExpInitializer(loc, e);
+	    wthis = new VarDeclaration(loc, e->type, Id::withSym, init);
+	    wthis->semantic(sc);
+	    sym = new WithScopeSymbol(this);
+	    sym->parent = sc->scopesym;
+	}
+	else
+	{   error("with expressions must be class objects, not '%s'", exp->type->toChars());
+	    return NULL;
+	}
+    }
+    sc = sc->push(sym);
+
+    if (body)
+	body = body->semantic(sc);
+
+    sc->pop();
+
+    return this;
+}
+
+void WithStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("with (");
+    exp->toCBuffer(buf, hgs);
+    buf->writestring(")\n");
+    if (body)
+	body->toCBuffer(buf, hgs);
+}
+
+int WithStatement::usesEH()
+{
+    return body ? body->usesEH() : 0;
+}
+
+int WithStatement::fallOffEnd()
+{
+    return body ? body->fallOffEnd() : TRUE;
+}
+
+/******************************** TryCatchStatement ***************************/
+
+TryCatchStatement::TryCatchStatement(Loc loc, Statement *body, Array *catches)
+    : Statement(loc)
+{
+    this->body = body;
+    this->catches = catches;
+}
+
+Statement *TryCatchStatement::syntaxCopy()
+{
+    Array *a = new Array();
+    a->setDim(catches->dim);
+    for (int i = 0; i < a->dim; i++)
+    {   Catch *c;
+
+	c = (Catch *)catches->data[i];
+	c = c->syntaxCopy();
+	a->data[i] = c;
+    }
+    TryCatchStatement *s = new TryCatchStatement(loc, body->syntaxCopy(), a);
+    return s;
+}
+
+Statement *TryCatchStatement::semantic(Scope *sc)
+{
+    body = body->semanticScope(sc, NULL /*this*/, NULL);
+
+    for (int i = 0; i < catches->dim; i++)
+    {   Catch *c;
+
+	c = (Catch *)catches->data[i];
+	c->semantic(sc);
+
+	// Determine if current catch 'hides' any previous catches
+	for (int j = 0; j < i; j++)
+	{   Catch *cj = (Catch *)catches->data[j];
+	    char *si = c->loc.toChars();
+	    char *sj = cj->loc.toChars();
+
+	    if (c->type->toBasetype()->implicitConvTo(cj->type->toBasetype()))
+		error("catch at %s hides catch at %s", sj, si);
+	}
+    }
+    return this;
+}
+
+int TryCatchStatement::hasBreak()
+{
+    return FALSE; //TRUE;
+}
+
+int TryCatchStatement::usesEH()
+{
+    return TRUE;
+}
+
+int TryCatchStatement::fallOffEnd()
+{
+    int result = FALSE;
+
+    if (body)
+	result = body->fallOffEnd();
+    for (int i = 0; i < catches->dim; i++)
+    {   Catch *c;
+
+	c = (Catch *)catches->data[i];
+	if (c->handler)
+	    result |= c->handler->fallOffEnd();
+    }
+    return result;
+}
+
+void TryCatchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("try");
+    buf->writenl();
+    if (body)
+        body->toCBuffer(buf, hgs);
+    int i;
+    for (i = 0; i < catches->dim; i++)
+    {
+        Catch *c = (Catch *)catches->data[i];
+        c->toCBuffer(buf, hgs);
+    }
+}
+
+/******************************** Catch ***************************/
+
+Catch::Catch(Loc loc, Type *t, Identifier *id, Statement *handler)
+{
+    //printf("Catch(%s, loc = %s)\n", id->toChars(), loc.toChars());
+    this->loc = loc;
+    this->type = t;
+    this->ident = id;
+    this->handler = handler;
+    var = NULL;
+}
+
+Catch *Catch::syntaxCopy()
+{
+    Catch *c = new Catch(loc,
+	(type ? type->syntaxCopy() : NULL),
+	ident,
+	(handler ? handler->syntaxCopy() : NULL));
+    return c;
+}
+
+void Catch::semantic(Scope *sc)
+{   ScopeDsymbol *sym;
+
+    //printf("Catch::semantic(%s)\n", ident->toChars());
+
+#ifndef IN_GCC
+    if (sc->tf)
+    {
+	/* This is because the _d_local_unwind() gets the stack munged
+	 * up on this. The workaround is to place any try-catches into
+	 * a separate function, and call that.
+	 * To fix, have the compiler automatically convert the finally
+	 * body into a nested function.
+	 */
+	error(loc, "cannot put catch statement inside finally block");
+    }
+#endif
+
+    sym = new ScopeDsymbol();
+    sym->parent = sc->scopesym;
+    sc = sc->push(sym);
+
+    if (!type)
+	type = new TypeIdentifier(0, Id::Object);
+    type = type->semantic(loc, sc);
+    if (!type->toBasetype()->isClassHandle())
+	error("can only catch class objects, not '%s'", type->toChars());
+    else if (ident)
+    {
+	var = new VarDeclaration(loc, type, ident, NULL);
+	var->parent = sc->parent;
+	sc->insert(var);
+    }
+    handler = handler->semantic(sc);
+
+    sc->pop();
+}
+
+void Catch::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("catch");
+    if (type)
+    {   buf->writebyte('(');
+	type->toCBuffer(buf, ident, hgs);
+        buf->writebyte(')');
+    }
+    buf->writenl();
+    buf->writebyte('{');
+    buf->writenl();
+    handler->toCBuffer(buf, hgs);
+    buf->writebyte('}');
+    buf->writenl();
+}
+
+/****************************** TryFinallyStatement ***************************/
+
+TryFinallyStatement::TryFinallyStatement(Loc loc, Statement *body, Statement *finalbody)
+    : Statement(loc)
+{
+    this->body = body;
+    this->finalbody = finalbody;
+}
+
+Statement *TryFinallyStatement::syntaxCopy()
+{
+    TryFinallyStatement *s = new TryFinallyStatement(loc,
+	body->syntaxCopy(), finalbody->syntaxCopy());
+    return s;
+}
+
+Statement *TryFinallyStatement::semantic(Scope *sc)
+{
+    //printf("TryFinallyStatement::semantic()\n");
+    body = body->semantic(sc);
+    sc = sc->push();
+    sc->tf = this;
+    sc->sbreak = NULL;
+    sc->scontinue = NULL;	// no break or continue out of finally block
+    finalbody = finalbody->semantic(sc);
+    sc->pop();
+    return this;
+}
+
+void TryFinallyStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->printf("try\n{\n");
+    body->toCBuffer(buf, hgs);
+    buf->printf("}\nfinally\n{\n");
+    finalbody->toCBuffer(buf, hgs);
+    buf->writeByte('}');
+    buf->writenl();
+}
+
+int TryFinallyStatement::hasBreak()
+{
+    return FALSE; //TRUE;
+}
+
+int TryFinallyStatement::hasContinue()
+{
+    return FALSE; //TRUE;
+}
+
+int TryFinallyStatement::usesEH()
+{
+    return TRUE;
+}
+
+int TryFinallyStatement::fallOffEnd()
+{   int result;
+
+    result = body->fallOffEnd();
+//    if (finalbody)
+//	result = finalbody->fallOffEnd();
+    return result;
+}
+
+/****************************** OnScopeStatement ***************************/
+
+OnScopeStatement::OnScopeStatement(Loc loc, TOK tok, Statement *statement)
+    : Statement(loc)
+{
+    this->tok = tok;
+    this->statement = statement;
+}
+
+Statement *OnScopeStatement::syntaxCopy()
+{
+    OnScopeStatement *s = new OnScopeStatement(loc,
+	tok, statement->syntaxCopy());
+    return s;
+}
+
+Statement *OnScopeStatement::semantic(Scope *sc)
+{
+    /* semantic is called on results of scopeCode() */
+    return this;
+}
+
+void OnScopeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring(Token::toChars(tok));
+    buf->writebyte(' ');
+    statement->toCBuffer(buf, hgs);
+}
+
+int OnScopeStatement::usesEH()
+{
+    return (tok != TOKon_scope_success);
+}
+
+void OnScopeStatement::scopeCode(Statement **sentry, Statement **sexception, Statement **sfinally)
+{
+    //printf("OnScopeStatement::scopeCode()\n");
+    //print();
+    *sentry = NULL;
+    *sexception = NULL;
+    *sfinally = NULL;
+    switch (tok)
+    {
+	case TOKon_scope_exit:
+	    *sfinally = statement;
+	    break;
+
+	case TOKon_scope_failure:
+	    *sexception = statement;
+	    break;
+
+	case TOKon_scope_success:
+	{
+	    /* Create:
+	     *	sentry:   int x = 0;
+	     *	sexception:    x = 1;
+	     *	sfinally: if (!x) statement;
+	     */
+	    static int num;
+	    char name[5 + sizeof(num) * 3 + 1];
+	    sprintf(name, "__osf%d", ++num);
+	    Identifier *id = Lexer::idPool(name);
+
+	    ExpInitializer *ie = new ExpInitializer(loc, new IntegerExp(0));
+	    VarDeclaration *v = new VarDeclaration(loc, Type::tint32, id, ie);
+	    *sentry = new DeclarationStatement(loc, v);
+
+	    Expression *e = new IntegerExp(1);
+	    e = new AssignExp(0, new VarExp(0, v), e);
+	    *sexception = new ExpStatement(0, e);
+
+	    e = new VarExp(0, v);
+	    e = new NotExp(0, e);
+	    *sfinally = new IfStatement(0, NULL, e, statement, NULL);
+
+	    break;
+	}
+
+	default:
+	    assert(0);
+    }
+}
+
+/******************************** ThrowStatement ***************************/
+
+ThrowStatement::ThrowStatement(Loc loc, Expression *exp)
+    : Statement(loc)
+{
+    this->exp = exp;
+}
+
+Statement *ThrowStatement::syntaxCopy()
+{
+    ThrowStatement *s = new ThrowStatement(loc, exp->syntaxCopy());
+    return s;
+}
+
+Statement *ThrowStatement::semantic(Scope *sc)
+{
+    //printf("ThrowStatement::semantic()\n");
+
+    FuncDeclaration *fd = sc->parent->isFuncDeclaration();
+    fd->hasReturnExp |= 2;
+
+    if (sc->incontract)
+	error("Throw statements cannot be in contracts");
+    exp = exp->semantic(sc);
+    exp = resolveProperties(sc, exp);
+    if (!exp->type->toBasetype()->isClassHandle())
+	error("can only throw class objects, not type %s", exp->type->toChars());
+    return this;
+}
+
+int ThrowStatement::fallOffEnd()
+{
+    return FALSE;
+}
+
+void ThrowStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->printf("throw ");
+    exp->toCBuffer(buf, hgs);
+    buf->writeByte(';');
+    buf->writenl();
+}
+
+/******************************** VolatileStatement **************************/
+
+VolatileStatement::VolatileStatement(Loc loc, Statement *statement)
+    : Statement(loc)
+{
+    this->statement = statement;
+}
+
+Statement *VolatileStatement::syntaxCopy()
+{
+    VolatileStatement *s = new VolatileStatement(loc,
+		statement ? statement->syntaxCopy() : NULL);
+    return s;
+}
+
+Statement *VolatileStatement::semantic(Scope *sc)
+{
+    statement = statement ? statement->semantic(sc) : NULL;
+    return this;
+}
+
+Statements *VolatileStatement::flatten(Scope *sc)
+{
+    Statements *a;
+
+    a = statement ? statement->flatten(sc) : NULL;
+    if (a)
+    {	for (int i = 0; i < a->dim; i++)
+	{   Statement *s = (Statement *)a->data[i];
+
+	    s = new VolatileStatement(loc, s);
+	    a->data[i] = s;
+	}
+    }
+
+    return a;
+}
+
+int VolatileStatement::fallOffEnd()
+{
+    return statement ? statement->fallOffEnd() : TRUE;
+}
+
+void VolatileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("volatile");
+    if (statement)
+    {   if (statement->isScopeStatement())
+            buf->writenl();
+        else
+            buf->writebyte(' ');
+        statement->toCBuffer(buf, hgs);
+    }
+}
+
+
+/******************************** GotoStatement ***************************/
+
+GotoStatement::GotoStatement(Loc loc, Identifier *ident)
+    : Statement(loc)
+{
+    this->ident = ident;
+    this->label = NULL;
+    this->tf = NULL;
+}
+
+Statement *GotoStatement::syntaxCopy()
+{
+    GotoStatement *s = new GotoStatement(loc, ident);
+    return s;
+}
+
+Statement *GotoStatement::semantic(Scope *sc)
+{   FuncDeclaration *fd = sc->parent->isFuncDeclaration();
+
+    //printf("GotoStatement::semantic()\n");
+    tf = sc->tf;
+    label = fd->searchLabel(ident);
+    if (!label->statement && sc->fes)
+    {
+	/* Either the goto label is forward referenced or it
+	 * is in the function that the enclosing foreach is in.
+	 * Can't know yet, so wrap the goto in a compound statement
+	 * so we can patch it later, and add it to a 'look at this later'
+	 * list.
+	 */
+	Statements *a = new Statements();
+	Statement *s;
+
+	a->push(this);
+	s = new CompoundStatement(loc, a);
+	sc->fes->gotos.push(s);		// 'look at this later' list
+	return s;
+    }
+    if (label->statement && label->statement->tf != sc->tf)
+	error("cannot goto in or out of finally block");
+    return this;
+}
+
+int GotoStatement::fallOffEnd()
+{
+    return FALSE;
+}
+
+void GotoStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("goto ");
+    buf->writestring(ident->toChars());
+    buf->writebyte(';');
+    buf->writenl();
+}
+
+/******************************** LabelStatement ***************************/
+
+LabelStatement::LabelStatement(Loc loc, Identifier *ident, Statement *statement)
+    : Statement(loc)
+{
+    this->ident = ident;
+    this->statement = statement;
+    this->tf = NULL;
+    this->lblock = NULL;
+    this->isReturnLabel = 0;
+}
+
+Statement *LabelStatement::syntaxCopy()
+{
+    LabelStatement *s = new LabelStatement(loc, ident, statement->syntaxCopy());
+    return s;
+}
+
+Statement *LabelStatement::semantic(Scope *sc)
+{   LabelDsymbol *ls;
+    FuncDeclaration *fd = sc->parent->isFuncDeclaration();
+
+    //printf("LabelStatement::semantic()\n");
+    ls = fd->searchLabel(ident);
+    if (ls->statement)
+	error("Label '%s' already defined", ls->toChars());
+    else
+	ls->statement = this;
+    tf = sc->tf;
+    sc = sc->push();
+    sc->scopesym = sc->enclosing->scopesym;
+    sc->callSuper |= CSXlabel;
+    sc->slabel = this;
+    if (statement)
+	statement = statement->semantic(sc);
+    sc->pop();
+    return this;
+}
+
+Statements *LabelStatement::flatten(Scope *sc)
+{
+    Statements *a = NULL;
+
+    if (statement)
+    {
+	a = statement->flatten(sc);
+	if (a)
+	{
+	    if (!a->dim)
+	    {
+		a->push(new ExpStatement(loc, NULL));
+	    }
+	    Statement *s = (Statement *)a->data[0];
+
+	    s = new LabelStatement(loc, ident, s);
+	    a->data[0] = s;
+	}
+    }
+
+    return a;
+}
+
+
+int LabelStatement::usesEH()
+{
+    return statement ? statement->usesEH() : FALSE;
+}
+
+int LabelStatement::fallOffEnd()
+{
+    return statement ? statement->fallOffEnd() : TRUE;
+}
+
+int LabelStatement::comeFrom()
+{
+    //printf("LabelStatement::comeFrom()\n");
+    return TRUE;
+}
+
+void LabelStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring(ident->toChars());
+    buf->writebyte(':');
+    buf->writenl();
+    if (statement)
+        statement->toCBuffer(buf, hgs);
+}
+
+
+/******************************** LabelDsymbol ***************************/
+
+LabelDsymbol::LabelDsymbol(Identifier *ident)
+	: Dsymbol(ident)
+{
+    statement = NULL;
+#if IN_GCC
+    asmLabelNum = 0;
+#endif
+}
+
+LabelDsymbol *LabelDsymbol::isLabel()		// is this a LabelDsymbol()?
+{
+    return this;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/statement.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,751 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#ifndef DMD_STATEMENT_H
+#define DMD_STATEMENT_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include "root.h"
+
+#include "arraytypes.h"
+#include "dsymbol.h"
+#include "lexer.h"
+
+struct OutBuffer;
+struct Scope;
+struct Expression;
+struct LabelDsymbol;
+struct Identifier;
+struct IfStatement;
+struct DeclarationStatement;
+struct DefaultStatement;
+struct VarDeclaration;
+struct Condition;
+struct Module;
+struct Token;
+struct InlineCostState;
+struct InlineDoState;
+struct InlineScanState;
+struct ReturnStatement;
+struct CompoundStatement;
+struct Argument;
+struct StaticAssert;
+struct AsmStatement;
+struct GotoStatement;
+struct ScopeStatement;
+struct TryCatchStatement;
+struct HdrGenState;
+struct InterState;
+
+enum TOK;
+
+namespace llvm
+{
+    class Value;
+}
+
+// Back end
+struct IRState;
+struct Blockx;
+#if IN_GCC
+union tree_node; typedef union tree_node block;
+union tree_node; typedef union tree_node elem;
+#else
+struct block;
+struct elem;
+#endif
+struct code;
+
+struct Statement : Object
+{
+    Loc loc;
+
+    Statement(Loc loc);
+    virtual Statement *syntaxCopy();
+
+    void print();
+    char *toChars();
+
+    void error(const char *format, ...);
+    virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    virtual TryCatchStatement *isTryCatchStatement() { return NULL; }
+    virtual GotoStatement *isGotoStatement() { return NULL; }
+    virtual AsmStatement *isAsmStatement() { return NULL; }
+#ifdef _DH
+    int incontract;
+#endif
+    virtual ScopeStatement *isScopeStatement() { return NULL; }
+    virtual Statement *semantic(Scope *sc);
+    Statement *semanticScope(Scope *sc, Statement *sbreak, Statement *scontinue);
+    virtual int hasBreak();
+    virtual int hasContinue();
+    virtual int usesEH();
+    virtual int fallOffEnd();
+    virtual int comeFrom();
+    virtual void scopeCode(Statement **sentry, Statement **sexit, Statement **sfinally);
+    virtual Statements *flatten(Scope *sc);
+    virtual Expression *interpret(InterState *istate);
+
+    virtual int inlineCost(InlineCostState *ics);
+    virtual Expression *doInline(InlineDoState *ids);
+    virtual Statement *inlineScan(InlineScanState *iss);
+
+    // Back end
+    virtual void toIR(IRState *irs);
+
+    // Avoid dynamic_cast
+    virtual DeclarationStatement *isDeclarationStatement() { return NULL; }
+    virtual CompoundStatement *isCompoundStatement() { return NULL; }
+    virtual ReturnStatement *isReturnStatement() { return NULL; }
+    virtual IfStatement *isIfStatement() { return NULL; }
+};
+
+struct ExpStatement : Statement
+{
+    Expression *exp;
+
+    ExpStatement(Loc loc, Expression *exp);
+    Statement *syntaxCopy();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    Statement *semantic(Scope *sc);
+    Expression *interpret(InterState *istate);
+    int fallOffEnd();
+
+    int inlineCost(InlineCostState *ics);
+    Expression *doInline(InlineDoState *ids);
+    Statement *inlineScan(InlineScanState *iss);
+
+    void toIR(IRState *irs);
+};
+
+struct CompileStatement : Statement
+{
+    Expression *exp;
+
+    CompileStatement(Loc loc, Expression *exp);
+    Statement *syntaxCopy();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    Statement *semantic(Scope *sc);
+};
+
+struct DeclarationStatement : ExpStatement
+{
+    // Doing declarations as an expression, rather than a statement,
+    // makes inlining functions much easier.
+
+    DeclarationStatement(Loc loc, Dsymbol *s);
+    DeclarationStatement(Loc loc, Expression *exp);
+    Statement *syntaxCopy();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    void scopeCode(Statement **sentry, Statement **sexit, Statement **sfinally);
+
+    DeclarationStatement *isDeclarationStatement() { return this; }
+};
+
+struct CompoundStatement : Statement
+{
+    Statements *statements;
+
+    CompoundStatement(Loc loc, Statements *s);
+    CompoundStatement(Loc loc, Statement *s1, Statement *s2);
+    Statement *syntaxCopy();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    Statement *semantic(Scope *sc);
+    int usesEH();
+    int fallOffEnd();
+    int comeFrom();
+    Statements *flatten(Scope *sc);
+    ReturnStatement *isReturnStatement();
+    Expression *interpret(InterState *istate);
+
+    int inlineCost(InlineCostState *ics);
+    Expression *doInline(InlineDoState *ids);
+    Statement *inlineScan(InlineScanState *iss);
+
+    void toIR(IRState *irs);
+
+    CompoundStatement *isCompoundStatement() { return this; }
+};
+
+/* The purpose of this is so that continue will go to the next
+ * of the statements, and break will go to the end of the statements.
+ */
+struct UnrolledLoopStatement : Statement
+{
+    Statements *statements;
+
+    UnrolledLoopStatement(Loc loc, Statements *statements);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    int hasBreak();
+    int hasContinue();
+    int usesEH();
+    int fallOffEnd();
+    int comeFrom();
+    Expression *interpret(InterState *istate);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    int inlineCost(InlineCostState *ics);
+    Expression *doInline(InlineDoState *ids);
+    Statement *inlineScan(InlineScanState *iss);
+
+    void toIR(IRState *irs);
+};
+
+struct ScopeStatement : Statement
+{
+    Statement *statement;
+
+    ScopeStatement(Loc loc, Statement *s);
+    Statement *syntaxCopy();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    ScopeStatement *isScopeStatement() { return this; }
+    Statement *semantic(Scope *sc);
+    int hasBreak();
+    int hasContinue();
+    int usesEH();
+    int fallOffEnd();
+    int comeFrom();
+    Expression *interpret(InterState *istate);
+
+    Statement *inlineScan(InlineScanState *iss);
+
+    void toIR(IRState *irs);
+};
+
+struct WhileStatement : Statement
+{
+    Expression *condition;
+    Statement *body;
+
+    WhileStatement(Loc loc, Expression *c, Statement *b);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    int hasBreak();
+    int hasContinue();
+    int usesEH();
+    int fallOffEnd();
+    int comeFrom();
+    Expression *interpret(InterState *istate);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    Statement *inlineScan(InlineScanState *iss);
+
+    void toIR(IRState *irs);
+};
+
+struct DoStatement : Statement
+{
+    Statement *body;
+    Expression *condition;
+
+    DoStatement(Loc loc, Statement *b, Expression *c);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    int hasBreak();
+    int hasContinue();
+    int usesEH();
+    int fallOffEnd();
+    int comeFrom();
+    Expression *interpret(InterState *istate);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    Statement *inlineScan(InlineScanState *iss);
+
+    void toIR(IRState *irs);
+};
+
+struct ForStatement : Statement
+{
+    Statement *init;
+    Expression *condition;
+    Expression *increment;
+    Statement *body;
+
+    ForStatement(Loc loc, Statement *init, Expression *condition, Expression *increment, Statement *body);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    void scopeCode(Statement **sentry, Statement **sexit, Statement **sfinally);
+    int hasBreak();
+    int hasContinue();
+    int usesEH();
+    int fallOffEnd();
+    int comeFrom();
+    Expression *interpret(InterState *istate);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    Statement *inlineScan(InlineScanState *iss);
+
+    void toIR(IRState *irs);
+};
+
+struct ForeachStatement : Statement
+{
+    enum TOK op;	// TOKforeach or TOKforeach_reverse
+    Arguments *arguments;	// array of Argument*'s
+    Expression *aggr;
+    Statement *body;
+
+    VarDeclaration *key;
+    VarDeclaration *value;
+
+    FuncDeclaration *func;	// function we're lexically in
+
+    Array cases;	// put breaks, continues, gotos and returns here
+    Array gotos;	// forward referenced goto's go here
+
+    ForeachStatement(Loc loc, enum TOK op, Arguments *arguments, Expression *aggr, Statement *body);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    int hasBreak();
+    int hasContinue();
+    int usesEH();
+    int fallOffEnd();
+    int comeFrom();
+    Expression *interpret(InterState *istate);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    Statement *inlineScan(InlineScanState *iss);
+
+    void toIR(IRState *irs);
+};
+
+struct IfStatement : Statement
+{
+    Argument *arg;
+    Expression *condition;
+    Statement *ifbody;
+    Statement *elsebody;
+
+    VarDeclaration *match;	// for MatchExpression results
+
+    IfStatement(Loc loc, Argument *arg, Expression *condition, Statement *ifbody, Statement *elsebody);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    Expression *interpret(InterState *istate);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    int usesEH();
+    int fallOffEnd();
+    IfStatement *isIfStatement() { return this; }
+
+    int inlineCost(InlineCostState *ics);
+    Expression *doInline(InlineDoState *ids);
+    Statement *inlineScan(InlineScanState *iss);
+
+    void toIR(IRState *irs);
+};
+
+struct ConditionalStatement : Statement
+{
+    Condition *condition;
+    Statement *ifbody;
+    Statement *elsebody;
+
+    ConditionalStatement(Loc loc, Condition *condition, Statement *ifbody, Statement *elsebody);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    Statements *flatten(Scope *sc);
+    int usesEH();
+
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+struct PragmaStatement : Statement
+{
+    Identifier *ident;
+    Expressions *args;		// array of Expression's
+    Statement *body;
+
+    PragmaStatement(Loc loc, Identifier *ident, Expressions *args, Statement *body);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    int usesEH();
+    int fallOffEnd();
+
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+struct StaticAssertStatement : Statement
+{
+    StaticAssert *sa;
+
+    StaticAssertStatement(StaticAssert *sa);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+struct SwitchStatement : Statement
+{
+    Expression *condition;
+    Statement *body;
+    DefaultStatement *sdefault;
+
+    Array gotoCases;		// array of unresolved GotoCaseStatement's
+    Array *cases;		// array of CaseStatement's
+    int hasNoDefault;		// !=0 if no default statement
+
+    SwitchStatement(Loc loc, Expression *c, Statement *b);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    int hasBreak();
+    int usesEH();
+    int fallOffEnd();
+    Expression *interpret(InterState *istate);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    Statement *inlineScan(InlineScanState *iss);
+
+    void toIR(IRState *irs);
+};
+
+struct CaseStatement : Statement
+{
+    Expression *exp;
+    Statement *statement;
+    int index;		// which case it is (since we sort this)
+    block *cblock;	// back end: label for the block
+
+    CaseStatement(Loc loc, Expression *exp, Statement *s);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    int compare(Object *obj);
+    int usesEH();
+    int fallOffEnd();
+    int comeFrom();
+    Expression *interpret(InterState *istate);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    Statement *inlineScan(InlineScanState *iss);
+
+    void toIR(IRState *irs);
+};
+
+struct DefaultStatement : Statement
+{
+    Statement *statement;
+#if IN_GCC
+    block *cblock;	// back end: label for the block
+#endif
+
+    DefaultStatement(Loc loc, Statement *s);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    int usesEH();
+    int fallOffEnd();
+    int comeFrom();
+    Expression *interpret(InterState *istate);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    Statement *inlineScan(InlineScanState *iss);
+
+    void toIR(IRState *irs);
+};
+
+struct GotoDefaultStatement : Statement
+{
+    SwitchStatement *sw;
+
+    GotoDefaultStatement(Loc loc);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    Expression *interpret(InterState *istate);
+    int fallOffEnd();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    void toIR(IRState *irs);
+};
+
+struct GotoCaseStatement : Statement
+{
+    Expression *exp;		// NULL, or which case to goto
+    CaseStatement *cs;		// case statement it resolves to
+
+    GotoCaseStatement(Loc loc, Expression *exp);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    Expression *interpret(InterState *istate);
+    int fallOffEnd();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    void toIR(IRState *irs);
+};
+
+struct SwitchErrorStatement : Statement
+{
+    SwitchErrorStatement(Loc loc);
+    int fallOffEnd();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    void toIR(IRState *irs);
+};
+
+struct ReturnStatement : Statement
+{
+    Expression *exp;
+
+    ReturnStatement(Loc loc, Expression *exp);
+    Statement *syntaxCopy();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    Statement *semantic(Scope *sc);
+    int fallOffEnd();
+    Expression *interpret(InterState *istate);
+
+    int inlineCost(InlineCostState *ics);
+    Expression *doInline(InlineDoState *ids);
+    Statement *inlineScan(InlineScanState *iss);
+
+    void toIR(IRState *irs);
+
+    ReturnStatement *isReturnStatement() { return this; }
+};
+
+struct BreakStatement : Statement
+{
+    Identifier *ident;
+
+    BreakStatement(Loc loc, Identifier *ident);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    Expression *interpret(InterState *istate);
+    int fallOffEnd();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    void toIR(IRState *irs);
+};
+
+struct ContinueStatement : Statement
+{
+    Identifier *ident;
+
+    ContinueStatement(Loc loc, Identifier *ident);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    Expression *interpret(InterState *istate);
+    int fallOffEnd();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    void toIR(IRState *irs);
+};
+
+struct SynchronizedStatement : Statement
+{
+    Expression *exp;
+    Statement *body;
+
+    SynchronizedStatement(Loc loc, Expression *exp, Statement *body);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    int hasBreak();
+    int hasContinue();
+    int usesEH();
+    int fallOffEnd();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    Statement *inlineScan(InlineScanState *iss);
+
+// Back end
+    elem *esync;
+    SynchronizedStatement(Loc loc, elem *esync, Statement *body);
+    void toIR(IRState *irs);
+};
+
+struct WithStatement : Statement
+{
+    Expression *exp;
+    Statement *body;
+    VarDeclaration *wthis;
+
+    WithStatement(Loc loc, Expression *exp, Statement *body);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    int usesEH();
+    int fallOffEnd();
+
+    Statement *inlineScan(InlineScanState *iss);
+
+    void toIR(IRState *irs);
+};
+
+struct TryCatchStatement : Statement
+{
+    Statement *body;
+    Array *catches;
+
+    TryCatchStatement(Loc loc, Statement *body, Array *catches);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    int hasBreak();
+    int usesEH();
+    int fallOffEnd();
+
+    Statement *inlineScan(InlineScanState *iss);
+
+    void toIR(IRState *irs);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    TryCatchStatement *isTryCatchStatement() { return this; }
+};
+
+struct Catch : Object
+{
+    Loc loc;
+    Type *type;
+    Identifier *ident;
+    VarDeclaration *var;
+    Statement *handler;
+
+    Catch(Loc loc, Type *t, Identifier *id, Statement *handler);
+    Catch *syntaxCopy();
+    void semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+struct TryFinallyStatement : Statement
+{
+    Statement *body;
+    Statement *finalbody;
+
+    TryFinallyStatement(Loc loc, Statement *body, Statement *finalbody);
+    Statement *syntaxCopy();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    Statement *semantic(Scope *sc);
+    int hasBreak();
+    int hasContinue();
+    int usesEH();
+    int fallOffEnd();
+
+    Statement *inlineScan(InlineScanState *iss);
+
+    void toIR(IRState *irs);
+};
+
+struct OnScopeStatement : Statement
+{
+    TOK tok;
+    Statement *statement;
+
+    OnScopeStatement(Loc loc, TOK tok, Statement *statement);
+    Statement *syntaxCopy();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    Statement *semantic(Scope *sc);
+    int usesEH();
+    void scopeCode(Statement **sentry, Statement **sexit, Statement **sfinally);
+
+    void toIR(IRState *irs);
+};
+
+struct ThrowStatement : Statement
+{
+    Expression *exp;
+
+    ThrowStatement(Loc loc, Expression *exp);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    int fallOffEnd();
+
+    Statement *inlineScan(InlineScanState *iss);
+
+    void toIR(IRState *irs);
+};
+
+struct VolatileStatement : Statement
+{
+    Statement *statement;
+
+    VolatileStatement(Loc loc, Statement *statement);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    Statements *flatten(Scope *sc);
+    int fallOffEnd();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    Statement *inlineScan(InlineScanState *iss);
+
+    void toIR(IRState *irs);
+};
+
+struct GotoStatement : Statement
+{
+    Identifier *ident;
+    LabelDsymbol *label;
+    TryFinallyStatement *tf;
+
+    GotoStatement(Loc loc, Identifier *ident);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    int fallOffEnd();
+    Expression *interpret(InterState *istate);
+
+    void toIR(IRState *irs);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    GotoStatement *isGotoStatement() { return this; }
+};
+
+struct LabelStatement : Statement
+{
+    Identifier *ident;
+    Statement *statement;
+    TryFinallyStatement *tf;
+    block *lblock;		// back end
+    int isReturnLabel;
+
+    LabelStatement(Loc loc, Identifier *ident, Statement *statement);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    Statements *flatten(Scope *sc);
+    int usesEH();
+    int fallOffEnd();
+    int comeFrom();
+    Expression *interpret(InterState *istate);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    Statement *inlineScan(InlineScanState *iss);
+
+    void toIR(IRState *irs);
+};
+
+struct LabelDsymbol : Dsymbol
+{
+    LabelStatement *statement;
+#if IN_GCC
+    unsigned asmLabelNum;       // GCC-specific
+#endif
+
+    LabelDsymbol(Identifier *ident);
+    LabelDsymbol *isLabel();
+};
+
+struct AsmStatement : Statement
+{
+    Token *tokens;
+    code *asmcode;
+    unsigned asmalign;		// alignment of this statement
+    unsigned refparam;		// !=0 if function parameter is referenced
+    unsigned naked;		// !=0 if function is to be naked
+    unsigned regs;		// mask of registers modified
+
+    AsmStatement(Loc loc, Token *tokens);
+    Statement *syntaxCopy();
+    Statement *semantic(Scope *sc);
+    int comeFrom();
+
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    virtual AsmStatement *isAsmStatement() { return this; }
+
+    void toIR(IRState *irs);
+};
+
+#endif /* DMD_STATEMENT_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/staticassert.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,109 @@
+
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "dsymbol.h"
+#include "staticassert.h"
+#include "expression.h"
+#include "id.h"
+#include "hdrgen.h"
+
+/********************************* AttribDeclaration ****************************/
+
+StaticAssert::StaticAssert(Loc loc, Expression *exp, Expression *msg)
+	: Dsymbol(Id::empty)
+{
+    this->loc = loc;
+    this->exp = exp;
+    this->msg = msg;
+}
+
+Dsymbol *StaticAssert::syntaxCopy(Dsymbol *s)
+{
+    StaticAssert *sa;
+
+    assert(!s);
+    sa = new StaticAssert(loc, exp->syntaxCopy(), msg ? msg->syntaxCopy() : NULL);
+    return sa;
+}
+
+int StaticAssert::addMember(Scope *sc, ScopeDsymbol *sd, int memnum)
+{
+    return 0;		// we didn't add anything
+}
+
+void StaticAssert::semantic(Scope *sc)
+{
+}
+
+void StaticAssert::semantic2(Scope *sc)
+{
+    Expression *e;
+
+    e = exp->semantic(sc);
+    e = e->optimize(WANTvalue | WANTinterpret);
+    if (e->isBool(FALSE))
+    {
+	if (msg)
+	{   HdrGenState hgs;
+	    OutBuffer buf;
+
+	    msg = msg->semantic(sc);
+	    msg = msg->optimize(WANTvalue | WANTinterpret);
+	    hgs.console = 1;
+	    msg->toCBuffer(&buf, &hgs);
+	    error("%s", buf.toChars());
+	}
+	else
+	    error("is false");
+	if (!global.gag)
+	    fatal();
+    }
+    else if (!e->isBool(TRUE))
+    {
+	error("(%s) is not evaluatable at compile time", exp->toChars());
+    }
+}
+
+int StaticAssert::oneMember(Dsymbol **ps)
+{
+    //printf("StaticAssert::oneMember())\n");
+    *ps = NULL;
+    return TRUE;
+}
+
+void StaticAssert::inlineScan()
+{
+}
+
+void StaticAssert::toObjFile()
+{
+}
+
+char *StaticAssert::kind()
+{
+    return "static assert";
+}
+
+void StaticAssert::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring(kind());
+    buf->writeByte('(');
+    exp->toCBuffer(buf, hgs);
+    if (msg)
+    {
+	buf->writeByte(',');
+	msg->toCBuffer(buf, hgs);
+    }
+    buf->writestring(");");
+    buf->writenl();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/staticassert.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,43 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#ifndef DMD_STATICASSERT_H
+#define DMD_STATICASSERT_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include "dsymbol.h"
+
+struct Expression;
+#ifdef _DH
+struct HdrGenState;
+#endif
+
+struct StaticAssert : Dsymbol
+{
+    Expression *exp;
+    Expression *msg;
+
+    StaticAssert(Loc loc, Expression *exp, Expression *msg);
+
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    int addMember(Scope *sc, ScopeDsymbol *sd, int memnum);
+    void semantic(Scope *sc);
+    void semantic2(Scope *sc);
+    void inlineScan();
+    int oneMember(Dsymbol **ps);
+    void toObjFile();
+    char *kind();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/stringtable.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,139 @@
+
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "root.h"
+#include "mem.h"
+#include "dchar.h"
+#include "lstring.h"
+#include "stringtable.h"
+
+StringTable::StringTable(unsigned size)
+{
+    table = (void **)mem.calloc(size, sizeof(void *));
+    tabledim = size;
+    count = 0;
+}
+
+StringTable::~StringTable()
+{
+    unsigned i;
+
+    // Zero out dangling pointers to help garbage collector.
+    // Should zero out StringEntry's too.
+    for (i = 0; i < count; i++)
+	table[i] = NULL;
+
+    mem.free(table);
+    table = NULL;
+}
+
+struct StringEntry
+{
+    StringEntry *left;
+    StringEntry *right;
+    hash_t hash;
+
+    StringValue value;
+
+    static StringEntry *alloc(const dchar *s, unsigned len);
+};
+
+StringEntry *StringEntry::alloc(const dchar *s, unsigned len)
+{
+    StringEntry *se;
+
+    se = (StringEntry *) mem.calloc(1,sizeof(StringEntry) - sizeof(Lstring) + Lstring::size(len));
+    se->value.lstring.length = len;
+    se->hash = Dchar::calcHash(s,len);
+    memcpy(se->value.lstring.string, s, len * sizeof(dchar));
+    return se;
+}
+
+void **StringTable::search(const dchar *s, unsigned len)
+{
+    hash_t hash;
+    unsigned u;
+    int cmp;
+    StringEntry **se;
+
+    //printf("StringTable::search(%p,%d)\n",s,len);
+    hash = Dchar::calcHash(s,len);
+    u = hash % tabledim;
+    se = (StringEntry **)&table[u];
+    //printf("\thash = %d, u = %d\n",hash,u);
+    while (*se)
+    {
+	cmp = (*se)->hash - hash;
+	if (cmp == 0)
+	{
+	    cmp = (*se)->value.lstring.len() - len;
+	    if (cmp == 0)
+	    {
+		cmp = Dchar::memcmp(s,(*se)->value.lstring.toDchars(),len);
+		if (cmp == 0)
+		    break;
+	    }
+	}
+	if (cmp < 0)
+	    se = &(*se)->left;
+	else
+	    se = &(*se)->right;
+    }
+    //printf("\treturn %p, %p\n",se, (*se));
+    return (void **)se;
+}
+
+StringValue *StringTable::lookup(const dchar *s, unsigned len)
+{   StringEntry *se;
+
+    se = *(StringEntry **)search(s,len);
+    if (se)
+	return &se->value;
+    else
+	return NULL;
+}
+
+StringValue *StringTable::update(const dchar *s, unsigned len)
+{   StringEntry **pse;
+    StringEntry *se;
+
+    pse = (StringEntry **)search(s,len);
+    se = *pse;
+    if (!se)			// not in table: so create new entry
+    {
+	se = StringEntry::alloc(s, len);
+	*pse = se;
+    }
+    return &se->value;
+}
+
+StringValue *StringTable::insert(const dchar *s, unsigned len)
+{   StringEntry **pse;
+    StringEntry *se;
+
+    pse = (StringEntry **)search(s,len);
+    se = *pse;
+    if (se)
+	return NULL;		// error: already in table
+    else
+    {
+	se = StringEntry::alloc(s, len);
+	*pse = se;
+    }
+    return &se->value;
+}
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/stringtable.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,48 @@
+// Copyright (c) 1999-2002 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+
+#ifndef STRINGTABLE_H
+#define STRINGTABLE_H
+
+#if __SC__
+#pragma once
+#endif
+
+#include "root.h"
+#include "dchar.h"
+#include "lstring.h"
+
+struct StringValue
+{
+    union
+    {	int intvalue;
+	void *ptrvalue;
+	dchar *string;
+    };
+    Lstring lstring;
+};
+
+struct StringTable : Object
+{
+    void **table;
+    unsigned count;
+    unsigned tabledim;
+
+    StringTable(unsigned size = 37);
+    ~StringTable();
+
+    StringValue *lookup(const dchar *s, unsigned len);
+    StringValue *insert(const dchar *s, unsigned len);
+    StringValue *update(const dchar *s, unsigned len);
+
+private:
+    void **search(const dchar *s, unsigned len);
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/struct.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,488 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "root.h"
+#include "aggregate.h"
+#include "scope.h"
+#include "mtype.h"
+#include "declaration.h"
+#include "module.h"
+#include "id.h"
+#include "statement.h"
+
+/********************************* AggregateDeclaration ****************************/
+
+AggregateDeclaration::AggregateDeclaration(Loc loc, Identifier *id)
+    : ScopeDsymbol(id)
+{
+    this->loc = loc;
+
+    storage_class = 0;
+    protection = PROTpublic;
+    type = NULL;
+    handle = NULL;
+    structsize = 0;		// size of struct
+    alignsize = 0;		// size of struct for alignment purposes
+    structalign = 0;		// struct member alignment in effect
+    hasUnions = 0;
+    sizeok = 0;			// size not determined yet
+    isdeprecated = 0;
+    inv = NULL;
+    aggNew = NULL;
+    aggDelete = NULL;
+
+    stag = NULL;
+    sinit = NULL;
+    scope = NULL;
+
+    llvmType = NULL;
+    llvmVtbl = NULL;
+    llvmInitZ = NULL;
+    llvmInProgress = false;
+}
+
+enum PROT AggregateDeclaration::prot()
+{
+    return protection;
+}
+
+void AggregateDeclaration::semantic2(Scope *sc)
+{
+    //printf("AggregateDeclaration::semantic2(%s)\n", toChars());
+    if (scope)
+    {	error("has forward references");
+	return;
+    }
+    if (members)
+    {
+	sc = sc->push(this);
+	for (size_t i = 0; i < members->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)members->data[i];
+	    s->semantic2(sc);
+	}
+	sc->pop();
+    }
+}
+
+void AggregateDeclaration::semantic3(Scope *sc)
+{   int i;
+
+    //printf("AggregateDeclaration::semantic3(%s)\n", toChars());
+    if (members)
+    {
+	sc = sc->push(this);
+	for (i = 0; i < members->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)members->data[i];
+	    s->semantic3(sc);
+	}
+	sc->pop();
+    }
+}
+
+void AggregateDeclaration::inlineScan()
+{   int i;
+
+    //printf("AggregateDeclaration::inlineScan(%s)\n", toChars());
+    if (members)
+    {
+	for (i = 0; i < members->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)members->data[i];
+	    //printf("inline scan aggregate symbol '%s'\n", s->toChars());
+	    s->inlineScan();
+	}
+    }
+}
+
+unsigned AggregateDeclaration::size(Loc loc)
+{
+    //printf("AggregateDeclaration::size() = %d\n", structsize);
+    if (!members)
+	error(loc, "unknown size");
+    if (sizeok != 1)
+    {	error(loc, "no size yet for forward reference");
+	//*(char*)0=0;
+    }
+    return structsize;
+}
+
+Type *AggregateDeclaration::getType()
+{
+    return type;
+}
+
+int AggregateDeclaration::isDeprecated()
+{
+    return isdeprecated;
+}
+
+/****************************
+ * Do byte or word alignment as necessary.
+ * Align sizes of 0, as we may not know array sizes yet.
+ */
+
+void AggregateDeclaration::alignmember(unsigned salign, unsigned size, unsigned *poffset)
+{
+    //printf("salign = %d, size = %d, offset = %d\n",salign,size,offset);
+    if (salign > 1)
+    {	int sa;
+
+	switch (size)
+	{   case 1:
+		break;
+	    case 2:
+	    case_2:
+		*poffset = (*poffset + 1) & ~1;	// align to word
+		break;
+	    case 3:
+	    case 4:
+		if (salign == 2)
+		    goto case_2;
+		*poffset = (*poffset + 3) & ~3;	// align to dword
+		break;
+	    default:
+		*poffset = (*poffset + salign - 1) & ~(salign - 1);
+		break;
+	}
+    }
+    //printf("result = %d\n",offset);
+}
+
+
+void AggregateDeclaration::addField(Scope *sc, VarDeclaration *v)
+{
+    unsigned memsize;		// size of member
+    unsigned memalignsize;	// size of member for alignment purposes
+    unsigned xalign;		// alignment boundaries
+
+    //printf("AggregateDeclaration::addField('%s') %s\n", v->toChars(), toChars());
+
+    // Check for forward referenced types which will fail the size() call
+    Type *t = v->type->toBasetype();
+    if (t->ty == Tstruct /*&& isStructDeclaration()*/)
+    {	TypeStruct *ts = (TypeStruct *)t;
+
+	if (ts->sym->sizeok != 1)
+	{
+	    sizeok = 2;		// cannot finish; flag as forward referenced
+	    return;
+	}
+    }
+    if (t->ty == Tident)
+    {
+	sizeok = 2;		// cannot finish; flag as forward referenced
+	return;
+    }
+
+    memsize = v->type->size(loc);
+    memalignsize = v->type->alignsize();
+    xalign = v->type->memalign(sc->structalign);
+    alignmember(xalign, memalignsize, &sc->offset);
+    v->offset = sc->offset;
+    sc->offset += memsize;
+    if (sc->offset > structsize)
+	structsize = sc->offset;
+    if (sc->structalign < memalignsize)
+	memalignsize = sc->structalign;
+    if (alignsize < memalignsize)
+	alignsize = memalignsize;
+    //printf("\talignsize = %d\n", alignsize);
+
+    v->storage_class |= STCfield;
+    //printf(" addField '%s' to '%s' at offset %d, size = %d\n", v->toChars(), toChars(), v->offset, memsize);
+    fields.push(v);
+}
+
+
+/********************************* StructDeclaration ****************************/
+
+StructDeclaration::StructDeclaration(Loc loc, Identifier *id)
+    : AggregateDeclaration(loc, id)
+{
+    zeroInit = 0;	// assume false until we do semantic processing
+
+    // For forward references
+    type = new TypeStruct(this);
+}
+
+Dsymbol *StructDeclaration::syntaxCopy(Dsymbol *s)
+{
+    StructDeclaration *sd;
+
+    if (s)
+	sd = (StructDeclaration *)s;
+    else
+	sd = new StructDeclaration(loc, ident);
+    ScopeDsymbol::syntaxCopy(sd);
+    return sd;
+}
+
+void StructDeclaration::semantic(Scope *sc)
+{   int i;
+    Scope *sc2;
+
+    //printf("+StructDeclaration::semantic(this=%p, '%s')\n", this, toChars());
+
+    //static int count; if (++count == 20) *(char*)0=0;
+
+    assert(type);
+    if (!members)			// if forward reference
+	return;
+
+    if (symtab)
+    {   if (!scope)
+            return;             // semantic() already completed
+    }
+    else
+        symtab = new DsymbolTable();
+
+    Scope *scx = NULL;
+    if (scope)
+    {   sc = scope;
+        scx = scope;            // save so we don't make redundant copies
+        scope = NULL;
+    }
+
+    parent = sc->parent;
+    handle = type->pointerTo();
+    structalign = sc->structalign;
+    protection = sc->protection;
+    assert(!isAnonymous());
+    if (sc->stc & STCabstract)
+	error("structs, unions cannot be abstract");
+
+    if (sizeok == 0)		// if not already done the addMember step
+    {
+	for (i = 0; i < members->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)members->data[i];
+	    //printf("adding member '%s' to '%s'\n", s->toChars(), this->toChars());
+	    s->addMember(sc, this, 1);
+	}
+    }
+
+    sizeok = 0;
+    sc2 = sc->push(this);
+    sc2->stc = 0;
+    sc2->parent = this;
+    if (isUnionDeclaration())
+	sc2->inunion = 1;
+    sc2->protection = PROTpublic;
+    sc2->explicitProtection = 0;
+
+    int members_dim = members->dim;
+    for (i = 0; i < members_dim; i++)
+    {
+	Dsymbol *s = (Dsymbol *)members->data[i];
+	s->semantic(sc2);
+	if (isUnionDeclaration())
+	    sc2->offset = 0;
+#if 0
+	if (sizeok == 2)
+	{   //printf("forward reference\n");
+	    break;
+	}
+#endif
+    }
+
+    /* The TypeInfo_Struct is expecting an opEquals and opCmp with
+     * a parameter that is a pointer to the struct. But if there
+     * isn't one, but is an opEquals or opCmp with a value, write
+     * another that is a shell around the value:
+     *	int opCmp(struct *p) { return opCmp(*p); }
+     */
+
+    TypeFunction *tfeqptr;
+    {
+	Arguments *arguments = new Arguments;
+	Argument *arg = new Argument(STCin, handle, Id::p, NULL);
+
+	arguments->push(arg);
+	tfeqptr = new TypeFunction(arguments, Type::tint32, 0, LINKd);
+	tfeqptr = (TypeFunction *)tfeqptr->semantic(0, sc);
+    }
+
+    TypeFunction *tfeq;
+    {
+	Arguments *arguments = new Arguments;
+	Argument *arg = new Argument(STCin, type, NULL, NULL);
+
+	arguments->push(arg);
+	tfeq = new TypeFunction(arguments, Type::tint32, 0, LINKd);
+	tfeq = (TypeFunction *)tfeq->semantic(0, sc);
+    }
+
+    Identifier *id = Id::eq;
+    for (int i = 0; i < 2; i++)
+    {
+	Dsymbol *s = search_function(this, id);
+	FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL;
+	if (fdx)
+	{   FuncDeclaration *fd = fdx->overloadExactMatch(tfeqptr);
+	    if (!fd)
+	    {	fd = fdx->overloadExactMatch(tfeq);
+		if (fd)
+		{   // Create the thunk, fdptr
+		    FuncDeclaration *fdptr = new FuncDeclaration(loc, loc, fdx->ident, STCundefined, tfeqptr);
+		    Expression *e = new IdentifierExp(loc, Id::p);
+		    e = new PtrExp(loc, e);
+		    Expressions *args = new Expressions();
+		    args->push(e);
+		    e = new IdentifierExp(loc, id);
+		    e = new CallExp(loc, e, args);
+		    fdptr->fbody = new ReturnStatement(loc, e);
+		    ScopeDsymbol *s = fdx->parent->isScopeDsymbol();
+		    assert(s);
+		    s->members->push(fdptr);
+		    fdptr->addMember(sc, s, 1);
+		    fdptr->semantic(sc2);
+		}
+	    }
+	}
+
+	id = Id::cmp;
+    }
+
+
+    sc2->pop();
+
+    if (sizeok == 2)
+    {	// semantic() failed because of forward references.
+	// Unwind what we did, and defer it for later
+	fields.setDim(0);
+	structsize = 0;
+	alignsize = 0;
+	structalign = 0;
+
+	scope = scx ? scx : new Scope(*sc);
+	scope->setNoFree();
+	scope->module->addDeferredSemantic(this);
+	//printf("\tdeferring %s\n", toChars());
+	return;
+    }
+
+    // 0 sized struct's are set to 1 byte
+    if (structsize == 0)
+    {
+	structsize = 1;
+	alignsize = 1;
+    }
+
+    // Round struct size up to next alignsize boundary.
+    // This will ensure that arrays of structs will get their internals
+    // aligned properly.
+    structsize = (structsize + alignsize - 1) & ~(alignsize - 1);
+
+    sizeok = 1;
+    Module::dprogress++;
+
+    //printf("-StructDeclaration::semantic(this=%p, '%s')\n", this, toChars());
+
+    // Determine if struct is all zeros or not
+    zeroInit = 1;
+    for (i = 0; i < fields.dim; i++)
+    {
+	Dsymbol *s = (Dsymbol *)fields.data[i];
+	VarDeclaration *vd = s->isVarDeclaration();
+	if (vd && !vd->isDataseg())
+	{
+	    if (vd->init)
+	    {
+		// Should examine init to see if it is really all 0's
+		zeroInit = 0;
+		break;
+	    }
+	    else
+	    {
+		if (!vd->type->isZeroInit())
+		{
+		    zeroInit = 0;
+		    break;
+		}
+	    }
+	}
+    }
+
+    /* Look for special member functions.
+     */
+    inv =    (InvariantDeclaration *)search(0, Id::classInvariant, 0);
+    aggNew =       (NewDeclaration *)search(0, Id::classNew,       0);
+    aggDelete = (DeleteDeclaration *)search(0, Id::classDelete,    0);
+
+    if (sc->func)
+    {
+	semantic2(sc);
+	semantic3(sc);
+    }
+}
+
+void StructDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{   int i;
+
+    buf->printf("%s ", kind());
+    if (!isAnonymous())
+	buf->writestring(toChars());
+    if (!members)
+    {
+	buf->writeByte(';');
+	buf->writenl();
+	return;
+    }
+    buf->writenl();
+    buf->writeByte('{');
+    buf->writenl();
+    for (i = 0; i < members->dim; i++)
+    {
+	Dsymbol *s = (Dsymbol *)members->data[i];
+
+	buf->writestring("    ");
+	s->toCBuffer(buf, hgs);
+    }
+    buf->writeByte('}');
+    buf->writenl();
+}
+
+
+char *StructDeclaration::kind()
+{
+    return "struct";
+}
+
+/********************************* UnionDeclaration ****************************/
+
+UnionDeclaration::UnionDeclaration(Loc loc, Identifier *id)
+    : StructDeclaration(loc, id)
+{
+}
+
+Dsymbol *UnionDeclaration::syntaxCopy(Dsymbol *s)
+{
+    UnionDeclaration *ud;
+
+    if (s)
+	ud = (UnionDeclaration *)s;
+    else
+	ud = new UnionDeclaration(loc, ident);
+    StructDeclaration::syntaxCopy(ud);
+    return ud;
+}
+
+
+char *UnionDeclaration::kind()
+{
+    return "union";
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/template.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,3959 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+// Handle template implementation
+
+#include <stdio.h>
+#include <assert.h>
+
+#if _WIN32
+#include <windows.h>
+long __cdecl __ehfilter(LPEXCEPTION_POINTERS ep);
+#endif
+
+#include "root.h"
+#include "mem.h"
+#include "stringtable.h"
+
+#include "mtype.h"
+#include "template.h"
+#include "init.h"
+#include "expression.h"
+#include "scope.h"
+#include "module.h"
+#include "aggregate.h"
+#include "declaration.h"
+#include "dsymbol.h"
+#include "mars.h"
+#include "dsymbol.h"
+#include "identifier.h"
+#include "hdrgen.h"
+
+#define LOG	0
+
+/********************************************
+ * These functions substitute for dynamic_cast. dynamic_cast does not work
+ * on earlier versions of gcc.
+ */
+
+Expression *isExpression(Object *o)
+{
+    //return dynamic_cast<Expression *>(o);
+    if (!o || o->dyncast() != DYNCAST_EXPRESSION)
+	return NULL;
+    return (Expression *)o;
+}
+
+Dsymbol *isDsymbol(Object *o)
+{
+    //return dynamic_cast<Dsymbol *>(o);
+    if (!o || o->dyncast() != DYNCAST_DSYMBOL)
+	return NULL;
+    return (Dsymbol *)o;
+}
+
+Type *isType(Object *o)
+{
+    //return dynamic_cast<Type *>(o);
+    if (!o || o->dyncast() != DYNCAST_TYPE)
+	return NULL;
+    return (Type *)o;
+}
+
+Tuple *isTuple(Object *o)
+{
+    //return dynamic_cast<Tuple *>(o);
+    if (!o || o->dyncast() != DYNCAST_TUPLE)
+	return NULL;
+    return (Tuple *)o;
+}
+
+/***********************
+ * Try to get arg as a type.
+ */
+
+Type *getType(Object *o)
+{
+    Type *t = isType(o);
+    if (!t)
+    {   Expression *e = isExpression(o);
+	if (e)
+	    t = e->type;
+    }
+    return t;
+}
+
+Dsymbol *getDsymbol(Object *oarg)
+{
+    Dsymbol *sa;
+    Expression *ea = isExpression(oarg);
+    if (ea)
+    {   // Try to convert Expression to symbol
+	if (ea->op == TOKvar)
+	    sa = ((VarExp *)ea)->var;
+	else if (ea->op == TOKfunction)
+	    sa = ((FuncExp *)ea)->fd;
+	else
+	    sa = NULL;
+    }
+    else
+    {   // Try to convert Type to symbol
+	Type *ta = isType(oarg);
+	if (ta)
+	    sa = ta->toDsymbol(NULL);
+	else
+	    sa = isDsymbol(oarg);	// if already a symbol
+    }
+    return sa;
+}
+
+/******************************
+ * If o1 matches o2, return 1.
+ * Else, return 0.
+ */
+
+int match(Object *o1, Object *o2, TemplateDeclaration *tempdecl, Scope *sc)
+{
+    Type *t1 = isType(o1);
+    Type *t2 = isType(o2);
+    Expression *e1 = isExpression(o1);
+    Expression *e2 = isExpression(o2);
+    Dsymbol *s1 = isDsymbol(o1);
+    Dsymbol *s2 = isDsymbol(o2);
+    Tuple *v1 = isTuple(o1);
+    Tuple *v2 = isTuple(o2);
+
+    /* A proper implementation of the various equals() overrides
+     * should make it possible to just do o1->equals(o2), but
+     * we'll do that another day.
+     */
+
+    if (t1)
+    {
+	/* if t1 is an instance of ti, then give error
+	 * about recursive expansions.
+	 */
+	Dsymbol *s = t1->toDsymbol(sc);
+	if (s && s->parent)
+	{   TemplateInstance *ti1 = s->parent->isTemplateInstance();
+	    if (ti1 && ti1->tempdecl == tempdecl)
+	    {
+		for (Scope *sc1 = sc; sc1; sc1 = sc1->enclosing)
+		{
+		    if (sc1->scopesym == ti1)
+		    {
+			error("recursive template expansion for template argument %s", t1->toChars());
+			return 1;	// fake a match
+		    }
+		}
+	    }
+	}
+
+	if (!t2 || !t1->equals(t2))
+	    goto L1;
+    }
+    else if (e1)
+    {
+#if 0
+	if (e1 && e2)
+	{
+	    printf("match %d\n", e1->equals(e2));
+	    e1->print();
+	    e2->print();
+	}
+#endif
+	if (!e2 || !e1->equals(e2))
+	    goto L1;
+    }
+    else if (s1)
+    {
+	//printf("%p %s, %p %s\n", s1, s1->toChars(), s2, s2->toChars());
+	if (!s2 || !s1->equals(s2) || s1->parent != s2->parent)
+	    goto L1;
+    }
+    else if (v1)
+    {
+	if (!v2)
+	    goto L1;
+	if (v1->objects.dim != v2->objects.dim)
+	    goto L1;
+	for (size_t i = 0; i < v1->objects.dim; i++)
+	{
+	    if (!match((Object *)v1->objects.data[i],
+		       (Object *)v2->objects.data[i],
+		       tempdecl, sc))
+		goto L1;
+	}
+    }
+    return 1;	// match
+L1:
+    return 0;	// nomatch;
+}
+
+/****************************************
+ */
+
+void ObjectToCBuffer(OutBuffer *buf, HdrGenState *hgs, Object *oarg)
+{
+    Type *t = isType(oarg);
+    Expression *e = isExpression(oarg);
+    Dsymbol *s = isDsymbol(oarg);
+    Tuple *v = isTuple(oarg);
+    if (t)
+	t->toCBuffer(buf, NULL, hgs);
+    else if (e)
+	e->toCBuffer(buf, hgs);
+    else if (s)
+    {
+	char *p = s->ident ? s->ident->toChars() : s->toChars();
+	buf->writestring(p);
+    }
+    else if (v)
+    {
+	Objects *args = &v->objects;
+	for (size_t i = 0; i < args->dim; i++)
+	{
+	    if (i)
+		buf->writeByte(',');
+	    Object *o = (Object *)args->data[i];
+	    ObjectToCBuffer(buf, hgs, o);
+	}
+    }
+    else if (!oarg)
+    {
+	buf->writestring("NULL");
+    }
+    else
+    {
+#ifdef DEBUG
+	printf("bad Object = %p\n", oarg);
+#endif
+	assert(0);
+    }
+}
+
+
+
+/* ======================== TemplateDeclaration ============================= */
+
+TemplateDeclaration::TemplateDeclaration(Loc loc, Identifier *id, TemplateParameters *parameters, Array *decldefs)
+    : ScopeDsymbol(id)
+{
+#if LOG
+    printf("TemplateDeclaration(this = %p, id = '%s')\n", this, id->toChars());
+#endif
+#if 0
+    if (parameters)
+	for (int i = 0; i < parameters->dim; i++)
+	{   TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+	    //printf("\tparameter[%d] = %p\n", i, tp);
+	    TemplateTypeParameter *ttp = tp->isTemplateTypeParameter();
+
+	    if (ttp)
+	    {
+		printf("\tparameter[%d] = %s : %s\n", i, tp->ident->toChars(), ttp->specType ? ttp->specType->toChars() : "");
+	    }
+	}
+#endif
+    this->loc = loc;
+    this->parameters = parameters;
+    this->members = decldefs;
+    this->overnext = NULL;
+    this->overroot = NULL;
+    this->scope = NULL;
+    this->onemember = NULL;
+}
+
+Dsymbol *TemplateDeclaration::syntaxCopy(Dsymbol *)
+{
+    //printf("TemplateDeclaration::syntaxCopy()\n");
+    TemplateDeclaration *td;
+    TemplateParameters *p;
+    Array *d;
+
+    p = NULL;
+    if (parameters)
+    {
+	p = new TemplateParameters();
+	p->setDim(parameters->dim);
+	for (int i = 0; i < p->dim; i++)
+	{   TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+	    p->data[i] = (void *)tp->syntaxCopy();
+	}
+    }
+    d = Dsymbol::arraySyntaxCopy(members);
+    td = new TemplateDeclaration(loc, ident, p, d);
+    return td;
+}
+
+void TemplateDeclaration::semantic(Scope *sc)
+{
+#if LOG
+    printf("TemplateDeclaration::semantic(this = %p, id = '%s')\n", this, ident->toChars());
+#endif
+    if (scope)
+	return;		// semantic() already run
+
+    if (sc->func)
+    {
+	error("cannot declare template at function scope %s", sc->func->toChars());
+    }
+
+    if (/*global.params.useArrayBounds &&*/ sc->module)
+    {
+	// Generate this function as it may be used
+	// when template is instantiated in other modules
+	sc->module->toModuleArray();
+    }
+
+    if (/*global.params.useAssert &&*/ sc->module)
+    {
+	// Generate this function as it may be used
+	// when template is instantiated in other modules
+	sc->module->toModuleAssert();
+    }
+
+    /* Remember Scope for later instantiations, but make
+     * a copy since attributes can change.
+     */
+    this->scope = new Scope(*sc);
+    this->scope->setNoFree();
+
+    // Set up scope for parameters
+    ScopeDsymbol *paramsym = new ScopeDsymbol();
+    paramsym->parent = sc->parent;
+    Scope *paramscope = sc->push(paramsym);
+    paramscope->parameterSpecialization = 1;
+
+    for (int i = 0; i < parameters->dim; i++)
+    {
+	TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+
+	tp->declareParameter(paramscope);
+    }
+
+    for (int i = 0; i < parameters->dim; i++)
+    {
+	TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+
+	tp->semantic(paramscope);
+    }
+
+    paramscope->pop();
+
+    if (members)
+    {
+	Dsymbol *s;
+	if (Dsymbol::oneMembers(members, &s))
+	{
+	    if (s && s->ident && s->ident->equals(ident))
+	    {
+		onemember = s;
+		s->parent = this;
+	    }
+	}
+    }
+
+    /* BUG: should check:
+     *	o no virtual functions or non-static data members of classes
+     */
+}
+
+char *TemplateDeclaration::kind()
+{
+    return (onemember && onemember->isAggregateDeclaration())
+		? onemember->kind()
+		: (char *)"template";
+}
+
+/**********************************
+ * Overload existing TemplateDeclaration 'this' with the new one 's'.
+ * Return !=0 if successful; i.e. no conflict.
+ */
+
+int TemplateDeclaration::overloadInsert(Dsymbol *s)
+{
+    TemplateDeclaration **pf;
+    TemplateDeclaration *f;
+
+#if LOG
+    printf("TemplateDeclaration::overloadInsert('%s')\n", s->toChars());
+#endif
+    f = s->isTemplateDeclaration();
+    if (!f)
+	return FALSE;
+    TemplateDeclaration *pthis = this;
+    for (pf = &pthis; *pf; pf = &(*pf)->overnext)
+    {
+#if 0
+	// Conflict if TemplateParameter's match
+	// Will get caught anyway later with TemplateInstance, but
+	// should check it now.
+	TemplateDeclaration *f2 = *pf;
+
+	if (f->parameters->dim != f2->parameters->dim)
+	    goto Lcontinue;
+
+	for (int i = 0; i < f->parameters->dim; i++)
+	{   TemplateParameter *p1 = (TemplateParameter *)f->parameters->data[i];
+	    TemplateParameter *p2 = (TemplateParameter *)f2->parameters->data[i];
+
+	    if (!p1->overloadMatch(p2))
+		goto Lcontinue;
+	}
+
+#if LOG
+	printf("\tfalse: conflict\n");
+#endif
+	return FALSE;
+
+     Lcontinue:
+	;
+#endif
+    }
+
+    f->overroot = this;
+    *pf = f;
+#if LOG
+    printf("\ttrue: no conflict\n");
+#endif
+    return TRUE;
+}
+
+/***************************************
+ * Given that ti is an instance of this TemplateDeclaration,
+ * deduce the types of the parameters to this, and store
+ * those deduced types in dedtypes[].
+ * Input:
+ *	flag	1: don't do semantic() because of dummy types
+ * Output:
+ *	dedtypes	deduced arguments
+ * Return match level.
+ */
+
+MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti,
+	Objects *dedtypes, int flag)
+{   MATCH m;
+    int dedtypes_dim = dedtypes->dim;
+
+#if LOG
+    printf("+TemplateDeclaration::matchWithInstance(this = %p, ti = %p, flag = %d)\n", this, ti, flag);
+#endif
+
+#if 0
+    printf("dedtypes->dim = %d, parameters->dim = %d\n", dedtypes_dim, parameters->dim);
+    if (ti->tiargs->dim)
+	printf("ti->tiargs->dim = %d, [0] = %p\n",
+	    ti->tiargs->dim,
+	    ti->tiargs->data[0]);
+#endif
+    dedtypes->zero();
+
+    int parameters_dim = parameters->dim;
+    int variadic = isVariadic() != NULL;
+
+    // If more arguments than parameters, no match
+    if (ti->tiargs->dim > parameters_dim && !variadic)
+    {
+#if LOG
+	printf(" no match: more arguments than parameters\n");
+#endif
+	return MATCHnomatch;
+    }
+
+    assert(dedtypes_dim == parameters_dim);
+    assert(dedtypes_dim >= ti->tiargs->dim || variadic);
+
+    // Set up scope for parameters
+    assert((size_t)scope > 0x10000);
+    ScopeDsymbol *paramsym = new ScopeDsymbol();
+    paramsym->parent = scope->parent;
+    Scope *paramscope = scope->push(paramsym);
+
+    // Attempt type deduction
+    m = MATCHexact;
+    for (int i = 0; i < dedtypes_dim; i++)
+    {	MATCH m2;
+	TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+	Declaration *sparam;
+
+	//printf("\targument [%d]\n", i);
+#if 0
+	printf("\targument [%d] is %s\n", i, oarg ? oarg->toChars() : "null");
+	TemplateTypeParameter *ttp = tp->isTemplateTypeParameter();
+	if (ttp)
+	    printf("\tparameter[%d] is %s : %s\n", i, tp->ident->toChars(), ttp->specType ? ttp->specType->toChars() : "");
+#endif
+
+	m2 = tp->matchArg(paramscope, ti->tiargs, i, parameters, dedtypes, &sparam);
+
+	if (m2 == MATCHnomatch)
+	{
+#if 0
+	    printf("\tmatchArg() for parameter %i failed\n", i);
+#endif
+	    goto Lnomatch;
+	}
+
+	if (m2 < m)
+	    m = m2;
+
+	if (!flag)
+	    sparam->semantic(paramscope);
+	if (!paramscope->insert(sparam))
+	    goto Lnomatch;
+    }
+
+    if (!flag)
+    {
+	// Any parameter left without a type gets the type of its corresponding arg
+	for (int i = 0; i < dedtypes_dim; i++)
+	{
+	    if (!dedtypes->data[i])
+	    {   assert(i < ti->tiargs->dim);
+		dedtypes->data[i] = ti->tiargs->data[i];
+	    }
+	}
+    }
+
+#if 0
+    // Print out the results
+    printf("--------------------------\n");
+    printf("template %s\n", toChars());
+    printf("instance %s\n", ti->toChars());
+    if (m)
+    {
+	for (int i = 0; i < dedtypes_dim; i++)
+	{
+	    TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+	    Object *oarg;
+
+	    printf(" [%d]", i);
+
+	    if (i < ti->tiargs->dim)
+		oarg = (Object *)ti->tiargs->data[i];
+	    else
+		oarg = NULL;
+	    tp->print(oarg, (Object *)dedtypes->data[i]);
+	}
+    }
+    else
+	goto Lnomatch;
+#endif
+
+#if LOG
+    printf(" match = %d\n", m);
+#endif
+    goto Lret;
+
+Lnomatch:
+#if LOG
+    printf(" no match\n");
+#endif
+    m = MATCHnomatch;
+
+Lret:
+    paramscope->pop();
+#if LOG
+    printf("-TemplateDeclaration::matchWithInstance(this = %p, ti = %p) = %d\n", this, ti, m);
+#endif
+    return m;
+}
+
+/********************************************
+ * Determine partial specialization order of 'this' vs td2.
+ * Returns:
+ *	1	this is at least as specialized as td2
+ *	0	td2 is more specialized than this
+ */
+
+int TemplateDeclaration::leastAsSpecialized(TemplateDeclaration *td2)
+{
+    /* This works by taking the template parameters to this template
+     * declaration and feeding them to td2 as if it were a template
+     * instance.
+     * If it works, then this template is at least as specialized
+     * as td2.
+     */
+
+    TemplateInstance ti(0, ident);		// create dummy template instance
+    Objects dedtypes;
+
+#define LOG_LEASTAS	0
+
+#if LOG_LEASTAS
+    printf("%s.leastAsSpecialized(%s)\n", toChars(), td2->toChars());
+#endif
+
+    // Set type arguments to dummy template instance to be types
+    // generated from the parameters to this template declaration
+    ti.tiargs = new Objects();
+    ti.tiargs->setDim(parameters->dim);
+    for (int i = 0; i < ti.tiargs->dim; i++)
+    {
+	TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+
+	void *p = tp->dummyArg();
+	if (p)
+	    ti.tiargs->data[i] = p;
+	else
+	    ti.tiargs->setDim(i);
+    }
+
+    // Temporary Array to hold deduced types
+    //dedtypes.setDim(parameters->dim);
+    dedtypes.setDim(td2->parameters->dim);
+
+    // Attempt a type deduction
+    if (td2->matchWithInstance(&ti, &dedtypes, 1))
+    {
+	/* A non-variadic template is more specialized than a
+	 * variadic one.
+	 */
+	if (isVariadic() && !td2->isVariadic())
+	    goto L1;
+
+#if LOG_LEASTAS
+	printf("  matches, so is least as specialized\n");
+#endif
+	return 1;
+    }
+  L1:
+#if LOG_LEASTAS
+    printf("  doesn't match, so is not as specialized\n");
+#endif
+    return 0;
+}
+
+
+/*************************************************
+ * Match function arguments against a specific template function.
+ * Input:
+ *	targsi		Expression/Type initial list of template arguments
+ *	fargs		arguments to function
+ * Output:
+ *	dedargs		Expression/Type deduced template arguments
+ */
+
+MATCH TemplateDeclaration::deduceMatch(Objects *targsi, Expressions *fargs,
+	Objects *dedargs)
+{
+    size_t i;
+    size_t nfparams;
+    size_t nfparams2;
+    size_t nfargs;
+    size_t nargsi;
+    MATCH match = MATCHexact;
+    FuncDeclaration *fd = onemember->toAlias()->isFuncDeclaration();
+    TypeFunction *fdtype;
+    TemplateTupleParameter *tp;
+    Objects dedtypes;	// for T:T*, the dedargs is the T*, dedtypes is the T
+
+#if 0
+    printf("\nTemplateDeclaration::deduceMatch() %s\n", toChars());
+    for (i = 0; i < fargs->dim; i++)
+    {	Expression *e = (Expression *)fargs->data[i];
+	printf("\tfarg[%d] is %s, type is %s\n", i, e->toChars(), e->type->toChars());
+    }
+#endif
+
+    assert((size_t)scope > 0x10000);
+
+    dedargs->setDim(parameters->dim);
+    dedargs->zero();
+
+    dedtypes.setDim(parameters->dim);
+    dedtypes.zero();
+
+    // Set up scope for parameters
+    ScopeDsymbol *paramsym = new ScopeDsymbol();
+    paramsym->parent = scope->parent;
+    Scope *paramscope = scope->push(paramsym);
+
+    nargsi = 0;
+    if (targsi)
+    {	// Set initial template arguments
+
+	nargsi = targsi->dim;
+	if (nargsi > parameters->dim)
+	    goto Lnomatch;
+
+	memcpy(dedargs->data, targsi->data, nargsi * sizeof(*dedargs->data));
+
+	for (i = 0; i < nargsi; i++)
+	{   TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+	    MATCH m;
+	    Declaration *sparam;
+
+	    m = tp->matchArg(paramscope, dedargs, i, parameters, &dedtypes, &sparam);
+	    if (m == MATCHnomatch)
+		goto Lnomatch;
+	    if (m < match)
+		match = m;
+
+	    sparam->semantic(paramscope);
+	    if (!paramscope->insert(sparam))
+		goto Lnomatch;
+	}
+    }
+
+    assert(fd->type->ty == Tfunction);
+    fdtype = (TypeFunction *)fd->type;
+
+    nfparams = Argument::dim(fdtype->parameters); // number of function parameters
+    nfparams2 = nfparams;
+    nfargs = fargs->dim;		// number of function arguments
+
+    /* Check for match of function arguments with variadic template
+     * parameter, such as:
+     *
+     * template Foo(T, A...) { void Foo(T t, A a); }
+     * void main() { Foo(1,2,3); }
+     */
+    tp = isVariadic();
+    if (tp)
+    {
+	if (nfparams == 0)		// if no function parameters
+	{
+	    Tuple *t = new Tuple();
+	    //printf("t = %p\n", t);
+	    dedargs->data[parameters->dim - 1] = (void *)t;
+	    goto L2;
+	}
+	else if (nfargs < nfparams - 1)
+	    goto L1;
+	else
+	{
+	    /* See if 'A' of the template parameter matches 'A'
+	     * of the type of the last function parameter.
+	     */
+	    Argument *fparam = (Argument *)fdtype->parameters->data[nfparams - 1];
+	    if (fparam->type->ty != Tident)
+		goto L1;
+	    TypeIdentifier *tid = (TypeIdentifier *)fparam->type;
+	    if (!tp->ident->equals(tid->ident) || tid->idents.dim)
+		goto L1;
+
+	    if (fdtype->varargs)	// variadic function doesn't
+		goto Lnomatch;		// go with variadic template
+
+	    /* The types of the function arguments [nfparams - 1 .. nfargs]
+	     * now form the tuple argument.
+	     */
+	    Tuple *t = new Tuple();
+	    dedargs->data[parameters->dim - 1] = (void *)t;
+
+	    int tuple_dim = nfargs - (nfparams - 1);
+	    t->objects.setDim(tuple_dim);
+	    for (i = 0; i < tuple_dim; i++)
+	    {	Expression *farg = (Expression *)fargs->data[nfparams - 1 + i];
+		t->objects.data[i] = (void *)farg->type;
+	    }
+	    nfparams2--;	// don't consider the last parameter for type deduction
+	    goto L2;
+	}
+    }
+
+L1:
+    if (nfparams == nfargs)
+	;
+    else if (nfargs > nfparams)
+    {
+	if (fdtype->varargs == 0)
+	    goto Lnomatch;		// too many args, no match
+	match = MATCHconvert;		// match ... with a conversion
+    }
+
+L2:
+    // Loop through the function parameters
+    for (i = 0; i < nfparams2; i++)
+    {
+	Argument *fparam = Argument::getNth(fdtype->parameters, i);
+	Expression *farg;
+	MATCH m;
+
+	if (i >= nfargs)		// if not enough arguments
+	{
+	    if (fparam->defaultArg)
+	    {	/* Default arguments do not participate in template argument
+		 * deduction.
+		 */
+		goto Lmatch;
+	    }
+	}
+	else
+	{   farg = (Expression *)fargs->data[i];
+#if 0
+	    printf("\tfarg->type   = %s\n", farg->type->toChars());
+	    printf("\tfparam->type = %s\n", fparam->type->toChars());
+#endif
+
+	    m = farg->type->deduceType(scope, fparam->type, parameters, &dedtypes);
+	    //printf("\tdeduceType m = %d\n", m);
+
+	    /* If no match, see if there's a conversion to a delegate
+	     */
+	    if (!m && fparam->type->toBasetype()->ty == Tdelegate)
+	    {
+		TypeDelegate *td = (TypeDelegate *)fparam->type->toBasetype();
+		TypeFunction *tf = (TypeFunction *)td->nextOf();
+
+		if (!tf->varargs && Argument::dim(tf->parameters) == 0)
+		{
+		    m = farg->type->deduceType(scope, tf->nextOf(), parameters, &dedtypes);
+		    if (!m && tf->nextOf()->toBasetype()->ty == Tvoid)
+			m = MATCHconvert;
+		}
+		//printf("\tm2 = %d\n", m);
+	    }
+
+	    if (m)
+	    {	if (m < match)
+		    match = m;		// pick worst match
+		continue;
+	    }
+	}
+	if (!(fdtype->varargs == 2 && i + 1 == nfparams))
+	    goto Lnomatch;
+
+	/* Check for match with function parameter T...
+	 */
+	Type *t = fparam->type;
+	switch (t->ty)
+	{
+	    // Perhaps we can do better with this, see TypeFunction::callMatch()
+	    case Tsarray:
+	    case Tarray:
+	    case Tclass:
+	    case Tident:
+		goto Lmatch;
+
+	    default:
+		goto Lnomatch;
+	}
+    }
+
+Lmatch:
+
+    /* Fill in any missing arguments with their defaults.
+     */
+    for (i = nargsi; i < dedargs->dim; i++)
+    {
+	TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+	Object *oarg = (Object *)dedargs->data[i];
+	Object *o = (Object *)dedtypes.data[i];
+	//printf("1dedargs[%d] = %p, dedtypes[%d] = %p\n", i, oarg, i, o);
+	if (!oarg)
+	{
+	    if (o)
+	    {
+		if (tp->specialization())
+		    error("specialization not allowed for deduced parameter %s", tp->ident->toChars());
+	    }
+	    else
+	    {	o = tp->defaultArg(paramscope);
+		if (!o)
+		    goto Lnomatch;
+#if 0
+		Match m;
+		Declaration *sparam;
+		m = tp->matchArg(paramscope, dedargs, i, parameters, &sparam);
+		if (!m)
+		    goto Lnomatch;
+#endif
+	    }
+	    declareParameter(paramscope, tp, o);
+	    dedargs->data[i] = (void *)o;
+	}
+    }
+
+#if 0
+    for (i = 0; i < dedargs->dim; i++)
+    {	Type *t = (Type *)dedargs->data[i];
+	printf("\tdedargs[%d] = %d, %s\n", i, t->dyncast(), t->toChars());
+    }
+#endif
+
+    paramscope->pop();
+    //printf("\tmatch\n");
+    return match;
+
+Lnomatch:
+    paramscope->pop();
+    //printf("\tnomatch\n");
+    return MATCHnomatch;
+}
+
+/**************************************************
+ * Declare template parameter tp with value o.
+ */
+
+void TemplateDeclaration::declareParameter(Scope *sc, TemplateParameter *tp, Object *o)
+{
+    //printf("TemplateDeclaration::declareParameter('%s', o = %p)\n", tp->ident->toChars(), o);
+
+    Type *targ = isType(o);
+    Expression *ea = isExpression(o);
+    Dsymbol *sa = isDsymbol(o);
+    Tuple *va = isTuple(o);
+
+    Dsymbol *s;
+
+    if (targ)
+    {
+	//printf("type %s\n", targ->toChars());
+	s = new AliasDeclaration(0, tp->ident, targ);
+    }
+    else if (sa)
+    {
+	//printf("Alias %s %s;\n", sa->ident->toChars(), tp->ident->toChars());
+	s = new AliasDeclaration(0, tp->ident, sa);
+    }
+    else if (ea)
+    {
+	// tdtypes.data[i] always matches ea here
+	Initializer *init = new ExpInitializer(loc, ea);
+	TemplateValueParameter *tvp = tp->isTemplateValueParameter();
+	assert(tvp);
+
+	VarDeclaration *v = new VarDeclaration(0, tvp->valType, tp->ident, init);
+	v->storage_class = STCconst;
+	s = v;
+    }
+    else if (va)
+    {
+	//printf("\ttuple\n");
+	s = new TupleDeclaration(loc, tp->ident, &va->objects);
+    }
+    else
+    {
+#ifdef DEBUG
+	o->print();
+#endif
+	assert(0);
+    }
+    if (!sc->insert(s))
+	error("declaration %s is already defined", tp->ident->toChars());
+    s->semantic(sc);
+}
+
+/**************************************
+ * Determine if TemplateDeclaration is variadic.
+ */
+
+TemplateTupleParameter *isVariadic(TemplateParameters *parameters)
+{   size_t dim = parameters->dim;
+    TemplateTupleParameter *tp = NULL;
+
+    if (dim)
+	tp = ((TemplateParameter *)parameters->data[dim - 1])->isTemplateTupleParameter();
+    return tp;
+}
+
+TemplateTupleParameter *TemplateDeclaration::isVariadic()
+{
+    return ::isVariadic(parameters);
+}
+
+/*************************************************
+ * Given function arguments, figure out which template function
+ * to expand, and return that function.
+ * If no match, give error message and return NULL.
+ * Input:
+ *	targsi		initial list of template arguments
+ *	fargs		arguments to function
+ */
+
+FuncDeclaration *TemplateDeclaration::deduce(Scope *sc, Loc loc,
+	Objects *targsi, Expressions *fargs)
+{
+    MATCH m_best = MATCHnomatch;
+    TemplateDeclaration *td_ambig = NULL;
+    TemplateDeclaration *td_best = NULL;
+    Objects *tdargs = new Objects();
+    TemplateInstance *ti;
+    FuncDeclaration *fd;
+
+#if 0
+    printf("TemplateDeclaration::deduce() %s\n", toChars());
+    printf("    targsi:\n");
+    if (targsi)
+    {	for (int i = 0; i < targsi->dim; i++)
+	{   Object *arg = (Object *)targsi->data[i];
+	    printf("\t%s\n", arg->toChars());
+	}
+    }
+    printf("    fargs:\n");
+    for (int i = 0; i < fargs->dim; i++)
+    {	Expression *arg = (Expression *)fargs->data[i];
+	printf("\t%s %s\n", arg->type->toChars(), arg->toChars());
+	//printf("\tty = %d\n", arg->type->ty);
+    }
+#endif
+
+    for (TemplateDeclaration *td = this; td; td = td->overnext)
+    {
+	if (!td->scope)
+	{
+	    error("forward reference to template %s", td->toChars());
+	    goto Lerror;
+	}
+	if (!td->onemember || !td->onemember->toAlias()->isFuncDeclaration())
+	{
+	    error("is not a function template");
+	    goto Lerror;
+	}
+
+	MATCH m;
+	Objects dedargs;
+
+	m = td->deduceMatch(targsi, fargs, &dedargs);
+	//printf("deduceMatch = %d\n", m);
+	if (!m)			// if no match
+	    continue;
+
+	if (m < m_best)
+	    goto Ltd_best;
+	if (m > m_best)
+	    goto Ltd;
+
+	{
+	// Disambiguate by picking the most specialized TemplateDeclaration
+	int c1 = td->leastAsSpecialized(td_best);
+	int c2 = td_best->leastAsSpecialized(td);
+	//printf("c1 = %d, c2 = %d\n", c1, c2);
+
+	if (c1 && !c2)
+	    goto Ltd;
+	else if (!c1 && c2)
+	    goto Ltd_best;
+	else
+	    goto Lambig;
+	}
+
+      Lambig:		// td_best and td are ambiguous
+	td_ambig = td;
+	continue;
+
+      Ltd_best:		// td_best is the best match so far
+	td_ambig = NULL;
+	continue;
+
+      Ltd:		// td is the new best match
+	td_ambig = NULL;
+	assert((size_t)td->scope > 0x10000);
+	td_best = td;
+	m_best = m;
+	tdargs->setDim(dedargs.dim);
+	memcpy(tdargs->data, dedargs.data, tdargs->dim * sizeof(void *));
+	continue;
+    }
+    if (!td_best)
+    {
+	error(loc, "does not match any template declaration");
+	goto Lerror;
+    }
+    if (td_ambig)
+    {
+	error(loc, "%s matches more than one function template declaration, %s and %s",
+		toChars(), td_best->toChars(), td_ambig->toChars());
+    }
+
+    /* The best match is td_best with arguments tdargs.
+     * Now instantiate the template.
+     */
+    assert((size_t)td_best->scope > 0x10000);
+    ti = new TemplateInstance(loc, td_best, tdargs);
+    ti->semantic(sc);
+    fd = ti->toAlias()->isFuncDeclaration();
+    if (!fd)
+	goto Lerror;
+    return fd;
+
+  Lerror:
+    {
+	OutBuffer buf;
+	HdrGenState hgs;
+
+	argExpTypesToCBuffer(&buf, fargs, &hgs);
+	error(loc, "cannot deduce template function from argument types (%s)",
+		buf.toChars());
+	return NULL;
+    }
+}
+
+void TemplateDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+#if 0 // Should handle template functions
+    if (onemember && onemember->isFuncDeclaration())
+	buf->writestring("foo ");
+#endif
+    buf->writestring(kind());
+    buf->writeByte(' ');
+    buf->writestring(ident->toChars());
+    buf->writeByte('(');
+    for (int i = 0; i < parameters->dim; i++)
+    {
+	TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+	if (i)
+	    buf->writeByte(',');
+	tp->toCBuffer(buf, hgs);
+    }
+    buf->writeByte(')');
+
+    if (hgs->hdrgen)
+    {
+	hgs->tpltMember++;
+	buf->writenl();
+	buf->writebyte('{');
+	buf->writenl();
+	for (int i = 0; i < members->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)members->data[i];
+	    s->toCBuffer(buf, hgs);
+	}
+	buf->writebyte('}');
+	buf->writenl();
+	hgs->tpltMember--;
+    }
+}
+
+
+char *TemplateDeclaration::toChars()
+{   OutBuffer buf;
+    HdrGenState hgs;
+
+    memset(&hgs, 0, sizeof(hgs));
+    buf.writestring(ident->toChars());
+    buf.writeByte('(');
+    for (int i = 0; i < parameters->dim; i++)
+    {
+	TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+	if (i)
+	    buf.writeByte(',');
+	tp->toCBuffer(&buf, &hgs);
+    }
+    buf.writeByte(')');
+    buf.writeByte(0);
+    return (char *)buf.extractData();
+}
+
+/* ======================== Type ============================================ */
+
+/****
+ * Given an identifier, figure out which TemplateParameter it is.
+ * Return -1 if not found.
+ */
+
+int templateParameterLookup(Type *tparam, TemplateParameters *parameters)
+{
+    assert(tparam->ty == Tident);
+    TypeIdentifier *tident = (TypeIdentifier *)tparam;
+    //printf("\ttident = '%s'\n", tident->toChars());
+    if (tident->idents.dim == 0)
+    {
+	Identifier *id = tident->ident;
+
+	for (size_t i = 0; i < parameters->dim; i++)
+	{   TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+
+	    if (tp->ident->equals(id))
+		return i;
+	}
+    }
+    return -1;
+}
+
+/* These form the heart of template argument deduction.
+ * Given 'this' being the type argument to the template instance,
+ * it is matched against the template declaration parameter specialization
+ * 'tparam' to determine the type to be used for the parameter.
+ * Example:
+ *	template Foo(T:T*)	// template declaration
+ *	Foo!(int*)		// template instantiation
+ * Input:
+ *	this = int*
+ *	tparam = T
+ *	parameters = [ T:T* ]	// Array of TemplateParameter's
+ * Output:
+ *	dedtypes = [ int ]	// Array of Expression/Type's
+ */
+
+MATCH Type::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters,
+	Objects *dedtypes)
+{
+    //printf("Type::deduceType()\n");
+    //printf("\tthis   = %d, ", ty); print();
+    //printf("\ttparam = %d, ", tparam->ty); tparam->print();
+    if (!tparam)
+	goto Lnomatch;
+
+    if (this == tparam)
+	goto Lexact;
+
+    if (tparam->ty == Tident)
+    {
+	// Determine which parameter tparam is
+	int i = templateParameterLookup(tparam, parameters);
+	if (i == -1)
+	{
+	    if (!sc)
+		goto Lnomatch;
+	    /* BUG: what if tparam is a template instance, that
+	     * has as an argument another Tident?
+	     */
+	    tparam = tparam->semantic(0, sc);
+	    assert(tparam->ty != Tident);
+	    return deduceType(sc, tparam, parameters, dedtypes);
+	}
+
+	TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+
+	// Found the corresponding parameter tp
+	if (!tp->isTemplateTypeParameter())
+	    goto Lnomatch;
+	Type *at = (Type *)dedtypes->data[i];
+	if (!at)
+	{
+	    dedtypes->data[i] = (void *)this;
+	    goto Lexact;
+	}
+	if (equals(at))
+	    goto Lexact;
+	else if (ty == Tclass && at->ty == Tclass)
+	{
+	    return (MATCH) implicitConvTo(at);
+	}
+	else if (ty == Tsarray && at->ty == Tarray &&
+	    next->equals(at->nextOf()))
+	{
+	    goto Lexact;
+	}
+	else
+	    goto Lnomatch;
+    }
+
+    if (ty != tparam->ty)
+	goto Lnomatch;
+
+    if (nextOf())
+	return nextOf()->deduceType(sc, tparam->nextOf(), parameters, dedtypes);
+
+Lexact:
+    return MATCHexact;
+
+Lnomatch:
+    return MATCHnomatch;
+}
+
+MATCH TypeSArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters,
+	Objects *dedtypes)
+{
+#if 0
+    printf("TypeSArray::deduceType()\n");
+    printf("\tthis   = %d, ", ty); print();
+    printf("\ttparam = %d, ", tparam->ty); tparam->print();
+#endif
+
+    // Extra check that array dimensions must match
+    if (tparam)
+    {
+	if (tparam->ty == Tsarray)
+	{
+	    TypeSArray *tp = (TypeSArray *)tparam;
+	    if (dim->toInteger() != tp->dim->toInteger())
+		return MATCHnomatch;
+	}
+	else if (tparam->ty == Taarray)
+	{
+	    TypeAArray *tp = (TypeAArray *)tparam;
+	    if (tp->index->ty == Tident)
+	    {	TypeIdentifier *tident = (TypeIdentifier *)tp->index;
+
+		if (tident->idents.dim == 0)
+		{   Identifier *id = tident->ident;
+
+		    for (size_t i = 0; i < parameters->dim; i++)
+		    {
+			TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+
+			if (tp->ident->equals(id))
+			{   // Found the corresponding template parameter
+			    TemplateValueParameter *tvp = tp->isTemplateValueParameter();
+			    if (!tvp || !tvp->valType->isintegral())
+				goto Lnomatch;
+
+			    if (dedtypes->data[i])
+			    {
+				if (!dim->equals((Object *)dedtypes->data[i]))
+				    goto Lnomatch;
+			    }
+			    else
+			    {	dedtypes->data[i] = (void *)dim;
+			    }
+			    return next->deduceType(sc, tparam->nextOf(), parameters, dedtypes);
+			}
+		    }
+		}
+	    }
+	}
+	else if (tparam->ty == Tarray)
+	{   MATCH m;
+
+	    m = next->deduceType(sc, tparam->nextOf(), parameters, dedtypes);
+	    if (m == MATCHexact)
+		m = MATCHconvert;
+	    return m;
+	}
+    }
+    return Type::deduceType(sc, tparam, parameters, dedtypes);
+
+  Lnomatch:
+    return MATCHnomatch;
+}
+
+MATCH TypeAArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes)
+{
+    //printf("TypeAArray::deduceType()\n");
+    //printf("\tthis   = %d, ", ty); print();
+    //printf("\ttparam = %d, ", tparam->ty); tparam->print();
+
+    // Extra check that index type must match
+    if (tparam && tparam->ty == Taarray)
+    {
+	TypeAArray *tp = (TypeAArray *)tparam;
+	if (!index->deduceType(sc, tp->index, parameters, dedtypes))
+	{
+	    return MATCHnomatch;
+	}
+    }
+    return Type::deduceType(sc, tparam, parameters, dedtypes);
+}
+
+MATCH TypeFunction::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes)
+{
+    //printf("TypeFunction::deduceType()\n");
+    //printf("\tthis   = %d, ", ty); print();
+    //printf("\ttparam = %d, ", tparam->ty); tparam->print();
+
+    // Extra check that function characteristics must match
+    if (tparam && tparam->ty == Tfunction)
+    {
+	TypeFunction *tp = (TypeFunction *)tparam;
+	if (varargs != tp->varargs ||
+	    linkage != tp->linkage)
+	    return MATCHnomatch;
+
+	size_t nfargs = Argument::dim(this->parameters);
+	size_t nfparams = Argument::dim(tp->parameters);
+
+	/* See if tuple match
+	 */
+	if (nfparams > 0 && nfargs >= nfparams - 1)
+	{
+	    /* See if 'A' of the template parameter matches 'A'
+	     * of the type of the last function parameter.
+	     */
+	    Argument *fparam = (Argument *)tp->parameters->data[nfparams - 1];
+	    if (fparam->type->ty != Tident)
+		goto L1;
+	    TypeIdentifier *tid = (TypeIdentifier *)fparam->type;
+	    if (tid->idents.dim)
+		goto L1;
+
+	    /* Look through parameters to find tuple matching tid->ident
+	     */
+	    size_t tupi = 0;
+	    for (; 1; tupi++)
+	    {	if (tupi == parameters->dim)
+		    goto L1;
+		TemplateParameter *t = (TemplateParameter *)parameters->data[tupi];
+		TemplateTupleParameter *tup = t->isTemplateTupleParameter();
+		if (tup && tup->ident->equals(tid->ident))
+		    break;
+	    }
+
+	    /* The types of the function arguments [nfparams - 1 .. nfargs]
+	     * now form the tuple argument.
+	     */
+	    int tuple_dim = nfargs - (nfparams - 1);
+
+	    /* See if existing tuple, and whether it matches or not
+	     */
+	    Object *o = (Object *)dedtypes->data[tupi];
+	    if (o)
+	    {	// Existing deduced argument must be a tuple, and must match
+		Tuple *t = isTuple(o);
+		if (!t || t->objects.dim != tuple_dim)
+		    return MATCHnomatch;
+		for (size_t i = 0; i < tuple_dim; i++)
+		{   Argument *arg = Argument::getNth(this->parameters, nfparams - 1 + i);
+		    if (!arg->type->equals((Object *)t->objects.data[i]))
+			return MATCHnomatch;
+		}
+	    }
+	    else
+	    {	// Create new tuple
+		Tuple *t = new Tuple();
+		t->objects.setDim(tuple_dim);
+		for (size_t i = 0; i < tuple_dim; i++)
+		{   Argument *arg = Argument::getNth(this->parameters, nfparams - 1 + i);
+		    t->objects.data[i] = (void *)arg->type;
+		}
+		dedtypes->data[tupi] = (void *)t;
+	    }
+	    nfparams--;	// don't consider the last parameter for type deduction
+	    goto L2;
+	}
+
+    L1:
+	if (nfargs != nfparams)
+	    return MATCHnomatch;
+    L2:
+	for (size_t i = 0; i < nfparams; i++)
+	{
+	    Argument *a = Argument::getNth(this->parameters, i);
+	    Argument *ap = Argument::getNth(tp->parameters, i);
+	    if (a->storageClass != ap->storageClass ||
+		!a->type->deduceType(sc, ap->type, parameters, dedtypes))
+		return MATCHnomatch;
+	}
+    }
+    return Type::deduceType(sc, tparam, parameters, dedtypes);
+}
+
+MATCH TypeIdentifier::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes)
+{
+    // Extra check
+    if (tparam && tparam->ty == Tident)
+    {
+	TypeIdentifier *tp = (TypeIdentifier *)tparam;
+
+	for (int i = 0; i < idents.dim; i++)
+	{
+	    Identifier *id1 = (Identifier *)idents.data[i];
+	    Identifier *id2 = (Identifier *)tp->idents.data[i];
+
+	    if (!id1->equals(id2))
+		return MATCHnomatch;
+	}
+    }
+    return Type::deduceType(sc, tparam, parameters, dedtypes);
+}
+
+MATCH TypeInstance::deduceType(Scope *sc,
+	Type *tparam, TemplateParameters *parameters,
+	Objects *dedtypes)
+{
+    //printf("TypeInstance::deduceType(tparam = %s) %s\n", tparam->toChars(), toChars());
+    //printf("\ttparam = %d, ", tparam->ty); tparam->print();
+
+    // Extra check
+    if (tparam && tparam->ty == Tinstance)
+    {
+	TypeInstance *tp = (TypeInstance *)tparam;
+
+	//printf("tempinst->tempdecl = %p\n", tempinst->tempdecl);
+	//printf("tp->tempinst->tempdecl = %p\n", tp->tempinst->tempdecl);
+	if (!tp->tempinst->tempdecl)
+	{   if (!tp->tempinst->name->equals(tempinst->name))
+		goto Lnomatch;
+	}
+	else if (tempinst->tempdecl != tp->tempinst->tempdecl)
+	    goto Lnomatch;
+
+	for (int i = 0; i < tempinst->tiargs->dim; i++)
+	{
+	    //printf("test: [%d]\n", i);
+	    Object *o1 = (Object *)tempinst->tiargs->data[i];
+	    Object *o2 = (Object *)tp->tempinst->tiargs->data[i];
+
+	    Type *t1 = isType(o1);
+	    Type *t2 = isType(o2);
+
+	    Expression *e1 = isExpression(o1);
+	    Expression *e2 = isExpression(o2);
+
+#if 0
+	    if (t1)	printf("t1 = %s\n", t1->toChars());
+	    if (t2)	printf("t2 = %s\n", t2->toChars());
+	    if (e1)	printf("e1 = %s\n", e1->toChars());
+	    if (e2)	printf("e2 = %s\n", e2->toChars());
+#endif
+
+	    if (t1 && t2)
+	    {
+		if (!t1->deduceType(sc, t2, parameters, dedtypes))
+		    goto Lnomatch;
+	    }
+	    else if (e1 && e2)
+	    {
+		if (!e1->equals(e2))
+		    goto Lnomatch;
+	    }
+	    else if (e1 && t2 && t2->ty == Tident)
+	    {	int i = templateParameterLookup(t2, parameters);
+		if (i == -1)
+		    goto Lnomatch;
+		TemplateParameter *tp = (TemplateParameter *)parameters->data[i];
+		// BUG: use tp->matchArg() instead of the following
+		TemplateValueParameter *tv = tp->isTemplateValueParameter();
+		if (!tv)
+		    goto Lnomatch;
+		Expression *e = (Expression *)dedtypes->data[i];
+		if (e)
+		{
+		    if (!e1->equals(e))
+			goto Lnomatch;
+		}
+		else
+		{   Type *vt = tv->valType->semantic(0, sc);
+		    MATCH m = (MATCH)e1->implicitConvTo(vt);
+		    if (!m)
+			goto Lnomatch;
+		    dedtypes->data[i] = e1;
+		}
+	    }
+	    // BUG: Need to handle alias and tuple parameters
+	    else
+		goto Lnomatch;
+	}
+    }
+    return Type::deduceType(sc, tparam, parameters, dedtypes);
+
+Lnomatch:
+    return MATCHnomatch;
+}
+
+MATCH TypeStruct::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes)
+{
+    //printf("TypeStruct::deduceType()\n");
+    //printf("\tthis->parent   = %s, ", sym->parent->toChars()); print();
+    //printf("\ttparam = %d, ", tparam->ty); tparam->print();
+
+    /* If this struct is a template struct, and we're matching
+     * it against a template instance, convert the struct type
+     * to a template instance, too, and try again.
+     */
+    TemplateInstance *ti = sym->parent->isTemplateInstance();
+
+    if (tparam && tparam->ty == Tinstance)
+    {
+	if (ti && ti->toAlias() == sym)
+	{
+	    TypeInstance *t = new TypeInstance(0, ti);
+	    return t->deduceType(sc, tparam, parameters, dedtypes);
+	}
+
+	/* Match things like:
+	 *  S!(T).foo
+	 */
+	TypeInstance *tpi = (TypeInstance *)tparam;
+	if (tpi->idents.dim)
+	{   Identifier *id = (Identifier *)tpi->idents.data[tpi->idents.dim - 1];
+	    if (id->dyncast() == DYNCAST_IDENTIFIER && sym->ident->equals(id))
+	    {
+		Type *tparent = sym->parent->getType();
+		if (tparent)
+		{
+		    /* Slice off the .foo in S!(T).foo
+		     */
+		    tpi->idents.dim--;
+		    MATCH m = tparent->deduceType(sc, tpi, parameters, dedtypes);
+		    tpi->idents.dim++;
+		    return m;
+		}
+	    }
+	}
+    }
+
+    // Extra check
+    if (tparam && tparam->ty == Tstruct)
+    {
+	TypeStruct *tp = (TypeStruct *)tparam;
+
+	if (sym != tp->sym)
+	    return MATCHnomatch;
+    }
+    return Type::deduceType(sc, tparam, parameters, dedtypes);
+}
+
+MATCH TypeEnum::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes)
+{
+    // Extra check
+    if (tparam && tparam->ty == Tenum)
+    {
+	TypeEnum *tp = (TypeEnum *)tparam;
+
+	if (sym != tp->sym)
+	    return MATCHnomatch;
+    }
+    return Type::deduceType(sc, tparam, parameters, dedtypes);
+}
+
+MATCH TypeTypedef::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes)
+{
+    // Extra check
+    if (tparam && tparam->ty == Ttypedef)
+    {
+	TypeTypedef *tp = (TypeTypedef *)tparam;
+
+	if (sym != tp->sym)
+	    return MATCHnomatch;
+    }
+    return Type::deduceType(sc, tparam, parameters, dedtypes);
+}
+
+MATCH TypeClass::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes)
+{
+    //printf("TypeClass::deduceType(this = %s)\n", toChars());
+
+    /* If this class is a template class, and we're matching
+     * it against a template instance, convert the class type
+     * to a template instance, too, and try again.
+     */
+    TemplateInstance *ti = sym->parent->isTemplateInstance();
+
+    if (tparam && tparam->ty == Tinstance)
+    {
+	if (ti && ti->toAlias() == sym)
+	{
+	    TypeInstance *t = new TypeInstance(0, ti);
+	    return t->deduceType(sc, tparam, parameters, dedtypes);
+	}
+
+	/* Match things like:
+	 *  S!(T).foo
+	 */
+	TypeInstance *tpi = (TypeInstance *)tparam;
+	if (tpi->idents.dim)
+	{   Identifier *id = (Identifier *)tpi->idents.data[tpi->idents.dim - 1];
+	    if (id->dyncast() == DYNCAST_IDENTIFIER && sym->ident->equals(id))
+	    {
+		Type *tparent = sym->parent->getType();
+		if (tparent)
+		{
+		    /* Slice off the .foo in S!(T).foo
+		     */
+		    tpi->idents.dim--;
+		    MATCH m = tparent->deduceType(sc, tpi, parameters, dedtypes);
+		    tpi->idents.dim++;
+		    return m;
+		}
+	    }
+	}
+    }
+
+    // Extra check
+    if (tparam && tparam->ty == Tclass)
+    {
+	TypeClass *tp = (TypeClass *)tparam;
+
+	//printf("\t%d\n", (MATCH) implicitConvTo(tp));
+	return (MATCH) implicitConvTo(tp);
+    }
+    return Type::deduceType(sc, tparam, parameters, dedtypes);
+}
+
+/* ======================== TemplateParameter =============================== */
+
+TemplateParameter::TemplateParameter(Loc loc, Identifier *ident)
+{
+    this->loc = loc;
+    this->ident = ident;
+    this->sparam = NULL;
+}
+
+TemplateTypeParameter  *TemplateParameter::isTemplateTypeParameter()
+{
+    return NULL;
+}
+
+TemplateValueParameter *TemplateParameter::isTemplateValueParameter()
+{
+    return NULL;
+}
+
+TemplateAliasParameter *TemplateParameter::isTemplateAliasParameter()
+{
+    return NULL;
+}
+
+TemplateTupleParameter *TemplateParameter::isTemplateTupleParameter()
+{
+    return NULL;
+}
+
+/* ======================== TemplateTypeParameter =========================== */
+
+// type-parameter
+
+TemplateTypeParameter::TemplateTypeParameter(Loc loc, Identifier *ident, Type *specType,
+	Type *defaultType)
+    : TemplateParameter(loc, ident)
+{
+    this->ident = ident;
+    this->specType = specType;
+    this->defaultType = defaultType;
+}
+
+TemplateTypeParameter  *TemplateTypeParameter::isTemplateTypeParameter()
+{
+    return this;
+}
+
+TemplateParameter *TemplateTypeParameter::syntaxCopy()
+{
+    TemplateTypeParameter *tp = new TemplateTypeParameter(loc, ident, specType, defaultType);
+    if (tp->specType)
+	tp->specType = specType->syntaxCopy();
+    if (defaultType)
+	tp->defaultType = defaultType->syntaxCopy();
+    return tp;
+}
+
+void TemplateTypeParameter::declareParameter(Scope *sc)
+{
+    //printf("TemplateTypeParameter::declareParameter('%s')\n", ident->toChars());
+    TypeIdentifier *ti = new TypeIdentifier(loc, ident);
+    sparam = new AliasDeclaration(loc, ident, ti);
+    if (!sc->insert(sparam))
+	error(loc, "parameter '%s' multiply defined", ident->toChars());
+}
+
+void TemplateTypeParameter::semantic(Scope *sc)
+{
+    //printf("TemplateTypeParameter::semantic('%s')\n", ident->toChars());
+    if (specType)
+    {
+	specType = specType->semantic(loc, sc);
+    }
+#if 0 // Don't do semantic() until instantiation
+    if (defaultType)
+    {
+	defaultType = defaultType->semantic(loc, sc);
+    }
+#endif
+}
+
+/****************************************
+ * Determine if two TemplateParameters are the same
+ * as far as TemplateDeclaration overloading goes.
+ * Returns:
+ *	1	match
+ *	0	no match
+ */
+
+int TemplateTypeParameter::overloadMatch(TemplateParameter *tp)
+{
+    TemplateTypeParameter *ttp = tp->isTemplateTypeParameter();
+
+    if (ttp)
+    {
+	if (specType != ttp->specType)
+	    goto Lnomatch;
+
+	if (specType && !specType->equals(ttp->specType))
+	    goto Lnomatch;
+
+	return 1;			// match
+    }
+
+Lnomatch:
+    return 0;
+}
+
+/*******************************************
+ * Match to a particular TemplateParameter.
+ * Input:
+ *	i		i'th argument
+ *	tiargs[]	actual arguments to template instance
+ *	parameters[]	template parameters
+ *	dedtypes[]	deduced arguments to template instance
+ *	*psparam	set to symbol declared and initialized to dedtypes[i]
+ */
+
+MATCH TemplateTypeParameter::matchArg(Scope *sc, Objects *tiargs,
+	int i, TemplateParameters *parameters, Objects *dedtypes,
+	Declaration **psparam)
+{
+    //printf("TemplateTypeParameter::matchArg()\n");
+    Type *t;
+    Object *oarg;
+    MATCH m = MATCHexact;
+    Type *ta;
+
+    if (i < tiargs->dim)
+	oarg = (Object *)tiargs->data[i];
+    else
+    {	// Get default argument instead
+	oarg = defaultArg(sc);
+	if (!oarg)
+	{   assert(i < dedtypes->dim);
+	    // It might have already been deduced
+	    oarg = (Object *)dedtypes->data[i];
+	    if (!oarg)
+		goto Lnomatch;
+	}
+    }
+
+    ta = isType(oarg);
+    if (!ta)
+	goto Lnomatch;
+    //printf("ta is %s\n", ta->toChars());
+
+    t = (Type *)dedtypes->data[i];
+
+    if (specType)
+    {
+	//printf("\tcalling deduceType(), specType is %s\n", specType->toChars());
+	MATCH m2 = ta->deduceType(sc, specType, parameters, dedtypes);
+	if (m2 == MATCHnomatch)
+	{   //printf("\tfailed deduceType\n");
+	    goto Lnomatch;
+	}
+
+	if (m2 < m)
+	    m = m2;
+	t = (Type *)dedtypes->data[i];
+    }
+    else
+    {
+	m = MATCHconvert;
+	if (t)
+	{   // Must match already deduced type
+
+	    if (!t->equals(ta))
+		goto Lnomatch;
+	}
+    }
+
+    if (!t)
+    {
+	dedtypes->data[i] = ta;
+	t = ta;
+    }
+    *psparam = new AliasDeclaration(loc, ident, t);
+    //printf("\tm = %d\n", m);
+    return m;
+
+Lnomatch:
+    *psparam = NULL;
+    //printf("\tm = %d\n", MATCHnomatch);
+    return MATCHnomatch;
+}
+
+
+void TemplateTypeParameter::print(Object *oarg, Object *oded)
+{
+    printf(" %s\n", ident->toChars());
+
+    Type *t  = isType(oarg);
+    Type *ta = isType(oded);
+
+    assert(ta);
+
+    if (specType)
+	printf("\tSpecialization: %s\n", specType->toChars());
+    if (defaultType)
+	printf("\tDefault:        %s\n", defaultType->toChars());
+    printf("\tArgument:       %s\n", t ? t->toChars() : "NULL");
+    printf("\tDeduced Type:   %s\n", ta->toChars());
+}
+
+
+void TemplateTypeParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring(ident->toChars());
+    if (specType)
+    {
+	buf->writestring(" : ");
+	specType->toCBuffer(buf, NULL, hgs);
+    }
+    if (defaultType)
+    {
+	buf->writestring(" = ");
+	defaultType->toCBuffer(buf, NULL, hgs);
+    }
+}
+
+
+void *TemplateTypeParameter::dummyArg()
+{   Type *t;
+
+    if (specType)
+	t = specType;
+    else
+    {   // Use this for alias-parameter's too (?)
+	t = new TypeIdentifier(loc, ident);
+    }
+    return (void *)t;
+}
+
+
+Object *TemplateTypeParameter::specialization()
+{
+    return specType;
+}
+
+
+Object *TemplateTypeParameter::defaultArg(Scope *sc)
+{
+    Type *t;
+
+    t = defaultType;
+    if (t)
+    {
+	t = t->syntaxCopy();
+	t = t->semantic(loc, sc);
+    }
+    return t;
+}
+
+/* ======================== TemplateAliasParameter ========================== */
+
+// alias-parameter
+
+Dsymbol *TemplateAliasParameter::sdummy = NULL;
+
+TemplateAliasParameter::TemplateAliasParameter(Loc loc, Identifier *ident, Type *specAliasT, Type *defaultAlias)
+    : TemplateParameter(loc, ident)
+{
+    this->ident = ident;
+    this->specAliasT = specAliasT;
+    this->defaultAlias = defaultAlias;
+
+    this->specAlias = NULL;
+}
+
+TemplateAliasParameter *TemplateAliasParameter::isTemplateAliasParameter()
+{
+    return this;
+}
+
+TemplateParameter *TemplateAliasParameter::syntaxCopy()
+{
+    TemplateAliasParameter *tp = new TemplateAliasParameter(loc, ident, specAliasT, defaultAlias);
+    if (tp->specAliasT)
+	tp->specAliasT = specAliasT->syntaxCopy();
+    if (defaultAlias)
+	tp->defaultAlias = defaultAlias->syntaxCopy();
+    return tp;
+}
+
+void TemplateAliasParameter::declareParameter(Scope *sc)
+{
+    TypeIdentifier *ti = new TypeIdentifier(loc, ident);
+    sparam = new AliasDeclaration(loc, ident, ti);
+    if (!sc->insert(sparam))
+	error(loc, "parameter '%s' multiply defined", ident->toChars());
+}
+
+void TemplateAliasParameter::semantic(Scope *sc)
+{
+    if (specAliasT)
+    {
+	specAlias = specAliasT->toDsymbol(sc);
+	if (!specAlias)
+	    error("%s is not a symbol", specAliasT->toChars());
+    }
+#if 0 // Don't do semantic() until instantiation
+    if (defaultAlias)
+	defaultAlias = defaultAlias->semantic(loc, sc);
+#endif
+}
+
+int TemplateAliasParameter::overloadMatch(TemplateParameter *tp)
+{
+    TemplateAliasParameter *tap = tp->isTemplateAliasParameter();
+
+    if (tap)
+    {
+	if (specAlias != tap->specAlias)
+	    goto Lnomatch;
+
+	return 1;			// match
+    }
+
+Lnomatch:
+    return 0;
+}
+
+MATCH TemplateAliasParameter::matchArg(Scope *sc,
+	Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes,
+	Declaration **psparam)
+{
+    Dsymbol *sa;
+    Object *oarg;
+    Expression *ea;
+
+    //printf("TemplateAliasParameter::matchArg()\n");
+
+    if (i < tiargs->dim)
+	oarg = (Object *)tiargs->data[i];
+    else
+    {	// Get default argument instead
+	oarg = defaultArg(sc);
+	if (!oarg)
+	{   assert(i < dedtypes->dim);
+	    // It might have already been deduced
+	    oarg = (Object *)dedtypes->data[i];
+	    if (!oarg)
+		goto Lnomatch;
+	}
+    }
+
+    sa = getDsymbol(oarg);
+    if (!sa)
+	goto Lnomatch;
+
+    if (specAlias)
+    {
+	if (!sa || sa == sdummy)
+	    goto Lnomatch;
+	if (sa != specAlias)
+	    goto Lnomatch;
+    }
+    else if (dedtypes->data[i])
+    {   // Must match already deduced symbol
+	Dsymbol *s = (Dsymbol *)dedtypes->data[i];
+
+	if (!sa || s != sa)
+	    goto Lnomatch;
+    }
+    dedtypes->data[i] = sa;
+
+    *psparam = new AliasDeclaration(loc, ident, sa);
+    return MATCHexact;
+
+Lnomatch:
+    *psparam = NULL;
+    return MATCHnomatch;
+}
+
+
+void TemplateAliasParameter::print(Object *oarg, Object *oded)
+{
+    printf(" %s\n", ident->toChars());
+
+    Dsymbol *sa = isDsymbol(oded);
+    assert(sa);
+
+    printf("\tArgument alias: %s\n", sa->toChars());
+}
+
+void TemplateAliasParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("alias ");
+    buf->writestring(ident->toChars());
+    if (specAliasT)
+    {
+	buf->writestring(" : ");
+	specAliasT->toCBuffer(buf, NULL, hgs);
+    }
+    if (defaultAlias)
+    {
+	buf->writestring(" = ");
+	defaultAlias->toCBuffer(buf, NULL, hgs);
+    }
+}
+
+
+void *TemplateAliasParameter::dummyArg()
+{   Dsymbol *s;
+
+    s = specAlias;
+    if (!s)
+    {
+	if (!sdummy)
+	    sdummy = new Dsymbol();
+	s = sdummy;
+    }
+    return (void*)s;
+}
+
+
+Object *TemplateAliasParameter::specialization()
+{
+    return specAliasT;
+}
+
+
+Object *TemplateAliasParameter::defaultArg(Scope *sc)
+{
+    Dsymbol *s = NULL;
+
+    if (defaultAlias)
+    {
+	s = defaultAlias->toDsymbol(sc);
+	if (!s)
+	    error("%s is not a symbol", defaultAlias->toChars());
+    }
+    return s;
+}
+
+/* ======================== TemplateValueParameter ========================== */
+
+// value-parameter
+
+Expression *TemplateValueParameter::edummy = NULL;
+
+TemplateValueParameter::TemplateValueParameter(Loc loc, Identifier *ident, Type *valType,
+	Expression *specValue, Expression *defaultValue)
+    : TemplateParameter(loc, ident)
+{
+    this->ident = ident;
+    this->valType = valType;
+    this->specValue = specValue;
+    this->defaultValue = defaultValue;
+}
+
+TemplateValueParameter *TemplateValueParameter::isTemplateValueParameter()
+{
+    return this;
+}
+
+TemplateParameter *TemplateValueParameter::syntaxCopy()
+{
+    TemplateValueParameter *tp =
+	new TemplateValueParameter(loc, ident, valType, specValue, defaultValue);
+    tp->valType = valType->syntaxCopy();
+    if (specValue)
+	tp->specValue = specValue->syntaxCopy();
+    if (defaultValue)
+	tp->defaultValue = defaultValue->syntaxCopy();
+    return tp;
+}
+
+void TemplateValueParameter::declareParameter(Scope *sc)
+{
+    VarDeclaration *v = new VarDeclaration(loc, valType, ident, NULL);
+    v->storage_class = STCtemplateparameter;
+    if (!sc->insert(v))
+	error(loc, "parameter '%s' multiply defined", ident->toChars());
+    sparam = v;
+}
+
+void TemplateValueParameter::semantic(Scope *sc)
+{
+    sparam->semantic(sc);
+    valType = valType->semantic(loc, sc);
+    if (!(valType->isintegral() || valType->isfloating() || valType->isString()) &&
+	valType->ty != Tident)
+	error(loc, "arithmetic/string type expected for value-parameter, not %s", valType->toChars());
+
+    if (specValue)
+    {   Expression *e = specValue;
+
+	e = e->semantic(sc);
+	e = e->implicitCastTo(sc, valType);
+	e = e->optimize(WANTvalue | WANTinterpret);
+	if (e->op == TOKint64 || e->op == TOKfloat64 ||
+	    e->op == TOKcomplex80 || e->op == TOKnull || e->op == TOKstring)
+	    specValue = e;
+	//e->toInteger();
+    }
+
+#if 0	// defer semantic analysis to arg match
+    if (defaultValue)
+    {   Expression *e = defaultValue;
+
+	e = e->semantic(sc);
+	e = e->implicitCastTo(sc, valType);
+	e = e->optimize(WANTvalue | WANTinterpret);
+	if (e->op == TOKint64)
+	    defaultValue = e;
+	//e->toInteger();
+    }
+#endif
+}
+
+int TemplateValueParameter::overloadMatch(TemplateParameter *tp)
+{
+    TemplateValueParameter *tvp = tp->isTemplateValueParameter();
+
+    if (tvp)
+    {
+	if (valType != tvp->valType)
+	    goto Lnomatch;
+
+	if (valType && !valType->equals(tvp->valType))
+	    goto Lnomatch;
+
+	if (specValue != tvp->specValue)
+	    goto Lnomatch;
+
+	return 1;			// match
+    }
+
+Lnomatch:
+    return 0;
+}
+
+
+MATCH TemplateValueParameter::matchArg(Scope *sc,
+	Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes,
+	Declaration **psparam)
+{
+    //printf("TemplateValueParameter::matchArg()\n");
+
+    Initializer *init;
+    Declaration *sparam;
+    MATCH m = MATCHexact;
+    Expression *ei;
+    Object *oarg;
+
+    if (i < tiargs->dim)
+	oarg = (Object *)tiargs->data[i];
+    else
+    {	// Get default argument instead
+	oarg = defaultArg(sc);
+	if (!oarg)
+	{   assert(i < dedtypes->dim);
+	    // It might have already been deduced
+	    oarg = (Object *)dedtypes->data[i];
+	    if (!oarg)
+		goto Lnomatch;
+	}
+    }
+
+    ei = isExpression(oarg);
+    Type *vt;
+
+    if (!ei && oarg)
+	goto Lnomatch;
+
+    if (specValue)
+    {
+	if (!ei || ei == edummy)
+	    goto Lnomatch;
+
+	Expression *e = specValue;
+
+	e = e->semantic(sc);
+	e = e->implicitCastTo(sc, valType);
+	e = e->optimize(WANTvalue | WANTinterpret);
+
+	ei = ei->syntaxCopy();
+	ei = ei->semantic(sc);
+	ei = ei->optimize(WANTvalue | WANTinterpret);
+	//printf("ei: %s, %s\n", ei->toChars(), ei->type->toChars());
+	//printf("e : %s, %s\n", e->toChars(), e->type->toChars());
+	if (!ei->equals(e))
+	    goto Lnomatch;
+    }
+    else if (dedtypes->data[i])
+    {   // Must match already deduced value
+	Expression *e = (Expression *)dedtypes->data[i];
+
+	if (!ei || !ei->equals(e))
+	    goto Lnomatch;
+    }
+Lmatch:
+    //printf("valType: %s, ty = %d\n", valType->toChars(), valType->ty);
+    vt = valType->semantic(0, sc);
+    //printf("ei: %s, %s\n", ei->toChars(), ei->type->toChars());
+    if (ei->type)
+    {
+	m = (MATCH)ei->implicitConvTo(vt);
+	//printf("m: %d\n", m);
+	if (!m)
+	    goto Lnomatch;
+    }
+    dedtypes->data[i] = ei;
+
+    init = new ExpInitializer(loc, ei);
+    sparam = new VarDeclaration(loc, vt, ident, init);
+    sparam->storage_class = STCconst;
+    *psparam = sparam;
+    return m;
+
+Lnomatch:
+    *psparam = NULL;
+    return MATCHnomatch;
+}
+
+
+void TemplateValueParameter::print(Object *oarg, Object *oded)
+{
+    printf(" %s\n", ident->toChars());
+
+    Expression *ea = isExpression(oded);
+
+    if (specValue)
+	printf("\tSpecialization: %s\n", specValue->toChars());
+    printf("\tArgument Value: %s\n", ea ? ea->toChars() : "NULL");
+}
+
+
+void TemplateValueParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    valType->toCBuffer(buf, ident, hgs);
+    if (specValue)
+    {
+	buf->writestring(" : ");
+	specValue->toCBuffer(buf, hgs);
+    }
+    if (defaultValue)
+    {
+	buf->writestring(" = ");
+	defaultValue->toCBuffer(buf, hgs);
+    }
+}
+
+
+void *TemplateValueParameter::dummyArg()
+{   Expression *e;
+
+    e = specValue;
+    if (!e)
+    {
+	// Create a dummy value
+	if (!edummy)
+	    edummy = valType->defaultInit();
+	e = edummy;
+    }
+    return (void *)e;
+}
+
+
+Object *TemplateValueParameter::specialization()
+{
+    return specValue;
+}
+
+
+Object *TemplateValueParameter::defaultArg(Scope *sc)
+{
+    Expression *e;
+
+    e = defaultValue;
+    if (e)
+    {
+	e = e->syntaxCopy();
+	e = e->semantic(sc);
+    }
+    return e;
+}
+
+/* ======================== TemplateTupleParameter ========================== */
+
+// variadic-parameter
+
+TemplateTupleParameter::TemplateTupleParameter(Loc loc, Identifier *ident)
+    : TemplateParameter(loc, ident)
+{
+    this->ident = ident;
+}
+
+TemplateTupleParameter *TemplateTupleParameter::isTemplateTupleParameter()
+{
+    return this;
+}
+
+TemplateParameter *TemplateTupleParameter::syntaxCopy()
+{
+    TemplateTupleParameter *tp = new TemplateTupleParameter(loc, ident);
+    return tp;
+}
+
+void TemplateTupleParameter::declareParameter(Scope *sc)
+{
+    TypeIdentifier *ti = new TypeIdentifier(loc, ident);
+    sparam = new AliasDeclaration(loc, ident, ti);
+    if (!sc->insert(sparam))
+	error(loc, "parameter '%s' multiply defined", ident->toChars());
+}
+
+void TemplateTupleParameter::semantic(Scope *sc)
+{
+}
+
+int TemplateTupleParameter::overloadMatch(TemplateParameter *tp)
+{
+    TemplateTupleParameter *tvp = tp->isTemplateTupleParameter();
+
+    if (tvp)
+    {
+	return 1;			// match
+    }
+
+Lnomatch:
+    return 0;
+}
+
+MATCH TemplateTupleParameter::matchArg(Scope *sc,
+	Objects *tiargs, int i, TemplateParameters *parameters,
+	Objects *dedtypes,
+	Declaration **psparam)
+{
+    //printf("TemplateTupleParameter::matchArg()\n");
+
+    /* The rest of the actual arguments (tiargs[]) form the match
+     * for the variadic parameter.
+     */
+    assert(i + 1 == dedtypes->dim);	// must be the last one
+    Tuple *ovar;
+    if (i + 1 == tiargs->dim && isTuple((Object *)tiargs->data[i]))
+	ovar = isTuple((Object *)tiargs->data[i]);
+    else
+    {
+	ovar = new Tuple();
+	//printf("ovar = %p\n", ovar);
+	if (i < tiargs->dim)
+	{
+	    //printf("i = %d, tiargs->dim = %d\n", i, tiargs->dim);
+	    ovar->objects.setDim(tiargs->dim - i);
+	    for (size_t j = 0; j < ovar->objects.dim; j++)
+		ovar->objects.data[j] = tiargs->data[i + j];
+	}
+    }
+    *psparam = new TupleDeclaration(loc, ident, &ovar->objects);
+    dedtypes->data[i] = (void *)ovar;
+    return MATCHexact;
+}
+
+
+void TemplateTupleParameter::print(Object *oarg, Object *oded)
+{
+    printf(" %s... [", ident->toChars());
+    Tuple *v = isTuple(oded);
+    assert(v);
+
+    //printf("|%d| ", v->objects.dim);
+    for (int i = 0; i < v->objects.dim; i++)
+    {
+	if (i)
+	    printf(", ");
+
+	Object *o = (Object *)v->objects.data[i];
+
+	Dsymbol *sa = isDsymbol(o);
+	if (sa)
+	    printf("alias: %s", sa->toChars());
+
+	Type *ta = isType(o);
+	if (ta)
+	    printf("type: %s", ta->toChars());
+
+	Expression *ea = isExpression(o);
+	if (ea)
+	    printf("exp: %s", ea->toChars());
+
+	assert(!isTuple(o));		// no nested Tuple arguments
+    }
+
+    printf("]\n");
+}
+
+void TemplateTupleParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring(ident->toChars());
+    buf->writestring("...");
+}
+
+
+void *TemplateTupleParameter::dummyArg()
+{
+    return NULL;
+}
+
+
+Object *TemplateTupleParameter::specialization()
+{
+    return NULL;
+}
+
+
+Object *TemplateTupleParameter::defaultArg(Scope *sc)
+{
+    return NULL;
+}
+
+/* ======================== TemplateInstance ================================ */
+
+TemplateInstance::TemplateInstance(Loc loc, Identifier *ident)
+    : ScopeDsymbol(NULL)
+{
+#if LOG
+    printf("TemplateInstance(this = %p, ident = '%s')\n", this, ident ? ident->toChars() : "null");
+#endif
+    this->loc = loc;
+    this->name = ident;
+    this->tiargs = NULL;
+    this->tempdecl = NULL;
+    this->inst = NULL;
+    this->argsym = NULL;
+    this->aliasdecl = NULL;
+    this->semanticdone = 0;
+    this->withsym = NULL;
+    this->nest = 0;
+    this->havetempdecl = 0;
+    this->isnested = NULL;
+    this->errors = 0;
+}
+
+
+TemplateInstance::TemplateInstance(Loc loc, TemplateDeclaration *td, Objects *tiargs)
+    : ScopeDsymbol(NULL)
+{
+#if LOG
+    printf("TemplateInstance(this = %p, tempdecl = '%s')\n", this, td->toChars());
+#endif
+    this->loc = loc;
+    this->name = td->ident;
+    this->tiargs = tiargs;
+    this->tempdecl = td;
+    this->inst = NULL;
+    this->argsym = NULL;
+    this->aliasdecl = NULL;
+    this->semanticdone = 0;
+    this->withsym = NULL;
+    this->nest = 0;
+    this->havetempdecl = 1;
+    this->isnested = NULL;
+    this->errors = 0;
+
+    assert((size_t)tempdecl->scope > 0x10000);
+}
+
+
+Objects *TemplateInstance::arraySyntaxCopy(Objects *objs)
+{
+    Objects *a = NULL;
+    if (objs)
+    {	a = new Objects();
+	a->setDim(objs->dim);
+	for (size_t i = 0; i < objs->dim; i++)
+	{
+	    Type *ta = isType((Object *)objs->data[i]);
+	    if (ta)
+		a->data[i] = ta->syntaxCopy();
+	    else
+	    {
+		Expression *ea = isExpression((Object *)objs->data[i]);
+		assert(ea);
+		a->data[i] = ea->syntaxCopy();
+	    }
+	}
+    }
+    return a;
+}
+
+Dsymbol *TemplateInstance::syntaxCopy(Dsymbol *s)
+{
+    TemplateInstance *ti;
+    int i;
+
+    if (s)
+	ti = (TemplateInstance *)s;
+    else
+	ti = new TemplateInstance(loc, name);
+
+    ti->tiargs = arraySyntaxCopy(tiargs);
+
+    ScopeDsymbol::syntaxCopy(ti);
+    return ti;
+}
+
+
+void TemplateInstance::semantic(Scope *sc)
+{
+    if (global.errors)
+    {
+	if (!global.gag)
+	{
+	    /* Trying to soldier on rarely generates useful messages
+	     * at this point.
+	     */
+	    fatal();
+	}
+	return;
+    }
+#if LOG
+    printf("\n+TemplateInstance::semantic('%s', this=%p)\n", toChars(), this);
+#endif
+    if (inst)		// if semantic() was already run
+    {
+#if LOG
+	printf("-TemplateInstance::semantic('%s', this=%p) already run\n", inst->toChars(), inst);
+#endif
+	return;
+    }
+
+    if (semanticdone != 0)
+    {
+	error(loc, "recursive template expansion");
+//	inst = this;
+	return;
+    }
+    semanticdone = 1;
+
+#if LOG
+    printf("\tdo semantic\n");
+#endif
+    if (havetempdecl)
+    {
+	assert((size_t)tempdecl->scope > 0x10000);
+	// Deduce tdtypes
+	tdtypes.setDim(tempdecl->parameters->dim);
+	if (!tempdecl->matchWithInstance(this, &tdtypes, 0))
+	{
+	    error("incompatible arguments for template instantiation");
+	    inst = this;
+	    return;
+	}
+    }
+    else
+    {
+	// Run semantic on each argument, place results in tiargs[]
+	semanticTiargs(sc);
+
+	tempdecl = findTemplateDeclaration(sc);
+	if (tempdecl)
+	    tempdecl = findBestMatch(sc);
+	if (!tempdecl || global.errors)
+	{   inst = this;
+	    //printf("error return %p, %d\n", tempdecl, global.errors);
+	    return;		// error recovery
+	}
+    }
+
+    isNested(tiargs);
+
+    /* See if there is an existing TemplateInstantiation that already
+     * implements the typeargs. If so, just refer to that one instead.
+     */
+
+    for (size_t i = 0; i < tempdecl->instances.dim; i++)
+    {
+	TemplateInstance *ti = (TemplateInstance *)tempdecl->instances.data[i];
+#if LOG
+	printf("\t%s: checking for match with instance %d (%p): '%s'\n", toChars(), i, ti, ti->toChars());
+#endif
+	assert(tdtypes.dim == ti->tdtypes.dim);
+
+	// Nesting must match
+	if (isnested != ti->isnested)
+	    continue;
+#if 0
+	if (isnested && sc->parent != ti->parent)
+	    continue;
+#endif
+	for (size_t j = 0; j < tdtypes.dim; j++)
+	{   Object *o1 = (Object *)tdtypes.data[j];
+	    Object *o2 = (Object *)ti->tdtypes.data[j];
+	    if (!match(o1, o2, tempdecl, sc))
+		goto L1;
+	}
+
+	// It's a match
+	inst = ti;
+	parent = ti->parent;
+#if LOG
+	printf("\tit's a match with instance %p\n", inst);
+#endif
+	return;
+
+     L1:
+	;
+    }
+
+    /* So, we need to implement 'this' instance.
+     */
+#if LOG
+    printf("\timplement template instance '%s'\n", toChars());
+#endif
+    unsigned errorsave = global.errors;
+    inst = this;
+    int tempdecl_instance_idx = tempdecl->instances.dim;
+    tempdecl->instances.push(this);
+    parent = tempdecl->parent;
+    //printf("parent = '%s'\n", parent->kind());
+
+    ident = genIdent();		// need an identifier for name mangling purposes.
+
+#if 1
+    if (isnested)
+	parent = isnested;
+#endif
+    //printf("parent = '%s'\n", parent->kind());
+
+    // Add 'this' to the enclosing scope's members[] so the semantic routines
+    // will get called on the instance members
+#if 1
+    int dosemantic3 = 0;
+    {	Array *a;
+	int i;
+
+	if (sc->scopesym && sc->scopesym->members && !sc->scopesym->isTemplateMixin())
+	{
+	    //printf("\t1: adding to %s %s\n", sc->scopesym->kind(), sc->scopesym->toChars());
+	    a = sc->scopesym->members;
+	}
+	else
+	{   Module *m = sc->module->importedFrom;
+	    //printf("\t2: adding to module %s\n", m->toChars());
+	    a = m->members;
+	    if (m->semanticdone >= 3)
+		dosemantic3 = 1;
+	}
+	for (i = 0; 1; i++)
+	{
+	    if (i == a->dim)
+	    {
+		a->push(this);
+		break;
+	    }
+	    if (this == (Dsymbol *)a->data[i])	// if already in Array
+		break;
+	}
+    }
+#endif
+
+    // Copy the syntax trees from the TemplateDeclaration
+    members = Dsymbol::arraySyntaxCopy(tempdecl->members);
+
+    // Create our own scope for the template parameters
+    Scope *scope = tempdecl->scope;
+    if (!scope)
+    {
+	error("forward reference to template declaration %s\n", tempdecl->toChars());
+	return;
+    }
+
+#if LOG
+    printf("\tcreate scope for template parameters '%s'\n", toChars());
+#endif
+    argsym = new ScopeDsymbol();
+    argsym->parent = scope->parent;
+    scope = scope->push(argsym);
+
+    // Declare each template parameter as an alias for the argument type
+    declareParameters(scope);
+
+    // Add members of template instance to template instance symbol table
+//    parent = scope->scopesym;
+    symtab = new DsymbolTable();
+    int memnum = 0;
+    for (int i = 0; i < members->dim; i++)
+    {
+	Dsymbol *s = (Dsymbol *)members->data[i];
+#if LOG
+	printf("\t[%d] adding member '%s' %p kind %s to '%s', memnum = %d\n", i, s->toChars(), s, s->kind(), this->toChars(), memnum);
+#endif
+	memnum |= s->addMember(scope, this, memnum);
+    }
+#if LOG
+    printf("adding members done\n");
+#endif
+
+    /* See if there is only one member of template instance, and that
+     * member has the same name as the template instance.
+     * If so, this template instance becomes an alias for that member.
+     */
+    //printf("members->dim = %d\n", members->dim);
+    if (members->dim)
+    {
+	Dsymbol *s;
+	if (Dsymbol::oneMembers(members, &s) && s)
+	{
+	    //printf("s->kind = '%s'\n", s->kind());
+	    //s->print();
+	    //printf("'%s', '%s'\n", s->ident->toChars(), tempdecl->ident->toChars());
+	    if (s->ident && s->ident->equals(tempdecl->ident))
+	    {
+		//printf("setting aliasdecl\n");
+		aliasdecl = new AliasDeclaration(loc, s->ident, s);
+	    }
+	}
+    }
+
+    // Do semantic() analysis on template instance members
+#if LOG
+    printf("\tdo semantic() on template instance members '%s'\n", toChars());
+#endif
+    Scope *sc2;
+    sc2 = scope->push(this);
+    //printf("isnested = %d, sc->parent = %s\n", isnested, sc->parent->toChars());
+    sc2->parent = /*isnested ? sc->parent :*/ this;
+
+#if _WIN32
+  __try
+  {
+#endif
+    for (int i = 0; i < members->dim; i++)
+    {
+	Dsymbol *s = (Dsymbol *)members->data[i];
+	//printf("\t[%d] semantic on '%s' %p kind %s in '%s'\n", i, s->toChars(), s, s->kind(), this->toChars());
+	//printf("test: isnested = %d, sc2->parent = %s\n", isnested, sc2->parent->toChars());
+//	if (isnested)
+//	    s->parent = sc->parent;
+	//printf("test3: isnested = %d, s->parent = %s\n", isnested, s->parent->toChars());
+	s->semantic(sc2);
+	//printf("test4: isnested = %d, s->parent = %s\n", isnested, s->parent->toChars());
+	sc2->module->runDeferredSemantic();
+    }
+#if _WIN32
+  }
+  __except (__ehfilter(GetExceptionInformation()))
+  {
+    global.gag = 0;			// ensure error message gets printed
+    error("recursive expansion");
+    fatal();
+  }
+#endif
+
+    /* If any of the instantiation members didn't get semantic() run
+     * on them due to forward references, we cannot run semantic2()
+     * or semantic3() yet.
+     */
+    for (size_t i = 0; i < Module::deferred.dim; i++)
+    {	Dsymbol *sd = (Dsymbol *)Module::deferred.data[i];
+
+	if (sd->parent == this)
+	    goto Laftersemantic;
+    }
+
+    /* The problem is when to parse the initializer for a variable.
+     * Perhaps VarDeclaration::semantic() should do it like it does
+     * for initializers inside a function.
+     */
+//    if (sc->parent->isFuncDeclaration())
+
+	/* BUG 782: this has problems if the classes this depends on
+	 * are forward referenced. Find a way to defer semantic()
+	 * on this template.
+	 */
+	semantic2(sc2);
+
+    if (sc->func || dosemantic3)
+    {
+	semantic3(sc2);
+    }
+
+  Laftersemantic:
+    sc2->pop();
+
+    scope->pop();
+
+    // Give additional context info if error occurred during instantiation
+    if (global.errors != errorsave)
+    {
+	error("error instantiating");
+	errors = 1;
+	if (global.gag)
+	    tempdecl->instances.remove(tempdecl_instance_idx);
+    }
+
+#if LOG
+    printf("-TemplateInstance::semantic('%s', this=%p)\n", toChars(), this);
+#endif
+}
+
+
+void TemplateInstance::semanticTiargs(Scope *sc)
+{
+    //printf("+TemplateInstance::semanticTiargs() %s\n", toChars());
+    semanticTiargs(loc, sc, tiargs);
+}
+
+void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs)
+{
+    // Run semantic on each argument, place results in tiargs[]
+    //printf("+TemplateInstance::semanticTiargs() %s\n", toChars());
+    if (!tiargs)
+	return;
+    for (size_t j = 0; j < tiargs->dim; j++)
+    {
+	Object *o = (Object *)tiargs->data[j];
+	Type *ta = isType(o);
+	Expression *ea = isExpression(o);
+	Dsymbol *sa = isDsymbol(o);
+
+	//printf("1: tiargs->data[%d] = %p, %p, %p\n", j, o, isDsymbol(o), isTuple(o));
+	if (ta)
+	{
+	    //printf("type %s\n", ta->toChars());
+	    // It might really be an Expression or an Alias
+	    ta->resolve(loc, sc, &ea, &ta, &sa);
+	    if (ea)
+	    {
+		ea = ea->semantic(sc);
+		ea = ea->optimize(WANTvalue | WANTinterpret);
+		tiargs->data[j] = ea;
+	    }
+	    else if (sa)
+	    {	tiargs->data[j] = sa;
+		TupleDeclaration *d = sa->toAlias()->isTupleDeclaration();
+		if (d)
+		{
+		    size_t dim = d->objects->dim;
+		    tiargs->remove(j);
+		    tiargs->insert(j, d->objects);
+		    j--;
+		}
+	    }
+	    else if (ta)
+	    {
+		if (ta->ty == Ttuple)
+		{   // Expand tuple
+		    TypeTuple *tt = (TypeTuple *)ta;
+		    size_t dim = tt->arguments->dim;
+		    tiargs->remove(j);
+		    if (dim)
+		    {	tiargs->reserve(dim);
+			for (size_t i = 0; i < dim; i++)
+			{   Argument *arg = (Argument *)tt->arguments->data[i];
+			    tiargs->insert(j + i, arg->type);
+			}
+		    }
+		    j--;
+		}
+		else
+		    tiargs->data[j] = ta;
+	    }
+	    else
+	    {
+		assert(global.errors);
+		tiargs->data[j] = Type::terror;
+	    }
+	}
+	else if (ea)
+	{
+	    if (!ea)
+	    {	assert(global.errors);
+		ea = new IntegerExp(0);
+	    }
+	    assert(ea);
+	    ea = ea->semantic(sc);
+	    ea = ea->optimize(WANTvalue | WANTinterpret);
+	    tiargs->data[j] = ea;
+	}
+	else if (sa)
+	{
+	}
+	else
+	{
+	    assert(0);
+	}
+	//printf("1: tiargs->data[%d] = %p\n", j, tiargs->data[j]);
+    }
+#if 0
+    printf("-TemplateInstance::semanticTiargs('%s', this=%p)\n", toChars(), this);
+    for (size_t j = 0; j < tiargs->dim; j++)
+    {
+	Object *o = (Object *)tiargs->data[j];
+	Type *ta = isType(o);
+	Expression *ea = isExpression(o);
+	Dsymbol *sa = isDsymbol(o);
+	Tuple *va = isTuple(o);
+
+	printf("\ttiargs[%d] = ta %p, ea %p, sa %p, va %p\n", j, ta, ea, sa, va);
+    }
+#endif
+}
+
+/**********************************************
+ * Find template declaration corresponding to template instance.
+ */
+
+TemplateDeclaration *TemplateInstance::findTemplateDeclaration(Scope *sc)
+{
+    //printf("TemplateInstance::findTemplateDeclaration() %s\n", toChars());
+    if (!tempdecl)
+    {
+	/* Given:
+	 *    foo!( ... )
+	 * figure out which TemplateDeclaration foo refers to.
+	 */
+	Dsymbol *s;
+	Dsymbol *scopesym;
+	Identifier *id;
+	int i;
+
+	id = name;
+	s = sc->search(loc, id, &scopesym);
+	if (!s)
+	{   error("identifier '%s' is not defined", id->toChars());
+	    return NULL;
+	}
+#if LOG
+	printf("It's an instance of '%s' kind '%s'\n", s->toChars(), s->kind());
+	printf("s->parent = '%s'\n", s->parent->toChars());
+#endif
+	withsym = scopesym->isWithScopeSymbol();
+
+	/* We might have found an alias within a template when
+	 * we really want the template.
+	 */
+	TemplateInstance *ti;
+	if (s->parent &&
+	    (ti = s->parent->isTemplateInstance()) != NULL)
+	{
+	    if (
+		(ti->name == id ||
+		 ti->toAlias()->ident == id)
+		&&
+		ti->tempdecl)
+	    {
+		/* This is so that one can refer to the enclosing
+		 * template, even if it has the same name as a member
+		 * of the template, if it has a !(arguments)
+		 */
+		tempdecl = ti->tempdecl;
+		if (tempdecl->overroot)		// if not start of overloaded list of TemplateDeclaration's
+		    tempdecl = tempdecl->overroot; // then get the start
+		s = tempdecl;
+	    }
+	}
+
+	s = s->toAlias();
+
+	/* It should be a TemplateDeclaration, not some other symbol
+	 */
+	tempdecl = s->isTemplateDeclaration();
+	if (!tempdecl)
+	{
+	    if (!s->parent && global.errors)
+		return NULL;
+	    if (!s->parent && s->getType())
+	    {	Dsymbol *s2 = s->getType()->toDsymbol(sc);
+		if (!s2)
+		{
+		    error("%s is not a template declaration, it is a %s", id->toChars(), s->kind());
+		    return NULL;
+		}
+		s = s2;
+	    }
+#ifdef DEBUG
+	    //if (!s->parent) printf("s = %s %s\n", s->kind(), s->toChars());
+#endif
+	    //assert(s->parent);
+	    TemplateInstance *ti = s->parent ? s->parent->isTemplateInstance() : NULL;
+	    if (ti &&
+		(ti->name == id ||
+		 ti->toAlias()->ident == id)
+		&&
+		ti->tempdecl)
+	    {
+		/* This is so that one can refer to the enclosing
+		 * template, even if it has the same name as a member
+		 * of the template, if it has a !(arguments)
+		 */
+		tempdecl = ti->tempdecl;
+		if (tempdecl->overroot)		// if not start of overloaded list of TemplateDeclaration's
+		    tempdecl = tempdecl->overroot; // then get the start
+	    }
+	    else
+	    {
+		error("%s is not a template declaration, it is a %s", id->toChars(), s->kind());
+		return NULL;
+	    }
+	}
+    }
+    else
+	assert(tempdecl->isTemplateDeclaration());
+    return tempdecl;
+}
+
+TemplateDeclaration *TemplateInstance::findBestMatch(Scope *sc)
+{
+    /* Since there can be multiple TemplateDeclaration's with the same
+     * name, look for the best match.
+     */
+    TemplateDeclaration *td_ambig = NULL;
+    TemplateDeclaration *td_best = NULL;
+    MATCH m_best = MATCHnomatch;
+    Objects dedtypes;
+
+#if LOG
+    printf("TemplateInstance::findBestMatch()\n");
+#endif
+    for (TemplateDeclaration *td = tempdecl; td; td = td->overnext)
+    {
+	MATCH m;
+
+//if (tiargs->dim) printf("2: tiargs->dim = %d, data[0] = %p\n", tiargs->dim, tiargs->data[0]);
+
+	// If more arguments than parameters,
+	// then this is no match.
+	if (td->parameters->dim < tiargs->dim)
+	{
+	    if (!td->isVariadic())
+		continue;
+	}
+
+	dedtypes.setDim(td->parameters->dim);
+	if (!td->scope)
+	{
+	    error("forward reference to template declaration %s", td->toChars());
+	    return NULL;
+	}
+	m = td->matchWithInstance(this, &dedtypes, 0);
+	if (!m)			// no match at all
+	    continue;
+
+#if 1
+	if (m < m_best)
+	    goto Ltd_best;
+	if (m > m_best)
+	    goto Ltd;
+#else
+	if (!m_best)
+	    goto Ltd;
+#endif
+	{
+	// Disambiguate by picking the most specialized TemplateDeclaration
+	int c1 = td->leastAsSpecialized(td_best);
+	int c2 = td_best->leastAsSpecialized(td);
+	//printf("c1 = %d, c2 = %d\n", c1, c2);
+
+	if (c1 && !c2)
+	    goto Ltd;
+	else if (!c1 && c2)
+	    goto Ltd_best;
+	else
+	    goto Lambig;
+	}
+
+      Lambig:		// td_best and td are ambiguous
+	td_ambig = td;
+	continue;
+
+      Ltd_best:		// td_best is the best match so far
+	td_ambig = NULL;
+	continue;
+
+      Ltd:		// td is the new best match
+	td_ambig = NULL;
+	td_best = td;
+	m_best = m;
+	tdtypes.setDim(dedtypes.dim);
+	memcpy(tdtypes.data, dedtypes.data, tdtypes.dim * sizeof(void *));
+	continue;
+    }
+
+    if (!td_best)
+    {
+	error("%s does not match any template declaration", toChars());
+	return NULL;
+    }
+    if (td_ambig)
+    {
+	error("%s matches more than one template declaration, %s and %s",
+		toChars(), td_best->toChars(), td_ambig->toChars());
+    }
+
+    /* The best match is td_best
+     */
+    tempdecl = td_best;
+
+#if 0
+    /* Cast any value arguments to be same type as value parameter
+     */
+    for (size_t i = 0; i < tiargs->dim; i++)
+    {	Object *o = (Object *)tiargs->data[i];
+	Expression *ea = isExpression(o);	// value argument
+	TemplateParameter *tp = (TemplateParameter *)tempdecl->parameters->data[i];
+	assert(tp);
+	TemplateValueParameter *tvp = tp->isTemplateValueParameter();
+	if (tvp)
+	{
+	    assert(ea);
+	    ea = ea->castTo(tvp->valType);
+	    ea = ea->optimize(WANTvalue | WANTinterpret);
+	    tiargs->data[i] = (Object *)ea;
+	}
+    }
+#endif
+
+#if LOG
+    printf("\tIt's a match with template declaration '%s'\n", tempdecl->toChars());
+#endif
+    return tempdecl;
+}
+
+
+/*****************************************
+ * Determines if a TemplateInstance will need a nested
+ * generation of the TemplateDeclaration.
+ */
+
+int TemplateInstance::isNested(Objects *args)
+{   int nested = 0;
+    //printf("TemplateInstance::isNested('%s')\n", tempdecl->ident->toChars());
+
+    /* A nested instance happens when an argument references a local
+     * symbol that is on the stack.
+     */
+    for (size_t i = 0; i < args->dim; i++)
+    {   Object *o = (Object *)args->data[i];
+	Expression *ea = isExpression(o);
+	Dsymbol *sa = isDsymbol(o);
+	Tuple *va = isTuple(o);
+	if (ea)
+	{
+	    if (ea->op == TOKvar)
+	    {
+		sa = ((VarExp *)ea)->var;
+		goto Lsa;
+	    }
+	    if (ea->op == TOKfunction)
+	    {
+		sa = ((FuncExp *)ea)->fd;
+		goto Lsa;
+	    }
+	}
+	else if (sa)
+	{
+	  Lsa:
+	    Declaration *d = sa->isDeclaration();
+	    if (d && !d->isDataseg() &&
+		(!d->isFuncDeclaration() || d->isFuncDeclaration()->isNested()) &&
+		!isTemplateMixin())
+	    {
+		// if module level template
+		if (tempdecl->toParent()->isModule())
+		{
+		    if (isnested && isnested != d->toParent())
+			error("inconsistent nesting levels %s and %s", isnested->toChars(), d->toParent()->toChars());
+		    isnested = d->toParent();
+		    nested |= 1;
+		}
+		else
+		    error("cannot use local '%s' as template parameter", d->toChars());
+	    }
+	}
+	else if (va)
+	{
+	    nested |= isNested(&va->objects);
+	}
+    }
+    return nested;
+}
+
+/****************************************
+ * This instance needs an identifier for name mangling purposes.
+ * Create one by taking the template declaration name and adding
+ * the type signature for it.
+ */
+
+Identifier *TemplateInstance::genIdent()
+{   OutBuffer buf;
+    char *id;
+    Objects *args;
+
+    //printf("TemplateInstance::genIdent('%s')\n", tempdecl->ident->toChars());
+    id = tempdecl->ident->toChars();
+    buf.printf("__T%zu%s", strlen(id), id);
+    args = tiargs;
+    for (int i = 0; i < args->dim; i++)
+    {   Object *o = (Object *)args->data[i];
+	Type *ta = isType(o);
+	Expression *ea = isExpression(o);
+	Dsymbol *sa = isDsymbol(o);
+	Tuple *va = isTuple(o);
+	//printf("\to %p ta %p ea %p sa %p va %p\n", o, ta, ea, sa, va);
+	if (ta)
+	{
+	    buf.writeByte('T');
+	    if (ta->deco)
+		buf.writestring(ta->deco);
+	    else
+	    {
+#ifdef DEBUG
+		printf("ta = %d, %s\n", ta->ty, ta->toChars());
+#endif
+		assert(global.errors);
+	    }
+	}
+	else if (ea)
+	{   sinteger_t v;
+	    real_t r;
+	    unsigned char *p;
+
+	    if (ea->op == TOKvar)
+	    {
+		sa = ((VarExp *)ea)->var;
+		ea = NULL;
+		goto Lsa;
+	    }
+	    if (ea->op == TOKfunction)
+	    {
+		sa = ((FuncExp *)ea)->fd;
+		ea = NULL;
+		goto Lsa;
+	    }
+	    buf.writeByte('V');
+	    if (ea->op == TOKtuple)
+	    {	ea->error("tuple is not a valid template value argument");
+		continue;
+	    }
+#if 1
+	    buf.writestring(ea->type->deco);
+#else
+	    // Use type of parameter, not type of argument
+	    TemplateParameter *tp = (TemplateParameter *)tempdecl->parameters->data[i];
+	    assert(tp);
+	    TemplateValueParameter *tvp = tp->isTemplateValueParameter();
+	    assert(tvp);
+	    buf.writestring(tvp->valType->deco);
+#endif
+	    ea->toMangleBuffer(&buf);
+	}
+	else if (sa)
+	{
+	  Lsa:
+	    buf.writeByte('S');
+	    Declaration *d = sa->isDeclaration();
+	    if (d && !d->type->deco)
+		error("forward reference of %s", d->toChars());
+	    else
+	    {
+		char *p = sa->mangle();
+		buf.printf("%zu%s", strlen(p), p);
+	    }
+	}
+	else if (va)
+	{
+	    assert(i + 1 == args->dim);		// must be last one
+	    args = &va->objects;
+	    i = -1;
+	}
+	else
+	    assert(0);
+    }
+    buf.writeByte('Z');
+    id = buf.toChars();
+    buf.data = NULL;
+    return new Identifier(id, TOKidentifier);
+}
+
+
+/****************************************************
+ * Declare parameters of template instance, initialize them with the
+ * template instance arguments.
+ */
+
+void TemplateInstance::declareParameters(Scope *scope)
+{
+    //printf("TemplateInstance::declareParameters()\n");
+    for (int i = 0; i < tdtypes.dim; i++)
+    {
+	TemplateParameter *tp = (TemplateParameter *)tempdecl->parameters->data[i];
+	//Object *o = (Object *)tiargs->data[i];
+	Object *o = (Object *)tdtypes.data[i];
+
+	//printf("\ttdtypes[%d] = %p\n", i, o);
+	tempdecl->declareParameter(scope, tp, o);
+    }
+}
+
+
+void TemplateInstance::semantic2(Scope *sc)
+{   int i;
+
+    if (semanticdone >= 2)
+	return;
+    semanticdone = 2;
+#if LOG
+    printf("+TemplateInstance::semantic2('%s')\n", toChars());
+#endif
+    if (!errors && members)
+    {
+	sc = tempdecl->scope;
+	assert(sc);
+	sc = sc->push(argsym);
+	sc = sc->push(this);
+	for (i = 0; i < members->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)members->data[i];
+#if LOG
+printf("\tmember '%s', kind = '%s'\n", s->toChars(), s->kind());
+#endif
+	    s->semantic2(sc);
+	}
+	sc = sc->pop();
+	sc->pop();
+    }
+#if LOG
+    printf("-TemplateInstance::semantic2('%s')\n", toChars());
+#endif
+}
+
+void TemplateInstance::semantic3(Scope *sc)
+{   int i;
+
+#if LOG
+    printf("TemplateInstance::semantic3('%s'), semanticdone = %d\n", toChars(), semanticdone);
+#endif
+//if (toChars()[0] == 'D') *(char*)0=0;
+    if (semanticdone >= 3)
+	return;
+    semanticdone = 3;
+    if (!errors && members)
+    {
+	sc = tempdecl->scope;
+	sc = sc->push(argsym);
+	sc = sc->push(this);
+	for (i = 0; i < members->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)members->data[i];
+	    s->semantic3(sc);
+	}
+	sc = sc->pop();
+	sc->pop();
+    }
+}
+
+void TemplateInstance::toObjFile()
+{   int i;
+
+#if LOG
+    printf("TemplateInstance::toObjFile('%s', this = %p)\n", toChars(), this);
+#endif
+    if (!errors && members)
+    {
+	for (i = 0; i < members->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)members->data[i];
+	    s->toObjFile();
+	}
+    }
+}
+
+void TemplateInstance::inlineScan()
+{   int i;
+
+#if LOG
+    printf("TemplateInstance::inlineScan('%s')\n", toChars());
+#endif
+    if (!errors && members)
+    {
+	for (i = 0; i < members->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)members->data[i];
+	    s->inlineScan();
+	}
+    }
+}
+
+void TemplateInstance::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    int i;
+
+    Identifier *id = name;
+    buf->writestring(id->toChars());
+    buf->writestring("!(");
+    if (nest)
+	buf->writestring("...");
+    else
+    {
+	nest++;
+	Objects *args = tiargs;
+	for (i = 0; i < args->dim; i++)
+	{
+	    if (i)
+		buf->writeByte(',');
+	    Object *oarg = (Object *)args->data[i];
+	    ObjectToCBuffer(buf, hgs, oarg);
+	}
+	nest--;
+    }
+    buf->writeByte(')');
+}
+
+
+Dsymbol *TemplateInstance::toAlias()
+{
+#if LOG
+    printf("TemplateInstance::toAlias()\n");
+#endif
+    if (!inst)
+    {	error("cannot resolve forward reference");
+	return this;
+    }
+
+    if (inst != this)
+	return inst->toAlias();
+
+    if (aliasdecl)
+	return aliasdecl->toAlias();
+
+    return inst;
+}
+
+AliasDeclaration *TemplateInstance::isAliasDeclaration()
+{
+    return aliasdecl;
+}
+
+char *TemplateInstance::kind()
+{
+    return "template instance";
+}
+
+int TemplateInstance::oneMember(Dsymbol **ps)
+{
+    *ps = NULL;
+    return TRUE;
+}
+
+char *TemplateInstance::toChars()
+{
+    OutBuffer buf;
+    HdrGenState hgs;
+    char *s;
+
+    toCBuffer(&buf, &hgs);
+    s = buf.toChars();
+    buf.data = NULL;
+    return s;
+}
+
+/* ======================== TemplateMixin ================================ */
+
+TemplateMixin::TemplateMixin(Loc loc, Identifier *ident, Type *tqual,
+	Array *idents, Objects *tiargs)
+	: TemplateInstance(loc, (Identifier *)idents->data[idents->dim - 1])
+{
+    //printf("TemplateMixin(ident = '%s')\n", ident ? ident->toChars() : "");
+    this->ident = ident;
+    this->tqual = tqual;
+    this->idents = idents;
+    this->tiargs = tiargs ? tiargs : new Objects();
+    this->scope = NULL;
+}
+
+Dsymbol *TemplateMixin::syntaxCopy(Dsymbol *s)
+{   TemplateMixin *tm;
+
+    Array *ids = new Array();
+    ids->setDim(idents->dim);
+    for (int i = 0; i < idents->dim; i++)
+    {	// Matches TypeQualified::syntaxCopyHelper()
+        Identifier *id = (Identifier *)idents->data[i];
+        if (id->dyncast() == DYNCAST_DSYMBOL)
+        {
+            TemplateInstance *ti = (TemplateInstance *)id;
+
+            ti = (TemplateInstance *)ti->syntaxCopy(NULL);
+            id = (Identifier *)ti;
+        }
+        ids->data[i] = id;
+    }
+
+    tm = new TemplateMixin(loc, ident,
+		(Type *)(tqual ? tqual->syntaxCopy() : NULL),
+		ids, tiargs);
+    TemplateInstance::syntaxCopy(tm);
+    return tm;
+}
+
+void TemplateMixin::semantic(Scope *sc)
+{
+#if LOG
+    printf("+TemplateMixin::semantic('%s', this=%p)\n", toChars(), this);
+    fflush(stdout);
+#endif
+    if (semanticdone &&
+	// This for when a class/struct contains mixin members, and
+	// is done over because of forward references
+	(!parent || !toParent()->isAggregateDeclaration()))
+    {
+#if LOG
+	printf("\tsemantic done\n");
+#endif
+	return;
+    }
+    if (!semanticdone)
+	semanticdone = 1;
+#if LOG
+    printf("\tdo semantic\n");
+#endif
+
+    Scope *scx = NULL;
+    if (scope)
+    {	sc = scope;
+	scx = scope;		// save so we don't make redundant copies
+	scope = NULL;
+    }
+
+    // Follow qualifications to find the TemplateDeclaration
+    if (!tempdecl)
+    {	Dsymbol *s;
+	int i;
+	Identifier *id;
+
+	if (tqual)
+	{   s = tqual->toDsymbol(sc);
+	    i = 0;
+	}
+	else
+	{
+	    i = 1;
+	    id = (Identifier *)idents->data[0];
+	    switch (id->dyncast())
+	    {
+		case DYNCAST_IDENTIFIER:
+		    s = sc->search(loc, id, NULL);
+		    break;
+
+		case DYNCAST_DSYMBOL:
+		{
+		    TemplateInstance *ti = (TemplateInstance *)id;
+		    ti->semantic(sc);
+		    s = ti;
+		    break;
+		}
+		default:
+		    assert(0);
+	    }
+	}
+
+	for (; i < idents->dim; i++)
+	{
+	    if (!s)
+		break;
+	    id = (Identifier *)idents->data[i];
+	    s = s->searchX(loc, sc, id);
+	}
+	if (!s)
+	{
+	    error("is not defined");
+	    inst = this;
+	    return;
+	}
+	tempdecl = s->toAlias()->isTemplateDeclaration();
+	if (!tempdecl)
+	{
+	    error("%s isn't a template", s->toChars());
+	    inst = this;
+	    return;
+	}
+    }
+
+    // Look for forward reference
+    assert(tempdecl);
+    for (TemplateDeclaration *td = tempdecl; td; td = td->overnext)
+    {
+	if (!td->scope)
+	{
+	    /* Cannot handle forward references if mixin is a struct member,
+	     * because addField must happen during struct's semantic, not
+	     * during the mixin semantic.
+	     * runDeferred will re-run mixin's semantic outside of the struct's
+	     * semantic.
+	     */
+	    semanticdone = 0;
+	    AggregateDeclaration *ad = toParent()->isAggregateDeclaration();
+	    if (ad)
+		ad->sizeok = 2;
+	    else
+	    {
+		// Forward reference
+		//printf("forward reference - deferring\n");
+		scope = scx ? scx : new Scope(*sc);
+		scope->setNoFree();
+		scope->module->addDeferredSemantic(this);
+	    }
+	    return;
+	}
+    }
+
+    // Run semantic on each argument, place results in tiargs[]
+    semanticTiargs(sc);
+
+    tempdecl = findBestMatch(sc);
+    if (!tempdecl)
+    {	inst = this;
+	return;		// error recovery
+    }
+
+    if (!ident)
+	ident = genIdent();
+
+    inst = this;
+    parent = sc->parent;
+
+    /* Detect recursive mixin instantiations.
+     */
+    for (Dsymbol *s = parent; s; s = s->parent)
+    {
+	//printf("\ts = '%s'\n", s->toChars());
+	TemplateMixin *tm = s->isTemplateMixin();
+	if (!tm || tempdecl != tm->tempdecl)
+	    continue;
+
+	for (int i = 0; i < tiargs->dim; i++)
+	{   Object *o = (Object *)tiargs->data[i];
+	    Type *ta = isType(o);
+	    Expression *ea = isExpression(o);
+	    Dsymbol *sa = isDsymbol(o);
+	    Object *tmo = (Object *)tm->tiargs->data[i];
+	    if (ta)
+	    {
+		Type *tmta = isType(tmo);
+		if (!tmta)
+		    goto Lcontinue;
+		if (!ta->equals(tmta))
+		    goto Lcontinue;
+	    }
+	    else if (ea)
+	    {	Expression *tme = isExpression(tmo);
+		if (!tme || !ea->equals(tme))
+		    goto Lcontinue;
+	    }
+	    else if (sa)
+	    {
+		Dsymbol *tmsa = isDsymbol(tmo);
+		if (sa != tmsa)
+		    goto Lcontinue;
+	    }
+	    else
+		assert(0);
+	}
+	error("recursive mixin instantiation");
+	return;
+
+    Lcontinue:
+	continue;
+    }
+
+    // Copy the syntax trees from the TemplateDeclaration
+    members = Dsymbol::arraySyntaxCopy(tempdecl->members);
+    if (!members)
+	return;
+
+    symtab = new DsymbolTable();
+
+    for (Scope *sce = sc; 1; sce = sce->enclosing)
+    {
+	ScopeDsymbol *sds = (ScopeDsymbol *)sce->scopesym;
+	if (sds)
+	{
+	    sds->importScope(this, PROTpublic);
+	    break;
+	}
+    }
+
+#if LOG
+    printf("\tcreate scope for template parameters '%s'\n", toChars());
+#endif
+    Scope *scy = sc;
+    scy = sc->push(this);
+    scy->parent = this;
+
+    argsym = new ScopeDsymbol();
+    argsym->parent = scy->parent;
+    Scope *scope = scy->push(argsym);
+
+    // Declare each template parameter as an alias for the argument type
+    declareParameters(scope);
+
+    // Add members to enclosing scope, as well as this scope
+    for (unsigned i = 0; i < members->dim; i++)
+    {   Dsymbol *s;
+
+	s = (Dsymbol *)members->data[i];
+	s->addMember(scope, this, i);
+	//sc->insert(s);
+	//printf("sc->parent = %p, sc->scopesym = %p\n", sc->parent, sc->scopesym);
+	//printf("s->parent = %s\n", s->parent->toChars());
+    }
+
+    // Do semantic() analysis on template instance members
+#if LOG
+    printf("\tdo semantic() on template instance members '%s'\n", toChars());
+#endif
+    Scope *sc2;
+    sc2 = scope->push(this);
+    sc2->offset = sc->offset;
+    for (int i = 0; i < members->dim; i++)
+    {
+	Dsymbol *s = (Dsymbol *)members->data[i];
+	s->semantic(sc2);
+    }
+    sc->offset = sc2->offset;
+
+    /* The problem is when to parse the initializer for a variable.
+     * Perhaps VarDeclaration::semantic() should do it like it does
+     * for initializers inside a function.
+     */
+//    if (sc->parent->isFuncDeclaration())
+
+	semantic2(sc2);
+
+    if (sc->func)
+    {
+	semantic3(sc2);
+    }
+
+    sc2->pop();
+
+    scope->pop();
+
+//    if (!isAnonymous())
+    {
+	scy->pop();
+    }
+#if LOG
+    printf("-TemplateMixin::semantic('%s', this=%p)\n", toChars(), this);
+#endif
+}
+
+void TemplateMixin::semantic2(Scope *sc)
+{   int i;
+
+    if (semanticdone >= 2)
+	return;
+    semanticdone = 2;
+#if LOG
+    printf("+TemplateMixin::semantic2('%s')\n", toChars());
+#endif
+    if (members)
+    {
+	assert(sc);
+	sc = sc->push(argsym);
+	sc = sc->push(this);
+	for (i = 0; i < members->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)members->data[i];
+#if LOG
+	    printf("\tmember '%s', kind = '%s'\n", s->toChars(), s->kind());
+#endif
+	    s->semantic2(sc);
+	}
+	sc = sc->pop();
+	sc->pop();
+    }
+#if LOG
+    printf("-TemplateMixin::semantic2('%s')\n", toChars());
+#endif
+}
+
+void TemplateMixin::semantic3(Scope *sc)
+{   int i;
+
+    if (semanticdone >= 3)
+	return;
+    semanticdone = 3;
+#if LOG
+    printf("TemplateMixin::semantic3('%s')\n", toChars());
+#endif
+    if (members)
+    {
+	sc = sc->push(argsym);
+	sc = sc->push(this);
+	for (i = 0; i < members->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)members->data[i];
+	    s->semantic3(sc);
+	}
+	sc = sc->pop();
+	sc->pop();
+    }
+}
+
+void TemplateMixin::inlineScan()
+{
+    TemplateInstance::inlineScan();
+}
+
+char *TemplateMixin::kind()
+{
+    return "mixin";
+}
+
+int TemplateMixin::oneMember(Dsymbol **ps)
+{
+    return Dsymbol::oneMember(ps);
+}
+
+int TemplateMixin::hasPointers()
+{
+    //printf("TemplateMixin::hasPointers() %s\n", toChars());
+    for (size_t i = 0; i < members->dim; i++)
+    {
+	Dsymbol *s = (Dsymbol *)members->data[i];
+	//printf(" s = %s %s\n", s->kind(), s->toChars());
+	if (s->hasPointers())
+	{
+	    return 1;
+	}
+    }
+    return 0;
+}
+
+char *TemplateMixin::toChars()
+{
+    OutBuffer buf;
+    HdrGenState hgs;
+    char *s;
+
+    TemplateInstance::toCBuffer(&buf, &hgs);
+    s = buf.toChars();
+    buf.data = NULL;
+    return s;
+}
+
+void TemplateMixin::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("mixin ");
+    int i;
+    for (i = 0; i < idents->dim; i++)
+    {   Identifier *id = (Identifier *)idents->data[i];
+
+    	if (i)
+	    buf->writeByte('.');
+	buf->writestring(id->toChars());
+    }
+    buf->writestring("!(");
+    if (tiargs)
+    {
+        for (i = 0; i < tiargs->dim; i++)
+        {   if (i)
+                buf->writebyte(',');
+	    Object *oarg = (Object *)tiargs->data[i];
+	    Type *t = isType(oarg);
+	    Expression *e = isExpression(oarg);
+	    Dsymbol *s = isDsymbol(oarg);
+	    if (t)
+		t->toCBuffer(buf, NULL, hgs);
+	    else if (e)
+		e->toCBuffer(buf, hgs);
+	    else if (s)
+	    {
+		char *p = s->ident ? s->ident->toChars() : s->toChars();
+		buf->writestring(p);
+	    }
+	    else if (!oarg)
+	    {
+		buf->writestring("NULL");
+	    }
+	    else
+	    {
+		assert(0);
+	    }
+        }
+    }
+    buf->writebyte(')');
+    buf->writebyte(';');
+    buf->writenl();
+}
+
+
+void TemplateMixin::toObjFile()
+{
+    //printf("TemplateMixin::toObjFile('%s')\n", toChars());
+    TemplateInstance::toObjFile();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/template.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,324 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#ifndef DMD_TEMPLATE_H
+#define DMD_TEMPLATE_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include "root.h"
+#include "arraytypes.h"
+#include "dsymbol.h"
+#include "mtype.h"
+
+
+struct OutBuffer;
+struct Identifier;
+struct TemplateInstance;
+struct TemplateParameter;
+struct TemplateTypeParameter;
+struct TemplateValueParameter;
+struct TemplateAliasParameter;
+struct TemplateTupleParameter;
+struct Type;
+struct TypeTypeof;
+struct Scope;
+struct Expression;
+struct AliasDeclaration;
+struct FuncDeclaration;
+struct HdrGenState;
+enum MATCH;
+
+struct Tuple : Object
+{
+    Objects objects;
+
+    int dyncast() { return DYNCAST_TUPLE; } // kludge for template.isType()
+};
+
+
+struct TemplateDeclaration : ScopeDsymbol
+{
+    TemplateParameters *parameters;	// array of TemplateParameter's
+    Array instances;		// array of TemplateInstance's
+
+    TemplateDeclaration *overnext;	// next overloaded TemplateDeclaration
+    TemplateDeclaration *overroot;	// first in overnext list
+
+    Scope *scope;
+    Dsymbol *onemember;		// if !=NULL then one member of this template
+
+    TemplateDeclaration(Loc loc, Identifier *id, TemplateParameters *parameters, Array *decldefs);
+    Dsymbol *syntaxCopy(Dsymbol *);
+    void semantic(Scope *sc);
+    int overloadInsert(Dsymbol *s);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    char *kind();
+    char *toChars();
+
+    void emitComment(Scope *sc);
+//    void toDocBuffer(OutBuffer *buf);
+
+    MATCH matchWithInstance(TemplateInstance *ti, Objects *atypes, int flag);
+    int leastAsSpecialized(TemplateDeclaration *td2);
+
+    MATCH deduceMatch(Objects *targsi, Expressions *fargs, Objects *dedargs);
+    FuncDeclaration *deduce(Scope *sc, Loc loc, Objects *targsi, Expressions *fargs);
+    void declareParameter(Scope *sc, TemplateParameter *tp, Object *o);
+
+    TemplateDeclaration *isTemplateDeclaration() { return this; }
+
+    TemplateTupleParameter *isVariadic();
+};
+
+struct TemplateParameter
+{
+    /* For type-parameter:
+     *	template Foo(ident)		// specType is set to NULL
+     *	template Foo(ident : specType)
+     * For value-parameter:
+     *	template Foo(valType ident)	// specValue is set to NULL
+     *	template Foo(valType ident : specValue)
+     * For alias-parameter:
+     *	template Foo(alias ident)
+     */
+
+    Loc loc;
+    Identifier *ident;
+
+    Declaration *sparam;
+
+    TemplateParameter(Loc loc, Identifier *ident);
+
+    virtual TemplateTypeParameter  *isTemplateTypeParameter();
+    virtual TemplateValueParameter *isTemplateValueParameter();
+    virtual TemplateAliasParameter *isTemplateAliasParameter();
+    virtual TemplateTupleParameter *isTemplateTupleParameter();
+
+    virtual TemplateParameter *syntaxCopy() = 0;
+    virtual void declareParameter(Scope *sc) = 0;
+    virtual void semantic(Scope *) = 0;
+    virtual void print(Object *oarg, Object *oded) = 0;
+    virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs) = 0;
+    virtual Object *specialization() = 0;
+    virtual Object *defaultArg(Scope *sc) = 0;
+
+    /* If TemplateParameter's match as far as overloading goes.
+     */
+    virtual int overloadMatch(TemplateParameter *) = 0;
+
+    /* Match actual argument against parameter.
+     */
+    virtual MATCH matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam) = 0;
+
+    /* Create dummy argument based on parameter.
+     */
+    virtual void *dummyArg() = 0;
+};
+
+struct TemplateTypeParameter : TemplateParameter
+{
+    /* Syntax:
+     *	ident : specType = defaultType
+     */
+    Type *specType;	// type parameter: if !=NULL, this is the type specialization
+    Type *defaultType;
+
+    TemplateTypeParameter(Loc loc, Identifier *ident, Type *specType, Type *defaultType);
+
+    TemplateTypeParameter *isTemplateTypeParameter();
+    TemplateParameter *syntaxCopy();
+    void declareParameter(Scope *sc);
+    void semantic(Scope *);
+    void print(Object *oarg, Object *oded);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    Object *specialization();
+    Object *defaultArg(Scope *sc);
+    int overloadMatch(TemplateParameter *);
+    MATCH matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam);
+    void *dummyArg();
+};
+
+struct TemplateValueParameter : TemplateParameter
+{
+    /* Syntax:
+     *	valType ident : specValue = defaultValue
+     */
+
+    Type *valType;
+    Expression *specValue;
+    Expression *defaultValue;
+
+    static Expression *edummy;
+
+    TemplateValueParameter(Loc loc, Identifier *ident, Type *valType, Expression *specValue, Expression *defaultValue);
+
+    TemplateValueParameter *isTemplateValueParameter();
+    TemplateParameter *syntaxCopy();
+    void declareParameter(Scope *sc);
+    void semantic(Scope *);
+    void print(Object *oarg, Object *oded);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    Object *specialization();
+    Object *defaultArg(Scope *sc);
+    int overloadMatch(TemplateParameter *);
+    MATCH matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam);
+    void *dummyArg();
+};
+
+struct TemplateAliasParameter : TemplateParameter
+{
+    /* Syntax:
+     *	ident : specAlias = defaultAlias
+     */
+
+    Type *specAliasT;
+    Dsymbol *specAlias;
+
+    Type *defaultAlias;
+
+    static Dsymbol *sdummy;
+
+    TemplateAliasParameter(Loc loc, Identifier *ident, Type *specAliasT, Type *defaultAlias);
+
+    TemplateAliasParameter *isTemplateAliasParameter();
+    TemplateParameter *syntaxCopy();
+    void declareParameter(Scope *sc);
+    void semantic(Scope *);
+    void print(Object *oarg, Object *oded);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    Object *specialization();
+    Object *defaultArg(Scope *sc);
+    int overloadMatch(TemplateParameter *);
+    MATCH matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam);
+    void *dummyArg();
+};
+
+struct TemplateTupleParameter : TemplateParameter
+{
+    /* Syntax:
+     *	ident ...
+     */
+
+    TemplateTupleParameter(Loc loc, Identifier *ident);
+
+    TemplateTupleParameter *isTemplateTupleParameter();
+    TemplateParameter *syntaxCopy();
+    void declareParameter(Scope *sc);
+    void semantic(Scope *);
+    void print(Object *oarg, Object *oded);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    Object *specialization();
+    Object *defaultArg(Scope *sc);
+    int overloadMatch(TemplateParameter *);
+    MATCH matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam);
+    void *dummyArg();
+};
+
+struct TemplateInstance : ScopeDsymbol
+{
+    /* Given:
+     *	foo!(args) =>
+     *	    name = foo
+     *	    tiargs = args
+     */
+    Identifier *name;
+    //Array idents;
+    Objects *tiargs;		// Array of Types/Expressions of template
+				// instance arguments [int*, char, 10*10]
+
+    Objects tdtypes;		// Array of Types/Expressions corresponding
+				// to TemplateDeclaration.parameters
+				// [int, char, 100]
+
+    TemplateDeclaration *tempdecl;	// referenced by foo.bar.abc
+    TemplateInstance *inst;		// refer to existing instance
+    ScopeDsymbol *argsym;		// argument symbol table
+    AliasDeclaration *aliasdecl;	// !=NULL if instance is an alias for its
+					// sole member
+    WithScopeSymbol *withsym;		// if a member of a with statement
+    int semanticdone;	// has semantic() been done?
+    int nest;		// for recursion detection
+    int havetempdecl;	// 1 if used second constructor
+    Dsymbol *isnested;	// if referencing local symbols, this is the context
+    int errors;		// 1 if compiled with errors
+#ifdef IN_GCC
+    /* On some targets, it is necessary to know whether a symbol
+       will be emitted in the output or not before the symbol
+       is used.  This can be different from getModule(). */
+    Module * objFileModule;
+#endif
+
+    TemplateInstance(Loc loc, Identifier *temp_id);
+    TemplateInstance(Loc loc, TemplateDeclaration *tempdecl, Objects *tiargs);
+    static Objects *arraySyntaxCopy(Objects *objs);
+    Dsymbol *syntaxCopy(Dsymbol *);
+    void semantic(Scope *sc);
+    void semantic2(Scope *sc);
+    void semantic3(Scope *sc);
+    void inlineScan();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    Dsymbol *toAlias();			// resolve real symbol
+    char *kind();
+    int oneMember(Dsymbol **ps);
+    char *toChars();
+    char *mangle();
+
+    void toObjFile();			// compile to .obj file
+
+    // Internal
+    static void semanticTiargs(Loc loc, Scope *sc, Objects *tiargs);
+    void semanticTiargs(Scope *sc);
+    TemplateDeclaration *findTemplateDeclaration(Scope *sc);
+    TemplateDeclaration *findBestMatch(Scope *sc);
+    void declareParameters(Scope *sc);
+    int isNested(Objects *tiargs);
+    Identifier *genIdent();
+
+    TemplateInstance *isTemplateInstance() { return this; }
+    AliasDeclaration *isAliasDeclaration();
+};
+
+struct TemplateMixin : TemplateInstance
+{
+    Array *idents;
+    Type *tqual;
+
+    Scope *scope;		// for forward referencing
+
+    TemplateMixin(Loc loc, Identifier *ident, Type *tqual, Array *idents, Objects *tiargs);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    void semantic(Scope *sc);
+    void semantic2(Scope *sc);
+    void semantic3(Scope *sc);
+    void inlineScan();
+    char *kind();
+    int oneMember(Dsymbol **ps);
+    int hasPointers();
+    char *toChars();
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+
+    void toObjFile();			// compile to .obj file
+
+    TemplateMixin *isTemplateMixin() { return this; }
+};
+
+Expression *isExpression(Object *o);
+Dsymbol *isDsymbol(Object *o);
+Type *isType(Object *o);
+Tuple *isTuple(Object *o);
+Type *getType(Object *o);
+Dsymbol *getDsymbol(Object *o);
+
+void ObjectToCBuffer(OutBuffer *buf, HdrGenState *hgs, Object *oarg);
+
+#endif /* DMD_TEMPLATE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/total.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,45 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#ifndef DMD_TOTAL_H
+#define DMD_TOTAL_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <wchar.h>
+
+#include "root.h"
+#include "stringtable.h"
+
+#include "arraytypes.h"
+#include "mars.h"
+#include "lexer.h"
+#include "parse.h"
+#include "identifier.h"
+#include "enum.h"
+#include "aggregate.h"
+#include "mtype.h"
+#include "expression.h"
+#include "declaration.h"
+#include "statement.h"
+#include "scope.h"
+#include "import.h"
+#include "module.h"
+#include "id.h"
+#include "cond.h"
+#include "version.h"
+
+#endif /* DMD_TOTAL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/unialpha.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,323 @@
+
+// Copyright (c) 2003 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <assert.h>
+
+/*******************************
+ * Return !=0 if unicode alpha.
+ * Use table from C99 Appendix D.
+ */
+
+int isUniAlpha(unsigned u)
+{
+    static unsigned short table[][2] =
+    {
+	{ 0x00AA, 0x00AA },
+	{ 0x00B5, 0x00B5 },
+	{ 0x00B7, 0x00B7 },
+	{ 0x00BA, 0x00BA },
+	{ 0x00C0, 0x00D6 },
+	{ 0x00D8, 0x00F6 },
+	{ 0x00F8, 0x01F5 },
+	{ 0x01FA, 0x0217 },
+	{ 0x0250, 0x02A8 },
+	{ 0x02B0, 0x02B8 },
+	{ 0x02BB, 0x02BB },
+	{ 0x02BD, 0x02C1 },
+	{ 0x02D0, 0x02D1 },
+	{ 0x02E0, 0x02E4 },
+	{ 0x037A, 0x037A },
+	{ 0x0386, 0x0386 },
+	{ 0x0388, 0x038A },
+	{ 0x038C, 0x038C },
+	{ 0x038E, 0x03A1 },
+	{ 0x03A3, 0x03CE },
+	{ 0x03D0, 0x03D6 },
+	{ 0x03DA, 0x03DA },
+	{ 0x03DC, 0x03DC },
+	{ 0x03DE, 0x03DE },
+	{ 0x03E0, 0x03E0 },
+	{ 0x03E2, 0x03F3 },
+	{ 0x0401, 0x040C },
+	{ 0x040E, 0x044F },
+	{ 0x0451, 0x045C },
+	{ 0x045E, 0x0481 },
+	{ 0x0490, 0x04C4 },
+	{ 0x04C7, 0x04C8 },
+	{ 0x04CB, 0x04CC },
+	{ 0x04D0, 0x04EB },
+	{ 0x04EE, 0x04F5 },
+	{ 0x04F8, 0x04F9 },
+	{ 0x0531, 0x0556 },
+	{ 0x0559, 0x0559 },
+	{ 0x0561, 0x0587 },
+	{ 0x05B0, 0x05B9 },
+	{ 0x05BB, 0x05BD },
+	{ 0x05BF, 0x05BF },
+	{ 0x05C1, 0x05C2 },
+	{ 0x05D0, 0x05EA },
+	{ 0x05F0, 0x05F2 },
+	{ 0x0621, 0x063A },
+	{ 0x0640, 0x0652 },
+	{ 0x0660, 0x0669 },
+	{ 0x0670, 0x06B7 },
+	{ 0x06BA, 0x06BE },
+	{ 0x06C0, 0x06CE },
+	{ 0x06D0, 0x06DC },
+	{ 0x06E5, 0x06E8 },
+	{ 0x06EA, 0x06ED },
+	{ 0x06F0, 0x06F9 },
+	{ 0x0901, 0x0903 },
+	{ 0x0905, 0x0939 },
+	{ 0x093D, 0x093D },
+	{ 0x093E, 0x094D },
+	{ 0x0950, 0x0952 },
+	{ 0x0958, 0x0963 },
+	{ 0x0966, 0x096F },
+	{ 0x0981, 0x0983 },
+	{ 0x0985, 0x098C },
+	{ 0x098F, 0x0990 },
+	{ 0x0993, 0x09A8 },
+	{ 0x09AA, 0x09B0 },
+	{ 0x09B2, 0x09B2 },
+	{ 0x09B6, 0x09B9 },
+	{ 0x09BE, 0x09C4 },
+	{ 0x09C7, 0x09C8 },
+	{ 0x09CB, 0x09CD },
+	{ 0x09DC, 0x09DD },
+	{ 0x09DF, 0x09E3 },
+	{ 0x09E6, 0x09EF },
+	{ 0x09F0, 0x09F1 },
+	{ 0x0A02, 0x0A02 },
+	{ 0x0A05, 0x0A0A },
+	{ 0x0A0F, 0x0A10 },
+	{ 0x0A13, 0x0A28 },
+	{ 0x0A2A, 0x0A30 },
+	{ 0x0A32, 0x0A33 },
+	{ 0x0A35, 0x0A36 },
+	{ 0x0A38, 0x0A39 },
+	{ 0x0A3E, 0x0A42 },
+	{ 0x0A47, 0x0A48 },
+	{ 0x0A4B, 0x0A4D },
+	{ 0x0A59, 0x0A5C },
+	{ 0x0A5E, 0x0A5E },
+	{ 0x0A66, 0x0A6F },
+	{ 0x0A74, 0x0A74 },
+	{ 0x0A81, 0x0A83 },
+	{ 0x0A85, 0x0A8B },
+	{ 0x0A8D, 0x0A8D },
+	{ 0x0A8F, 0x0A91 },
+	{ 0x0A93, 0x0AA8 },
+	{ 0x0AAA, 0x0AB0 },
+	{ 0x0AB2, 0x0AB3 },
+	{ 0x0AB5, 0x0AB9 },
+	{ 0x0ABD, 0x0AC5 },
+	{ 0x0AC7, 0x0AC9 },
+	{ 0x0ACB, 0x0ACD },
+	{ 0x0AD0, 0x0AD0 },
+	{ 0x0AE0, 0x0AE0 },
+	{ 0x0AE6, 0x0AEF },
+	{ 0x0B01, 0x0B03 },
+	{ 0x0B05, 0x0B0C },
+	{ 0x0B0F, 0x0B10 },
+	{ 0x0B13, 0x0B28 },
+	{ 0x0B2A, 0x0B30 },
+	{ 0x0B32, 0x0B33 },
+	{ 0x0B36, 0x0B39 },
+	{ 0x0B3D, 0x0B3D },
+	{ 0x0B3E, 0x0B43 },
+	{ 0x0B47, 0x0B48 },
+	{ 0x0B4B, 0x0B4D },
+	{ 0x0B5C, 0x0B5D },
+	{ 0x0B5F, 0x0B61 },
+	{ 0x0B66, 0x0B6F },
+	{ 0x0B82, 0x0B83 },
+	{ 0x0B85, 0x0B8A },
+	{ 0x0B8E, 0x0B90 },
+	{ 0x0B92, 0x0B95 },
+	{ 0x0B99, 0x0B9A },
+	{ 0x0B9C, 0x0B9C },
+	{ 0x0B9E, 0x0B9F },
+	{ 0x0BA3, 0x0BA4 },
+	{ 0x0BA8, 0x0BAA },
+	{ 0x0BAE, 0x0BB5 },
+	{ 0x0BB7, 0x0BB9 },
+	{ 0x0BBE, 0x0BC2 },
+	{ 0x0BC6, 0x0BC8 },
+	{ 0x0BCA, 0x0BCD },
+	{ 0x0BE7, 0x0BEF },
+	{ 0x0C01, 0x0C03 },
+	{ 0x0C05, 0x0C0C },
+	{ 0x0C0E, 0x0C10 },
+	{ 0x0C12, 0x0C28 },
+	{ 0x0C2A, 0x0C33 },
+	{ 0x0C35, 0x0C39 },
+	{ 0x0C3E, 0x0C44 },
+	{ 0x0C46, 0x0C48 },
+	{ 0x0C4A, 0x0C4D },
+	{ 0x0C60, 0x0C61 },
+	{ 0x0C66, 0x0C6F },
+	{ 0x0C82, 0x0C83 },
+	{ 0x0C85, 0x0C8C },
+	{ 0x0C8E, 0x0C90 },
+	{ 0x0C92, 0x0CA8 },
+	{ 0x0CAA, 0x0CB3 },
+	{ 0x0CB5, 0x0CB9 },
+	{ 0x0CBE, 0x0CC4 },
+	{ 0x0CC6, 0x0CC8 },
+	{ 0x0CCA, 0x0CCD },
+	{ 0x0CDE, 0x0CDE },
+	{ 0x0CE0, 0x0CE1 },
+	{ 0x0CE6, 0x0CEF },
+	{ 0x0D02, 0x0D03 },
+	{ 0x0D05, 0x0D0C },
+	{ 0x0D0E, 0x0D10 },
+	{ 0x0D12, 0x0D28 },
+	{ 0x0D2A, 0x0D39 },
+	{ 0x0D3E, 0x0D43 },
+	{ 0x0D46, 0x0D48 },
+	{ 0x0D4A, 0x0D4D },
+	{ 0x0D60, 0x0D61 },
+	{ 0x0D66, 0x0D6F },
+	{ 0x0E01, 0x0E3A },
+	{ 0x0E40, 0x0E5B },
+//	{ 0x0E50, 0x0E59 },
+	{ 0x0E81, 0x0E82 },
+	{ 0x0E84, 0x0E84 },
+	{ 0x0E87, 0x0E88 },
+	{ 0x0E8A, 0x0E8A },
+	{ 0x0E8D, 0x0E8D },
+	{ 0x0E94, 0x0E97 },
+	{ 0x0E99, 0x0E9F },
+	{ 0x0EA1, 0x0EA3 },
+	{ 0x0EA5, 0x0EA5 },
+	{ 0x0EA7, 0x0EA7 },
+	{ 0x0EAA, 0x0EAB },
+	{ 0x0EAD, 0x0EAE },
+	{ 0x0EB0, 0x0EB9 },
+	{ 0x0EBB, 0x0EBD },
+	{ 0x0EC0, 0x0EC4 },
+	{ 0x0EC6, 0x0EC6 },
+	{ 0x0EC8, 0x0ECD },
+	{ 0x0ED0, 0x0ED9 },
+	{ 0x0EDC, 0x0EDD },
+	{ 0x0F00, 0x0F00 },
+	{ 0x0F18, 0x0F19 },
+	{ 0x0F20, 0x0F33 },
+	{ 0x0F35, 0x0F35 },
+	{ 0x0F37, 0x0F37 },
+	{ 0x0F39, 0x0F39 },
+	{ 0x0F3E, 0x0F47 },
+	{ 0x0F49, 0x0F69 },
+	{ 0x0F71, 0x0F84 },
+	{ 0x0F86, 0x0F8B },
+	{ 0x0F90, 0x0F95 },
+	{ 0x0F97, 0x0F97 },
+	{ 0x0F99, 0x0FAD },
+	{ 0x0FB1, 0x0FB7 },
+	{ 0x0FB9, 0x0FB9 },
+	{ 0x10A0, 0x10C5 },
+	{ 0x10D0, 0x10F6 },
+	{ 0x1E00, 0x1E9B },
+	{ 0x1EA0, 0x1EF9 },
+	{ 0x1F00, 0x1F15 },
+	{ 0x1F18, 0x1F1D },
+	{ 0x1F20, 0x1F45 },
+	{ 0x1F48, 0x1F4D },
+	{ 0x1F50, 0x1F57 },
+	{ 0x1F59, 0x1F59 },
+	{ 0x1F5B, 0x1F5B },
+	{ 0x1F5D, 0x1F5D },
+	{ 0x1F5F, 0x1F7D },
+	{ 0x1F80, 0x1FB4 },
+	{ 0x1FB6, 0x1FBC },
+	{ 0x1FBE, 0x1FBE },
+	{ 0x1FC2, 0x1FC4 },
+	{ 0x1FC6, 0x1FCC },
+	{ 0x1FD0, 0x1FD3 },
+	{ 0x1FD6, 0x1FDB },
+	{ 0x1FE0, 0x1FEC },
+	{ 0x1FF2, 0x1FF4 },
+	{ 0x1FF6, 0x1FFC },
+	{ 0x203F, 0x2040 },
+	{ 0x207F, 0x207F },
+	{ 0x2102, 0x2102 },
+	{ 0x2107, 0x2107 },
+	{ 0x210A, 0x2113 },
+	{ 0x2115, 0x2115 },
+	{ 0x2118, 0x211D },
+	{ 0x2124, 0x2124 },
+	{ 0x2126, 0x2126 },
+	{ 0x2128, 0x2128 },
+	{ 0x212A, 0x2131 },
+	{ 0x2133, 0x2138 },
+	{ 0x2160, 0x2182 },
+	{ 0x3005, 0x3007 },
+	{ 0x3021, 0x3029 },
+	{ 0x3041, 0x3093 },
+	{ 0x309B, 0x309C },
+	{ 0x30A1, 0x30F6 },
+	{ 0x30FB, 0x30FC },
+	{ 0x3105, 0x312C },
+	{ 0x4E00, 0x9FA5 },
+	{ 0xAC00, 0xD7A3 },
+    };
+
+#ifdef DEBUG
+    for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++)
+    {
+	//printf("%x\n", table[i][0]);
+	assert(table[i][0] <= table[i][1]);
+	if (i < sizeof(table) / sizeof(table[0]) - 1)
+	    assert(table[i][1] < table[i + 1][0]);
+    }
+#endif
+
+    if (u > 0xD7A3)
+	goto Lisnot;
+
+    // Binary search
+    int mid;
+    int low;
+    int high;
+
+    low = 0;
+    high = sizeof(table) / sizeof(table[0]) - 1;
+    while (low <= high)
+    {
+	mid = (low + high) >> 1;
+	if (u < table[mid][0])
+	    high = mid - 1;
+	else if (u > table[mid][1])
+	    low = mid + 1;
+	else
+	    goto Lis;
+    }
+
+Lisnot:
+#ifdef DEBUG
+    for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++)
+    {
+	assert(u < table[i][0] || u > table[i][1]);
+    }
+#endif
+    return 0;
+
+Lis:
+#ifdef DEBUG
+    for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++)
+    {
+	if (u >= table[i][0] && u <= table[i][1])
+	    return 1;
+    }
+    assert(0);		// should have been in table
+#endif
+    return 1;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/utf.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,193 @@
+// utf.c
+// Copyright (c) 2003 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+// Description of UTF-8 at:
+// http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "utf.h"
+
+int utf_isValidDchar(dchar_t c)
+{
+    return c < 0xD800 ||
+	(c > 0xDFFF && c <= 0x10FFFF && c != 0xFFFE && c != 0xFFFF);
+}
+
+/********************************************
+ * Decode a single UTF-8 character sequence.
+ * Returns:
+ *	NULL	success
+ *	!=NULL	error message string
+ */
+
+char *utf_decodeChar(unsigned char *s, size_t len, size_t *pidx, dchar_t *presult)
+{
+    dchar_t V;
+    size_t i = *pidx;
+    unsigned char u = s[i];
+
+    assert(i >= 0 && i < len);
+
+    if (u & 0x80)
+    {   unsigned n;
+	unsigned char u2;
+
+	/* The following encodings are valid, except for the 5 and 6 byte
+	 * combinations:
+	 *	0xxxxxxx
+	 *	110xxxxx 10xxxxxx
+	 *	1110xxxx 10xxxxxx 10xxxxxx
+	 *	11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+	 *	111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+	 *	1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+	 */
+	for (n = 1; ; n++)
+	{
+	    if (n > 4)
+		goto Lerr;		// only do the first 4 of 6 encodings
+	    if (((u << n) & 0x80) == 0)
+	    {
+		if (n == 1)
+		    goto Lerr;
+		break;
+	    }
+	}
+
+	// Pick off (7 - n) significant bits of B from first byte of octet
+	V = (dchar_t)(u & ((1 << (7 - n)) - 1));
+
+	if (i + (n - 1) >= len)
+	    goto Lerr;			// off end of string
+
+	/* The following combinations are overlong, and illegal:
+	 *	1100000x (10xxxxxx)
+	 *	11100000 100xxxxx (10xxxxxx)
+	 *	11110000 1000xxxx (10xxxxxx 10xxxxxx)
+	 *	11111000 10000xxx (10xxxxxx 10xxxxxx 10xxxxxx)
+	 *	11111100 100000xx (10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx)
+	 */
+	u2 = s[i + 1];
+	if ((u & 0xFE) == 0xC0 ||
+	    (u == 0xE0 && (u2 & 0xE0) == 0x80) ||
+	    (u == 0xF0 && (u2 & 0xF0) == 0x80) ||
+	    (u == 0xF8 && (u2 & 0xF8) == 0x80) ||
+	    (u == 0xFC && (u2 & 0xFC) == 0x80))
+	    goto Lerr;			// overlong combination
+
+	for (unsigned j = 1; j != n; j++)
+	{
+	    u = s[i + j];
+	    if ((u & 0xC0) != 0x80)
+		goto Lerr;			// trailing bytes are 10xxxxxx
+	    V = (V << 6) | (u & 0x3F);
+	}
+	if (!utf_isValidDchar(V))
+	    goto Lerr;
+	i += n;
+    }
+    else
+    {
+	V = (dchar_t) u;
+	i++;
+    }
+
+    assert(utf_isValidDchar(V));
+    *pidx = i;
+    *presult = V;
+    return NULL;
+
+  Lerr:
+    *presult = (dchar_t) s[i];
+    *pidx = i + 1;
+    return "invalid UTF-8 sequence";
+}
+
+/***************************************************
+ * Validate a UTF-8 string.
+ * Returns:
+ *	NULL	success
+ *	!=NULL	error message string
+ */
+
+char *utf_validateString(unsigned char *s, size_t len)
+{
+    size_t idx;
+    char *err = NULL;
+    dchar_t dc;
+
+    for (idx = 0; idx < len; )
+    {
+	err = utf_decodeChar(s, len, &idx, &dc);
+	if (err)
+	    break;
+    }
+    return err;
+}
+
+
+/********************************************
+ * Decode a single UTF-16 character sequence.
+ * Returns:
+ *	NULL	success
+ *	!=NULL	error message string
+ */
+
+
+char *utf_decodeWchar(unsigned short *s, size_t len, size_t *pidx, dchar_t *presult)
+{
+    char *msg;
+    size_t i = *pidx;
+    unsigned u = s[i];
+
+    assert(i >= 0 && i < len);
+    if (u & ~0x7F)
+    {   if (u >= 0xD800 && u <= 0xDBFF)
+	{   unsigned u2;
+
+	    if (i + 1 == len)
+	    {   msg = "surrogate UTF-16 high value past end of string";
+		goto Lerr;
+	    }
+	    u2 = s[i + 1];
+	    if (u2 < 0xDC00 || u2 > 0xDFFF)
+	    {   msg = "surrogate UTF-16 low value out of range";
+		goto Lerr;
+	    }
+	    u = ((u - 0xD7C0) << 10) + (u2 - 0xDC00);
+	    i += 2;
+	}
+	else if (u >= 0xDC00 && u <= 0xDFFF)
+	{   msg = "unpaired surrogate UTF-16 value";
+	    goto Lerr;
+	}
+	else if (u == 0xFFFE || u == 0xFFFF)
+	{   msg = "illegal UTF-16 value";
+	    goto Lerr;
+	}
+	else
+	    i++;
+    }
+    else
+    {
+	i++;
+    }
+
+    assert(utf_isValidDchar(u));
+    *pidx = i;
+    *presult = (dchar_t)u;
+    return NULL;
+
+  Lerr:
+    *presult = (dchar_t)s[i];
+    *pidx = i + 1;
+    return msg;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/utf.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,26 @@
+// Compiler implementation of the D programming language
+// utf.h
+// Copyright (c) 2003-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#ifndef DMD_UTF_H
+#define DMD_UTF_H
+
+
+typedef unsigned dchar_t;
+
+int utf_isValidDchar(dchar_t c);
+
+char *utf_decodeChar(unsigned char *s, size_t len, size_t *pidx, dchar_t *presult);
+char *utf_decodeWchar(unsigned short *s, size_t len, size_t *pidx, dchar_t *presult);
+
+char *utf_validateString(unsigned char *s, size_t len);
+
+extern int isUniAlpha(dchar_t);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/version.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,181 @@
+
+// Copyright (c) 1999-2005 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "root.h"
+
+#include "identifier.h"
+#include "dsymbol.h"
+#include "cond.h"
+#include "version.h"
+#include "module.h"
+
+/* ================================================== */
+
+/* DebugSymbol's happen for statements like:
+ *	debug = identifier;
+ *	debug = integer;
+ */
+
+DebugSymbol::DebugSymbol(Loc loc, Identifier *ident)
+    : Dsymbol(ident)
+{
+    this->loc = loc;
+}
+
+DebugSymbol::DebugSymbol(Loc loc, unsigned level)
+    : Dsymbol()
+{
+    this->level = level;
+    this->loc = loc;
+}
+
+Dsymbol *DebugSymbol::syntaxCopy(Dsymbol *s)
+{
+    assert(!s);
+    DebugSymbol *ds = new DebugSymbol(loc, ident);
+    ds->level = level;
+    return ds;
+}
+
+int DebugSymbol::addMember(Scope *sc, ScopeDsymbol *sd, int memnum)
+{
+    //printf("DebugSymbol::addMember('%s') %s\n", sd->toChars(), toChars());
+    Module *m;
+
+    // Do not add the member to the symbol table,
+    // just make sure subsequent debug declarations work.
+    m = sd->isModule();
+    if (ident)
+    {
+	if (!m)
+	    error("declaration must be at module level");
+	else
+	{
+	    if (findCondition(m->debugidsNot, ident))
+		error("defined after use");
+	    if (!m->debugids)
+		m->debugids = new Array();
+	    m->debugids->push(ident->toChars());
+	}
+    }
+    else
+    {
+	if (!m)
+	    error("level declaration must be at module level");
+	else
+	    m->debuglevel = level;
+    }
+    return 0;
+}
+
+void DebugSymbol::semantic(Scope *sc)
+{
+    //printf("DebugSymbol::semantic() %s\n", toChars());
+}
+
+void DebugSymbol::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("debug = ");
+    if (ident)
+	buf->writestring(ident->toChars());
+    else
+	buf->printf("%u", level);
+    buf->writestring(";");
+    buf->writenl();
+}
+
+char *DebugSymbol::kind()
+{
+    return "debug";
+}
+
+/* ================================================== */
+
+/* VersionSymbol's happen for statements like:
+ *	version = identifier;
+ *	version = integer;
+ */
+
+VersionSymbol::VersionSymbol(Loc loc, Identifier *ident)
+    : Dsymbol(ident)
+{
+    this->loc = loc;
+}
+
+VersionSymbol::VersionSymbol(Loc loc, unsigned level)
+    : Dsymbol()
+{
+    this->level = level;
+    this->loc = loc;
+}
+
+Dsymbol *VersionSymbol::syntaxCopy(Dsymbol *s)
+{
+    assert(!s);
+    VersionSymbol *ds = new VersionSymbol(loc, ident);
+    ds->level = level;
+    return ds;
+}
+
+int VersionSymbol::addMember(Scope *sc, ScopeDsymbol *sd, int memnum)
+{
+    //printf("VersionSymbol::addMember('%s') %s\n", sd->toChars(), toChars());
+    Module *m;
+
+    // Do not add the member to the symbol table,
+    // just make sure subsequent debug declarations work.
+    m = sd->isModule();
+    if (ident)
+    {
+	VersionCondition::checkPredefined(loc, ident->toChars());
+	if (!m)
+	    error("declaration must be at module level");
+	else
+	{
+	    if (findCondition(m->versionidsNot, ident))
+		error("defined after use");
+	    if (!m->versionids)
+		m->versionids = new Array();
+	    m->versionids->push(ident->toChars());
+	}
+    }
+    else
+    {
+	if (!m)
+	    error("level declaration must be at module level");
+	else
+	    m->versionlevel = level;
+    }
+    return 0;
+}
+
+void VersionSymbol::semantic(Scope *sc)
+{
+}
+
+void VersionSymbol::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("version = ");
+    if (ident)
+	buf->writestring(ident->toChars());
+    else
+	buf->printf("%u", level);
+    buf->writestring(";");
+    buf->writenl();
+}
+
+char *VersionSymbol::kind()
+{
+    return "version";
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/version.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,51 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#ifndef DMD_VERSION_H
+#define DMD_VERSION_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include "dsymbol.h"
+
+struct OutBuffer;
+struct HdrGenState;
+
+struct DebugSymbol : Dsymbol
+{
+    unsigned level;
+
+    DebugSymbol(Loc loc, Identifier *ident);
+    DebugSymbol(Loc loc, unsigned level);
+    Dsymbol *syntaxCopy(Dsymbol *);
+
+    int addMember(Scope *sc, ScopeDsymbol *s, int memnum);
+    void semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    char *kind();
+};
+
+struct VersionSymbol : Dsymbol
+{
+    unsigned level;
+
+    VersionSymbol(Loc loc, Identifier *ident);
+    VersionSymbol(Loc loc, unsigned level);
+    Dsymbol *syntaxCopy(Dsymbol *);
+
+    int addMember(Scope *sc, ScopeDsymbol *s, int memnum);
+    void semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    char *kind();
+};
+
+#endif /* DMD_VERSION_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen/elem.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,65 @@
+#include <iostream>
+
+#include "llvm/Instructions.h"
+
+#include "elem.h"
+
+#include "irstate.h"
+#include "logger.h"
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem::elem()
+{
+    mem = 0;
+    val = 0;
+    arg = 0;
+
+    type = NONE;
+    inplace = false;
+    field = false;
+
+    vardecl = 0;
+    funcdecl = 0;
+}
+
+llvm::Value* elem::getValue()
+{
+    assert(val || mem);
+    switch(type)
+    {
+    case NONE:
+        assert(0 && "type == NONE");
+        break;
+
+    case VAR:
+    case REF: {
+        if (val) {
+            return val;
+        }
+        else {
+            if (!llvm::isa<llvm::PointerType>(mem->getType()))
+            {
+                Logger::cout() << "unexpected type: " << *mem->getType() << '\n';
+                assert(0);
+            }
+            const llvm::PointerType* pt = llvm::cast<llvm::PointerType>(mem->getType());
+            if (!pt->getElementType()->isFirstClassType()) {
+                return mem;
+            }
+            else {
+                return new llvm::LoadInst(mem, "tmp", gIR->scopebb());
+            }
+        }
+    }
+
+    case VAL:
+    case NUL:
+    case FUNC:
+    case CONST:
+    case SLICE:
+        return val ? val : mem;
+    }
+    assert(0 && "type == invalid value");
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen/elem.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,44 @@
+#ifndef LLVMDC_GEN_ELEM_H
+#define LLVMDC_GEN_ELEM_H
+
+#include "llvm/Value.h"
+
+#include "root.h"
+#include "declaration.h"
+#include "aggregate.h"
+
+// represents a value. be it a constant literal, a variable etc.
+// maintains all the information for doing load/store appropriately
+struct elem : Object
+{
+    enum {
+        NONE,
+        VAR,
+        VAL,
+        FUNC,
+        CONST,
+        NUL,
+        REF,
+        SLICE
+    };
+
+public:
+    elem();
+
+    llvm::Value* mem;
+    llvm::Value* val;
+    llvm::Value* arg;
+    int type;
+    bool inplace;
+    bool field;
+
+    VarDeclaration* vardecl;
+    FuncDeclaration* funcdecl;
+
+    llvm::Value* getValue();
+    //llvm::Value* getMemory();
+
+    bool isNull()   {return !(mem || val);}
+};
+
+#endif // LLVMDC_GEN_ELEM_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen/enums.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,8 @@
+enum
+{
+    LLVMnone,
+    LLVMnull,
+    LLVMmangle,
+    LLVMintrinsic,
+    LLVMbind,
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen/irstate.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,111 @@
+/* DMDFE backend stubs
+ * This file contains the implementations of the backend routines.
+ * For dmdfe these do nothing but print a message saying the module
+ * has been parsed. Substitute your own behaviors for these routimes.
+ */
+
+#include "irstate.h"
+
+#include "mtype.h"
+
+IRState* gIR = 0;
+llvm::TargetData* gTargetData = 0;
+
+//////////////////////////////////////////////////////////////////////////////////////////
+IRScope::IRScope()
+{
+    begin = end = 0;
+    returned = false;
+}
+
+IRScope::IRScope(llvm::BasicBlock* b, llvm::BasicBlock* e)
+{
+    begin = b;
+    end = e;
+    returned = false;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+IRState::IRState()
+{
+    dmodule = 0;
+    module = 0;
+    inLvalue = false;
+    emitMain = false;
+    mainFunc = 0;
+}
+
+llvm::Function* IRState::topfunc()
+{
+    assert(!funcs.empty() && "Function stack is empty!");
+    return funcs.top();
+}
+
+TypeFunction* IRState::topfunctype()
+{
+    assert(!functypes.empty() && "TypeFunction stack is empty!");
+    return functypes.top();
+}
+
+llvm::Instruction* IRState::topallocapoint()
+{
+    assert(!functypes.empty() && "AllocaPoint stack is empty!");
+    return functypes.top()->llvmAllocaPoint;
+}
+
+IRStruct& IRState::topstruct()
+{
+    assert(!structs.empty() && "Struct vector is empty!");
+    return structs.back();
+}
+
+llvm::Value* IRState::toplval()
+{
+    assert(!lvals.empty() && "Lval vector is empty!");
+    return lvals.back();
+}
+
+IRScope& IRState::scope()
+{
+    assert(!scopes.empty());
+    return scopes.back();
+}
+
+llvm::BasicBlock* IRState::scopebb()
+{
+    return scopebegin();
+}
+llvm::BasicBlock* IRState::scopebegin()
+{
+    IRScope& s = scope();
+    assert(s.begin);
+    return s.begin;
+}
+llvm::BasicBlock* IRState::scopeend()
+{
+    IRScope& s = scope();
+    assert(s.end);
+    return s.end;
+}
+bool IRState::scopereturned()
+{
+    return scope().returned;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+IRStruct::IRStruct()
+ : recty(llvm::OpaqueType::get())
+{
+    type = 0;
+}
+
+IRStruct::IRStruct(TypeStruct* t)
+ : recty(llvm::OpaqueType::get())
+{
+    type = t;
+}
+
+IRStruct::~IRStruct()
+{
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen/irstate.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,122 @@
+#ifndef LLVMDC_GEN_IRSTATE_H
+#define LLVMDC_GEN_IRSTATE_H
+
+#include <stack>
+#include <vector>
+#include <deque>
+
+#include "llvm/DerivedTypes.h"
+#include "llvm/Module.h"
+#include "llvm/Function.h"
+#include "llvm/BasicBlock.h"
+#include "llvm/Target/TargetData.h"
+
+#include "root.h"
+
+// global ir state for current module
+struct IRState;
+extern IRState* gIR;
+extern llvm::TargetData* gTargetData;
+
+struct TypeFunction;
+struct TypeStruct;
+struct ClassDeclaration;
+struct FuncDeclaration;
+struct Module;
+struct TypeStruct;
+
+// represents a scope
+struct IRScope
+{
+    llvm::BasicBlock* begin;
+    llvm::BasicBlock* end;
+    bool returned;
+
+    IRScope();
+    IRScope(llvm::BasicBlock* b, llvm::BasicBlock* e);
+};
+
+// represents a struct
+struct IRStruct : Object
+{
+    typedef std::vector<const llvm::Type*> TypeVector;
+    typedef std::vector<llvm::Constant*> ConstantVector;
+    typedef std::vector<llvm::PATypeHolder> PATypeHolderVector;
+
+public:
+    IRStruct();
+    IRStruct(TypeStruct*);
+    virtual ~IRStruct();
+
+    TypeStruct* type;
+    TypeVector fields;
+    ConstantVector inits;
+    llvm::PATypeHolder recty;
+};
+
+// represents a clas
+struct IRClass : Object
+{
+    // TODO
+};
+
+// represents the module
+struct IRState : Object
+{
+    IRState();
+
+    // module
+    Module* dmodule;
+    llvm::Module* module;
+
+    // functions
+    std::stack<llvm::Function*> funcs;
+    llvm::Function* topfunc();
+    std::stack<TypeFunction*> functypes;
+    TypeFunction* topfunctype();
+    llvm::Instruction* topallocapoint();
+
+    // structs
+    typedef std::vector<IRStruct> StructVector;
+    StructVector structs;
+    IRStruct& topstruct();
+
+    // classes TODO move into IRClass
+    typedef std::vector<ClassDeclaration*> ClassDeclVec;
+    ClassDeclVec classes;
+    typedef std::vector<FuncDeclaration*> FuncDeclVec;
+    typedef std::vector<FuncDeclVec> ClassMethodVec;
+    ClassMethodVec classmethods;
+    typedef std::vector<bool> BoolVec;
+    BoolVec queueClassMethods;
+
+    // D main function
+    bool emitMain;
+    llvm::Function* mainFunc;
+
+    // L-values
+    bool inLvalue;
+    typedef std::vector<llvm::Value*> LvalVec;
+    LvalVec lvals;
+    llvm::Value* toplval();
+
+    // basic block scopes
+    std::vector<IRScope> scopes;
+    IRScope& scope();
+    llvm::BasicBlock* scopebegin();
+    llvm::BasicBlock* scopeend();
+    llvm::BasicBlock* scopebb();
+    bool scopereturned();
+
+    // loop blocks
+    typedef std::vector<IRScope> BBVec;
+    BBVec loopbbs;
+
+    // this holds the array being indexed or sliced so $ will work
+    // might be a better way but it works. problem is I only get a
+    // VarDeclaration for __dollar, but I can't see how to get the
+    // array pointer from this :(
+    LvalVec arrays;
+};
+
+#endif // LLVMDC_GEN_IRSTATE_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen/logger.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,47 @@
+#ifndef LLVMD_NO_LOGGER
+
+#include <cassert>
+#include <cstdarg>
+#include <cstdio>
+#include <cstdlib>
+#include <iostream>
+#include <string>
+
+#include "logger.h"
+
+namespace Logger
+{
+    static std::string indent_str;
+    void indent()
+    {
+        indent_str += "  ";
+    }
+    void undent()
+    {
+        assert(!indent_str.empty());
+        indent_str.resize(indent_str.size()-2);
+    }
+    std::ostream& cout()
+    {
+        return std::cout << indent_str;
+    }
+    void println(const char* fmt,...)
+    {
+        printf(indent_str.c_str());
+        va_list va;
+        va_start(va,fmt);
+        vprintf(fmt,va);
+        va_end(va);
+        printf("\n");
+    }
+    void print(const char* fmt,...)
+    {
+        printf(indent_str.c_str());
+        va_list va;
+        va_start(va,fmt);
+        vprintf(fmt,va);
+        va_end(va);
+    }
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen/logger.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,48 @@
+#ifndef _llvmd_gen_logger_h_
+#define _llvmd_gen_logger_h_
+
+#include <iostream>
+
+namespace Logger
+{
+    #ifndef LLVMD_NO_LOGGER
+    void indent();
+    void undent();
+    std::ostream& cout();
+    void println(const char* fmt,...);
+    void print(const char* fmt,...);
+    #else
+    inline void indent() {}
+    inline void undent() {}
+    inline std::ostream& cout() { return std::cout; }
+    inline void println(const char* fmt, ...) {}
+    inline void print(const char* fmt, ...) {}
+    #endif
+
+    struct LoggerScope
+    {
+        LoggerScope()
+        {
+            #ifndef LLVMD_NO_LOGGER
+            //std::cout << "-->indented\n";
+            Logger::indent();
+            #endif
+            
+        }
+        ~LoggerScope()
+        {
+            #ifndef LLVMD_NO_LOGGER
+            //std::cout << "<--undented\n";
+            Logger::undent();
+            #endif
+        }
+    };
+}
+
+#ifndef LLVMD_NO_LOGGER
+#define LOG_SCOPE    Logger::LoggerScope _logscope;
+#else
+#define LOG_SCOPE
+#endif
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen/runtime.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,74 @@
+#include <cassert>
+
+#include "llvm/Module.h"
+#include "llvm/Bitcode/ReaderWriter.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+#include "runtime.h"
+#include "logger.h"
+
+#include "root.h"
+#include "mars.h"
+
+static llvm::Module* M = NULL;
+static bool runtime_failed = false;
+
+bool LLVM_D_InitRuntime()
+{
+    Logger::println("*** Loading D runtime ***");
+    LOG_SCOPE;
+
+    std::string filename(global.params.runtimeImppath);
+    filename.append("/llvmdcore.bc");
+    llvm::MemoryBuffer* buffer = llvm::MemoryBuffer::getFile(filename.c_str(), filename.length());
+    if (!buffer) {
+        Logger::println("Failed to load runtime library from disk");
+        runtime_failed = true;
+        return false;
+    }
+
+    std::string errstr;
+    bool retval = false;
+    M = llvm::ParseBitcodeFile(buffer, &errstr);
+    if (M) {
+        retval = true;
+    }
+    else {
+        Logger::println("Failed to load runtime: %s", errstr.c_str());
+        runtime_failed = true;
+    }
+    
+    delete buffer;
+    return retval;
+}
+
+void LLVM_D_FreeRuntime()
+{
+    if (M) {
+        Logger::println("*** Freeing D runtime ***");
+        delete M;
+    }
+}
+
+llvm::Function* LLVM_D_GetRuntimeFunction(llvm::Module* target, const char* name)
+{
+    // TODO maybe check the target module first, to allow overriding the runtime on a pre module basis?
+    // could be done and seems like it could be neat too :)
+
+    if (global.params.noruntime) {
+        error("No implicit runtime calls allowed with -noruntime option enabled");
+        fatal();
+    }
+    
+    if (!M) {
+        assert(!runtime_failed);
+        LLVM_D_InitRuntime();
+    }
+    
+    llvm::Function* fn = M->getFunction(name);
+    if (!fn)
+        return NULL;
+    
+    const llvm::FunctionType* fnty = fn->getFunctionType();
+    return llvm::cast<llvm::Function>(target->getOrInsertFunction(name, fnty));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen/runtime.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,6 @@
+// D runtime support helpers
+
+bool LLVM_D_InitRuntime();
+void LLVM_D_FreeRuntime();
+
+llvm::Function* LLVM_D_GetRuntimeFunction(llvm::Module* target, const char* name);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen/tocsym.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,215 @@
+
+// Copyright (c) 1999-2005 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+// stubbed out for dmdfe. Original is in dmd/tocsym.c
+
+#include <stddef.h>
+
+#include "mars.h"
+#include "module.h"
+#include "mtype.h"
+#include "declaration.h"
+#include "statement.h"
+#include "enum.h"
+#include "aggregate.h"
+#include "init.h"
+#include "attrib.h"
+#include "lexer.h"
+#include "symbol.h"
+
+/********************************* SymbolDeclaration ****************************/
+
+SymbolDeclaration::SymbolDeclaration(Loc loc, Symbol *s, StructDeclaration *dsym)
+    : Declaration(new Identifier("", TOKidentifier))
+{
+}
+
+Symbol *SymbolDeclaration::toSymbol()
+{
+    return sym;
+}
+
+/*************************************
+ * Helper
+ */
+
+Symbol *Dsymbol::toSymbolX(const char *prefix, int sclass, TYPE *t, const char *suffix)
+{
+  return 0;
+}
+
+/*************************************
+ */
+
+Symbol *Dsymbol::toSymbol()
+{
+  return 0;
+}
+
+/*********************************
+ * Generate import symbol from symbol.
+ */
+
+Symbol *Dsymbol::toImport()
+{
+  return 0;
+}
+
+/*************************************
+ */
+
+Symbol *Dsymbol::toImport(Symbol *sym)
+{
+  return 0;
+}
+
+/*************************************
+ */
+
+Symbol *VarDeclaration::toSymbol()
+{
+  return 0;
+}
+
+/*************************************
+ */
+
+Symbol *ClassInfoDeclaration::toSymbol()
+{
+  return 0;
+}
+
+/*************************************
+ */
+
+Symbol *ModuleInfoDeclaration::toSymbol()
+{
+  return 0;
+}
+
+/*************************************
+ */
+
+Symbol *TypeInfoDeclaration::toSymbol()
+{
+  return 0;
+}
+
+/*************************************
+ */
+
+Symbol *FuncDeclaration::toSymbol()
+{
+
+    return 0;
+}
+
+/*************************************
+ */
+
+Symbol *FuncDeclaration::toThunkSymbol(int offset)
+{
+  return 0;
+}
+
+/*************************************
+ */
+
+Symbol *FuncAliasDeclaration::toSymbol()
+{
+
+    return 0;
+}
+
+
+/****************************************
+ * Create a static symbol we can hang DT initializers onto.
+ */
+
+Symbol *static_sym()
+{
+  return 0;
+}
+
+/*************************************
+ * Create the "ClassInfo" symbol
+ */
+
+Symbol *ClassDeclaration::toSymbol()
+{
+  return 0;
+}
+
+/*************************************
+ * Create the "InterfaceInfo" symbol
+ */
+
+Symbol *InterfaceDeclaration::toSymbol()
+{
+  return 0;
+}
+
+/*************************************
+ * Create the "ModuleInfo" symbol
+ */
+
+Symbol *Module::toSymbol()
+{
+  return 0;
+}
+
+/*************************************
+ * This is accessible via the ClassData, but since it is frequently
+ * needed directly (like for rtti comparisons), make it directly accessible.
+ */
+
+Symbol *ClassDeclaration::toVtblSymbol()
+{
+  return 0;
+}
+
+/**********************************
+ * Create the static initializer for the struct/class.
+ */
+
+Symbol *AggregateDeclaration::toInitializer()
+{
+  return 0;
+}
+
+
+/******************************************
+ */
+
+Symbol *Module::toModuleAssert()
+{
+  return 0;
+}
+
+/******************************************
+ */
+
+Symbol *Module::toModuleArray()
+{
+  return 0;
+}
+
+/********************************************
+ * Determine the right symbol to look up
+ * an associative array element.
+ * Input:
+ *	flags	0	don't add value signature
+ *		1	add value signature
+ */
+
+Symbol *TypeAArray::aaGetSymbol(char *func, int flags)
+{
+  return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen/todt.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,170 @@
+
+// Copyright (c) 1999-2005 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+// stubbed out for dmdfe. Original is in dmd/todt.c
+
+#include	"lexer.h"
+#include	"mtype.h"
+#include	"expression.h"
+#include	"init.h"
+#include	"enum.h"
+#include	"aggregate.h"
+#include	"declaration.h"
+
+struct dt_t {};
+
+dt_t *Initializer::toDt()
+{
+    return 0;
+}
+
+
+dt_t *StructInitializer::toDt()
+{
+    return 0;
+}
+
+
+dt_t *ArrayInitializer::toDt()
+{
+    return 0;
+}
+
+
+dt_t *ArrayInitializer::toDtBit()
+{
+    return 0;
+}
+
+
+dt_t *ExpInitializer::toDt()
+{
+    return 0;
+}
+
+dt_t *VoidInitializer::toDt()
+{
+    return 0;
+}
+
+/* ================================================================ */
+
+dt_t **Expression::toDt(dt_t **pdt)
+{
+    return 0;
+}
+
+dt_t **IntegerExp::toDt(dt_t **pdt)
+{
+    return 0;
+}
+
+dt_t **RealExp::toDt(dt_t **pdt)
+{
+    return 0;
+}
+
+dt_t **ComplexExp::toDt(dt_t **pdt)
+{
+    return 0;
+}
+
+dt_t **NullExp::toDt(dt_t **pdt)
+{
+    return 0;
+}
+
+dt_t **StringExp::toDt(dt_t **pdt)
+{
+    return 0;
+}
+
+dt_t **SymOffExp::toDt(dt_t **pdt)
+{
+    return 0;
+}
+
+dt_t **VarExp::toDt(dt_t **pdt)
+{
+    return 0;
+}
+
+dt_t **ArrayLiteralExp::toDt(dt_t **pdt)
+{
+    return 0;
+}
+dt_t **StructLiteralExp::toDt(dt_t **pdt)
+{
+    return 0;
+}
+
+void ClassDeclaration::toDt(dt_t **pdt)
+{
+}
+
+void ClassDeclaration::toDt2(dt_t **pdt, ClassDeclaration *cd)
+{
+}
+
+void StructDeclaration::toDt(dt_t **pdt)
+{
+}
+
+
+void TypeInfoPointerDeclaration::toDt(dt_t **pdt)
+{
+}
+void TypeInfoArrayDeclaration::toDt(dt_t **pdt)
+{
+}
+void TypeInfoStaticArrayDeclaration::toDt(dt_t **pdt)
+{
+}
+void TypeInfoAssociativeArrayDeclaration::toDt(dt_t **pdt)
+{
+}
+void TypeInfoEnumDeclaration::toDt(dt_t **pdt)
+{
+}
+void TypeInfoFunctionDeclaration::toDt(dt_t **pdt)
+{
+}
+void TypeInfoDelegateDeclaration::toDt(dt_t **pdt)
+{
+}
+void TypeInfoInterfaceDeclaration::toDt(dt_t **pdt)
+{
+}
+void TypeInfoTupleDeclaration::toDt(dt_t **pdt)
+{
+}
+
+
+dt_t **Type::toDt(dt_t **pdt)
+{
+    return 0;
+}
+
+dt_t **TypeSArray::toDt(dt_t **pdt)
+{
+    return 0;
+}
+
+dt_t **TypeStruct::toDt(dt_t **pdt)
+{
+    return 0;
+}
+
+dt_t **TypeTypedef::toDt(dt_t **pdt)
+{
+    return 0;
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen/toir.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,2910 @@
+// Backend stubs
+
+/* DMDFE backend stubs
+ * This file contains the implementations of the backend routines.
+ * For dmdfe these do nothing but print a message saying the module
+ * has been parsed. Substitute your own behaviors for these routimes.
+ */
+
+#include <stdio.h>
+#include <math.h>
+#include <sstream>
+#include <fstream>
+#include <iostream>
+
+#include "llvm/Type.h"
+#include "llvm/DerivedTypes.h"
+#include "llvm/Constants.h"
+#include "llvm/Instructions.h"
+#include "llvm/IntrinsicInst.h"
+#include "llvm/CallingConv.h"
+
+#include "total.h"
+#include "init.h"
+#include "symbol.h"
+#include "mtype.h"
+#include "hdrgen.h"
+#include "irstate.h"
+#include "elem.h"
+#include "port.h"
+#include "logger.h"
+
+#include "tollvm.h"
+#include "runtime.h"
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem* DeclarationExp::toElem(IRState* p)
+{
+    Logger::print("DeclarationExp::toElem: %s | T=%s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+    elem* e = new elem;
+
+    // variable declaration
+    if (VarDeclaration* vd = declaration->isVarDeclaration())
+    {
+        Logger::println("VarDeclaration");
+
+        // handle const
+        // TODO probably not correct
+        bool isconst = (vd->storage_class & STCconst) != 0;
+
+        // allocate storage on the stack
+        Logger::println("vdtype = %s", vd->type->toChars());
+        const llvm::Type* lltype = LLVM_DtoType(vd->type);
+        llvm::AllocaInst* allocainst = new llvm::AllocaInst(lltype, vd->toChars(), p->topallocapoint());
+        //allocainst->setAlignment(vd->type->alignsize()); // TODO
+        vd->llvmValue = allocainst;
+        // e->val = really needed??
+
+        LLVM_DtoInitializer(vd->type, vd->init);
+    }
+    // struct declaration
+    else if (StructDeclaration* s = declaration->isStructDeclaration())
+    {
+        Logger::println("StructDeclaration");
+        s->toObjFile();
+    }
+    // unsupported declaration
+    else
+    {
+        error("Only Var/Struct-Declaration is supported for DeclarationExp");
+        fatal();
+    }
+    return e;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem* VarExp::toElem(IRState* p)
+{
+    Logger::print("VarExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    elem* e = new elem;
+
+    assert(var);
+    if (VarDeclaration* vd = var->isVarDeclaration())
+    {
+        Logger::println("VarDeclaration");
+
+        if (TypeInfoDeclaration* tid = vd->isTypeInfoDeclaration())
+        {
+            Logger::println("TypeInfoDeclaration");
+        }
+
+        // this must be a dollar expression or some other magic value
+        if (!vd->llvmValue)
+        {
+            // dollar
+            if (!p->arrays.empty())
+            {
+                llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
+                llvm::Value* tmp = new llvm::GetElementPtrInst(p->arrays.back(),zero,zero,"tmp",p->scopebb());
+                e->val = new llvm::LoadInst(tmp,"tmp",p->scopebb());
+                e->type = elem::VAL;
+            }
+            // magic
+            else
+            {
+                if (TypeInfoDeclaration* tid = vd->isTypeInfoDeclaration())
+                {
+                    tid->toObjFile();
+                    e->mem = tid->llvmValue;
+                    e->type = elem::VAR;
+                }
+                else
+                assert(0 && "only magic supported is typeinfo");
+            }
+            return e;
+        }
+
+        // function parameter
+        if (vd->storage_class & STCparameter) {
+            Logger::println("function param");
+            if (vd->storage_class & (STCref | STCout)) {
+                e->mem = vd->llvmValue;
+                e->type = elem::VAR;
+            }
+            else {
+                if (vd->type->ty == Tstruct || vd->type->ty == Tdelegate || vd->type->ty == Tarray) {
+                    e->mem = vd->llvmValue;
+                    e->type = elem::VAR;
+                }
+                else {
+                    e->val = vd->llvmValue;
+                    e->type = elem::VAL;
+                }
+            }
+        }
+        else {
+            e->mem = vd->llvmValue;
+            //e->mem->setName(toChars());
+            e->vardecl = vd;
+            e->type = elem::VAR;
+        }
+    }
+    else if (FuncDeclaration* fdecl = var->isFuncDeclaration())
+    {
+        Logger::println("FuncDeclaration");
+        if (fdecl->llvmValue == 0) {
+            fdecl->toObjFile();
+        }
+        e->val = fdecl->llvmValue;
+        e->type = elem::FUNC;
+        e->funcdecl = fdecl;
+    }
+    else if (SymbolDeclaration* sdecl = var->isSymbolDeclaration())
+    {
+        // this seems to be the static initialiser for structs
+        Logger::print("Sym: type=%s\n", sdecl->type->toChars());
+        assert(sdecl->type->ty == Tstruct);
+        //assert(sdecl->llvmInitZ);
+        //e->val = sdecl->llvmInitZ;
+        TypeStruct* ts = (TypeStruct*)sdecl->type;
+        e->mem = ts->llvmInit;
+        assert(e->mem);
+        e->type = elem::VAR;
+    }
+    else
+    {
+        assert(0 && "Unimplemented VarExp type");
+    }
+
+    assert(e->mem || e->val);
+    return e;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem* IntegerExp::toElem(IRState* p)
+{
+    Logger::print("IntegerExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+    elem* e = new elem;
+    const llvm::Type* t = LLVM_DtoType(type);
+    if (llvm::isa<llvm::PointerType>(t)) {
+        llvm::Constant* i = llvm::ConstantInt::get(LLVM_DtoSize_t(),(uint64_t)value,false);
+        e->val = llvm::ConstantExpr::getIntToPtr(i, t);
+    }
+    else if (llvm::isa<llvm::IntegerType>(t)) {
+        e->val = llvm::ConstantInt::get(t,(uint64_t)value,!type->isunsigned());
+    }
+    else {
+        assert(0);
+    }
+    e->type = elem::CONST;
+    return e;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem* RealExp::toElem(IRState* p)
+{
+    Logger::print("RealExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+    elem* e = new elem;
+    e->val = llvm::ConstantFP::get(LLVM_DtoType(type),value);
+    e->type = elem::CONST;
+    return e;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem* NullExp::toElem(IRState* p)
+{
+    Logger::print("NullExp::toElem(type=%s): %s\n", type->toChars(),toChars());
+    LOG_SCOPE;
+    elem* e = new elem;
+    const llvm::Type* t = LLVM_DtoType(type);
+    if (llvm::isa<llvm::StructType>(t))
+        t = llvm::PointerType::get(t);
+    Logger::cout() << *t << '\n';
+    e->val = llvm::Constant::getNullValue(t);
+    assert(e->val);
+    Logger::cout() << *e->val << '\n';
+    e->type = elem::NUL;
+    return e;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem* StringExp::toElem(IRState* p)
+{
+    Logger::print("StringExp::toElem: %s\n", toChars());
+    LOG_SCOPE;
+
+    assert(type->next->ty == Tchar && "Only char is supported");
+    assert(sz == 1);
+
+    const llvm::Type* ct = LLVM_DtoType(type->next);
+    //printf("ct = %s\n", type->next->toChars());
+    const llvm::ArrayType* at = llvm::ArrayType::get(ct,len+1);
+
+    uint8_t* str = (uint8_t*)string;
+    std::string cont((char*)str, len);
+
+    llvm::Constant* _init = llvm::ConstantArray::get(cont,true);
+
+    llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::InternalLinkage;//WeakLinkage;
+    llvm::GlobalVariable* gvar = new llvm::GlobalVariable(at,true,_linkage,_init,"stringliteral",gIR->module);
+
+    llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
+    llvm::Value* arrptr = new llvm::GetElementPtrInst(gvar,zero,zero,"tmp",p->scopebb());
+
+    elem* e = new elem;
+
+    if (type->ty == Tarray) {
+        llvm::Value* arr = p->toplval();
+        LLVM_DtoSetArray(arr, llvm::ConstantInt::get(LLVM_DtoSize_t(),len,false), arrptr);
+    }
+    else if (type->ty == Tpointer) {
+        e->mem = arrptr;
+    }
+    else {
+        assert(0);
+    }
+
+    e->inplace = true;
+    e->type = elem::VAL;
+
+    return e;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem* AssignExp::toElem(IRState* p)
+{
+    Logger::print("AssignExp::toElem: %s | %s = %s\n", toChars(), e1->type->toChars(), e2->type->toChars());
+    LOG_SCOPE;
+
+    assert(e1 && e2);
+    p->inLvalue = true;
+        elem* l = e1->toElem(p);
+    p->inLvalue = false;
+
+    p->lvals.push_back(l->mem);
+        elem* r = e2->toElem(p);
+    p->lvals.pop_back();
+
+    assert(l->mem);
+    //e->val = l->store(r->getValue());
+
+    TY e1ty = e1->type->ty;
+    TY e2ty = e2->type->ty;
+
+    elem* e = new elem;
+
+    // struct
+    if (e1ty == Tstruct) {
+        // struct + struct
+        if (e2ty == Tstruct) {
+            // struct literals do the assignment themselvs (in place)
+            if (!r->inplace) {
+                TypeStruct* ts = (TypeStruct*)e2->type;
+                assert(r->mem);
+                LLVM_DtoStructCopy(ts,l->mem,r->mem);
+            }
+            else {
+                e->inplace = true;
+            }
+        }
+        // struct + const int
+        else if (e2->type->isintegral()){
+            IntegerExp* iexp = (IntegerExp*)e2;
+            assert(iexp->value == 0 && "Only integral struct initializer allowed is zero");
+            TypeStruct* st = (TypeStruct*)e1->type;
+            LLVM_DtoStructZeroInit(st, l->mem);
+        }
+        // :x
+        else
+        assert(0 && "struct = unknown");
+    }
+    else if (e1ty == Tsarray) {
+        assert(0 && "static array = not supported");
+    }
+    else if (e1ty == Tarray) {
+        if (e2->type->isscalar() || e2->type->ty == Tclass){
+            LLVM_DtoArrayInit(l->mem, r->getValue());
+        }
+        else if (e2ty == Tarray) {
+            //new llvm::StoreInst(r->val,l->val,p->scopebb());
+            if (r->type == elem::NUL) {
+                llvm::Constant* c = llvm::cast<llvm::Constant>(r->val);
+                assert(c->isNullValue());
+                LLVM_DtoNullArray(l->mem);
+            }
+            else if (r->type == elem::SLICE) {
+                if (l->type == elem::SLICE)
+                LLVM_DtoArrayCopy(l,r);
+                else
+                LLVM_DtoSetArray(l->mem,r->arg,r->mem);
+            }
+            else {
+                // new expressions write directly to the array reference
+                // so do string literals
+                if (!r->inplace) {
+                    assert(r->mem);
+                    LLVM_DtoArrayAssign(l->mem, r->mem);
+                }
+                else {
+                    e->inplace = true;
+                }
+            }
+        }
+        else
+        assert(0);
+    }
+    else if (e1ty == Tpointer) {
+        if (e2ty == Tpointer) {
+            llvm::Value* v = r->field ? r->mem : r->getValue();
+            Logger::cout() << "*=*: " << *v << ", " << *l->mem << '\n';
+            new llvm::StoreInst(v, l->mem, p->scopebb());
+        }
+        else
+        assert(0);
+    }
+    else if (e1ty == Tclass) {
+        if (e2ty == Tclass) {
+            llvm::Value* tmp = r->getValue();
+            Logger::cout() << "tmp: " << *tmp << ", " << *l->mem << '\n';
+            new llvm::StoreInst(tmp, l->mem, p->scopebb());
+        }
+        else
+        assert(0);
+    }
+    else if (e1ty == Tdelegate) {
+        Logger::println("Assigning to delegate");
+        if (e2ty == Tdelegate) {
+            if (r->type == elem::NUL) {
+                llvm::Constant* c = llvm::cast<llvm::Constant>(r->val);
+                if (c->isNullValue()) {
+                    LLVM_DtoNullDelegate(l->mem);
+                }
+                else
+                assert(0);
+            }
+            else if (r->inplace) {
+                // do nothing
+                e->inplace = true;
+            }
+            else
+            assert(0);
+        }
+        else
+        assert(0);
+    }
+    // !struct && !array && !pointer && !class
+    else {
+        Logger::cout() << *l->mem << '\n';
+        new llvm::StoreInst(r->getValue(),l->mem,p->scopebb());
+    }
+
+    delete r;
+    delete l;
+    return e;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem* AddExp::toElem(IRState* p)
+{
+    Logger::print("AddExp::toElem: %s\n", toChars());
+    LOG_SCOPE;
+    elem* e = new elem;
+    elem* l = e1->toElem(p);
+    elem* r = e2->toElem(p);
+
+    if (e1->type != e2->type) {
+        if (e1->type->ty == Tpointer && e1->type->next->ty == Tstruct) {
+            assert(l->field);
+            llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
+            assert(r->type == elem::CONST);
+            llvm::ConstantInt* cofs = llvm::cast<llvm::ConstantInt>(r->val);
+
+            TypeStruct* ts = (TypeStruct*)e1->type->next;
+            llvm::Value* offset = llvm::ConstantInt::get(llvm::Type::Int32Ty, ts->sym->offsetToIndex(cofs->getZExtValue()), false);
+
+            e->mem = new llvm::GetElementPtrInst(l->getValue(), zero, offset, "tmp", p->scopebb());
+            e->type = elem::VAR;
+            e->field = true;
+        }
+        else if (e1->type->ty == Tpointer) {
+            e->val = new llvm::GetElementPtrInst(l->getValue(), r->getValue(), "tmp", p->scopebb());
+            e->type = elem::VAR;
+        }
+        else {
+            assert(0);
+        }
+    }
+    else {
+        e->val = llvm::BinaryOperator::createAdd(l->getValue(), r->getValue(), "tmp", p->scopebb());
+        e->type = elem::VAL;
+    }
+    delete l;
+    delete r;
+    return e;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem* AddAssignExp::toElem(IRState* p)
+{
+    Logger::print("AddAssignExp::toElem: %s\n", toChars());
+    LOG_SCOPE;
+
+    elem* l = e1->toElem(p);
+    elem* r = e2->toElem(p);
+
+    elem* e = new elem;
+    llvm::Value* val = 0;
+    if (e1->type->ty == Tpointer) {
+        val = e->mem = new llvm::GetElementPtrInst(l->getValue(),r->getValue(),"tmp",p->scopebb());
+    }
+    else {
+        val = e->val = llvm::BinaryOperator::createAdd(l->getValue(),r->getValue(),"tmp",p->scopebb());
+    }
+
+    /*llvm::Value* storeVal = l->storeVal ? l->storeVal : l->val;
+    if (llvm::isa<llvm::PointerType>(storeVal->getType()) && storeVal->getType()->getContainedType(0) != tmp->getType())
+    {
+        tmp = LLVM_DtoPointedType(storeVal, tmp);
+    }*/
+
+    new llvm::StoreInst(val,l->mem,p->scopebb());
+    e->type = elem::VAR;
+
+    delete l;
+    delete r;
+    return e;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem* MinExp::toElem(IRState* p)
+{
+    Logger::print("MinExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+    elem* e = new elem;
+    elem* l = e1->toElem(p);
+    elem* r = e2->toElem(p);
+
+    llvm::Value* left = l->getValue();
+    if (llvm::isa<llvm::PointerType>(left->getType()))
+        left = new llvm::PtrToIntInst(left,LLVM_DtoSize_t(),"tmp",p->scopebb());
+
+    llvm::Value* right = r->getValue();
+    if (llvm::isa<llvm::PointerType>(right->getType()))
+        right = new llvm::PtrToIntInst(right,LLVM_DtoSize_t(),"tmp",p->scopebb());
+
+    e->val = llvm::BinaryOperator::createSub(left,right,"tmp",p->scopebb());
+    e->type = elem::VAL;
+
+    const llvm::Type* totype = LLVM_DtoType(type);
+    if (e->val->getType() != totype) {
+        assert(0);
+        assert(llvm::isa<llvm::PointerType>(e->val->getType()));
+        assert(llvm::isa<llvm::IntegerType>(totype));
+        e->val = new llvm::IntToPtrInst(e->val,totype,"tmp",p->scopebb());
+    }
+
+    delete l;
+    delete r;
+    return e;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem* MinAssignExp::toElem(IRState* p)
+{
+    Logger::print("MinAssignExp::toElem: %s\n", toChars());
+    LOG_SCOPE;
+
+    elem* l = e1->toElem(p);
+    elem* r = e2->toElem(p);
+
+    llvm::Value* tmp = 0;
+    if (e1->type->ty == Tpointer) {
+        tmp = r->getValue();
+        llvm::Value* zero = llvm::ConstantInt::get(tmp->getType(),0,false);
+        tmp = llvm::BinaryOperator::createSub(zero,tmp,"tmp",p->scopebb());
+        tmp = new llvm::GetElementPtrInst(l->getValue(),tmp,"tmp",p->scopebb());
+    }
+    else {
+        tmp = llvm::BinaryOperator::createSub(l->getValue(),r->getValue(),"tmp",p->scopebb());
+    }
+
+    /*llvm::Value* storeVal = l->storeVal ? l->storeVal : l->val;
+    if (storeVal->getType()->getContainedType(0) != tmp->getType())
+    {
+        tmp = LLVM_DtoPointedType(storeVal, tmp);
+    }*/
+
+    new llvm::StoreInst(tmp, l->mem, p->scopebb());
+
+    delete l;
+    delete r;
+
+    elem* e = new elem;
+    e->val = tmp;
+    e->type = elem::VAR;
+    return e;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem* MulExp::toElem(IRState* p)
+{
+    Logger::print("MulExp::toElem: %s\n", toChars());
+    LOG_SCOPE;
+    elem* e = new elem;
+    elem* l = e1->toElem(p);
+    elem* r = e2->toElem(p);
+    llvm::Value* vl = l->getValue();
+    llvm::Value* vr = r->getValue();
+    Logger::cout() << "mul: " << *vl << ", " << *vr << '\n';
+    e->val = llvm::BinaryOperator::createMul(vl,vr,"tmp",p->scopebb());
+    e->type = elem::VAL;
+    delete l;
+    delete r;
+    return e;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem* MulAssignExp::toElem(IRState* p)
+{
+    Logger::print("MulAssignExp::toElem: %s\n", toChars());
+    LOG_SCOPE;
+
+    elem* l = e1->toElem(p);
+    elem* r = e2->toElem(p);
+    llvm::Value* vl = l->getValue();
+    llvm::Value* vr = r->getValue();
+    Logger::cout() << "mulassign: " << *vl << ", " << *vr << '\n';
+    llvm::Value* tmp = llvm::BinaryOperator::createMul(vl,vr,"tmp",p->scopebb());
+
+    /*llvm::Value* storeVal = l->storeVal ? l->storeVal : l->val;
+    if (storeVal->getType()->getContainedType(0) != tmp->getType())
+    {
+        tmp = LLVM_DtoPointedType(storeVal, tmp);
+    }*/
+
+    new llvm::StoreInst(tmp,l->mem,p->scopebb());
+
+    delete l;
+    delete r;
+
+    elem* e = new elem;
+    e->val = tmp;
+    e->type = elem::VAR;
+    return e;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem* DivExp::toElem(IRState* p)
+{
+    Logger::print("DivExp::toElem: %s\n", toChars());
+    LOG_SCOPE;
+    elem* e = new elem;
+    elem* l = e1->toElem(p);
+    elem* r = e2->toElem(p);
+
+    if (type->isunsigned())
+        e->val = llvm::BinaryOperator::createUDiv(l->getValue(),r->getValue(),"tmp",p->scopebb());
+    else if (type->isintegral())
+        e->val = llvm::BinaryOperator::createSDiv(l->getValue(),r->getValue(),"tmp",p->scopebb());
+    else if (type->isfloating())
+        e->val = llvm::BinaryOperator::createFDiv(l->getValue(),r->getValue(),"tmp",p->scopebb());
+    else
+        assert(0);
+    e->type = elem::VAL;
+    delete l;
+    delete r;
+    return e;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem* DivAssignExp::toElem(IRState* p)
+{
+    Logger::print("DivAssignExp::toElem: %s\n", toChars());
+    LOG_SCOPE;
+
+    elem* l = e1->toElem(p);
+    elem* r = e2->toElem(p);
+
+    llvm::Value* tmp;
+    if (type->isunsigned())
+        tmp = llvm::BinaryOperator::createUDiv(l->getValue(),r->getValue(),"tmp",p->scopebb());
+    else if (type->isintegral())
+        tmp = llvm::BinaryOperator::createSDiv(l->getValue(),r->getValue(),"tmp",p->scopebb());
+    else if (type->isfloating())
+        tmp = llvm::BinaryOperator::createFDiv(l->getValue(),r->getValue(),"tmp",p->scopebb());
+    else
+        assert(0);
+
+    /*llvm::Value* storeVal = l->storeVal ? l->storeVal : l->val;
+    if (storeVal->getType()->getContainedType(0) != tmp->getType())
+    {
+        tmp = LLVM_DtoPointedType(storeVal, tmp);
+    }*/
+
+    new llvm::StoreInst(tmp,l->mem,p->scopebb());
+
+    delete l;
+    delete r;
+
+    elem* e = new elem;
+    e->val = tmp;
+    e->type = elem::VAR;
+    return e;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem* ModExp::toElem(IRState* p)
+{
+    Logger::print("ModExp::toElem: %s\n", toChars());
+    LOG_SCOPE;
+    elem* e = new elem;
+    elem* l = e1->toElem(p);
+    elem* r = e2->toElem(p);
+
+    if (type->isunsigned())
+        e->val = llvm::BinaryOperator::createURem(l->getValue(),r->getValue(),"tmp",p->scopebb());
+    else if (type->isintegral())
+        e->val = llvm::BinaryOperator::createSRem(l->getValue(),r->getValue(),"tmp",p->scopebb());
+    else if (type->isfloating())
+        e->val = llvm::BinaryOperator::createFRem(l->getValue(),r->getValue(),"tmp",p->scopebb());
+    else
+        assert(0);
+    e->type = elem::VAL;
+    delete l;
+    delete r;
+    return e;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem* ModAssignExp::toElem(IRState* p)
+{
+    Logger::print("ModAssignExp::toElem: %s\n", toChars());
+    LOG_SCOPE;
+
+    elem* l = e1->toElem(p);
+    elem* r = e2->toElem(p);
+
+    llvm::Value* tmp;
+    if (type->isunsigned())
+        tmp = llvm::BinaryOperator::createURem(l->getValue(),r->getValue(),"tmp",p->scopebb());
+    else if (type->isintegral())
+        tmp = llvm::BinaryOperator::createSRem(l->getValue(),r->getValue(),"tmp",p->scopebb());
+    else if (type->isfloating())
+        tmp = llvm::BinaryOperator::createFRem(l->getValue(),r->getValue(),"tmp",p->scopebb());
+    else
+        assert(0);
+
+    /*llvm::Value* storeVal = l->storeVal ? l->storeVal : l->val;
+    if (storeVal->getType()->getContainedType(0) != tmp->getType())
+    {
+        tmp = LLVM_DtoPointedType(storeVal, tmp);
+    }*/
+
+    new llvm::StoreInst(tmp,l->mem,p->scopebb());
+
+    delete l;
+    delete r;
+
+    elem* e = new elem;
+    e->val = tmp;
+    e->type = elem::VAR;
+    return e;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem* CallExp::toElem(IRState* p)
+{
+    Logger::print("CallExp::toElem: %s\n", toChars());
+    LOG_SCOPE;
+    elem* e = new elem;
+    elem* fn = e1->toElem(p);
+    LINK dlink = LINKdefault;
+    
+    bool delegateCall = false;
+    llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty,0,false);
+    llvm::Value* one = llvm::ConstantInt::get(llvm::Type::Int32Ty,1,false);
+
+    // hidden struct return parameter handling
+    bool retinptr = false;
+    
+    TypeFunction* tf = 0;
+    
+    // regular functions
+    if (e1->type->ty == Tfunction) {
+        tf = (TypeFunction*)e1->type;
+        if (tf->llvmRetInPtr) {
+            retinptr = true;
+        }
+        dlink = tf->linkage;
+    }
+    
+    // delegates
+    else if (e1->type->ty == Tdelegate) {
+        Logger::println("delegateTy = %s\n", e1->type->toChars());
+        assert(e1->type->next->ty == Tfunction);
+        tf = (TypeFunction*)e1->type->next;
+        if (tf->llvmRetInPtr) {
+            retinptr = true;
+        }
+        dlink = tf->linkage;
+        delegateCall = true;
+    }
+    
+    // invalid
+    else {
+        assert(tf);
+    }
+
+    size_t n = arguments->dim;
+    if (fn->arg || delegateCall) n++;
+    if (retinptr) n++;
+
+    llvm::Value* funcval = fn->getValue();
+    std::vector<llvm::Value*> llargs(n, 0);
+
+    const llvm::FunctionType* llfnty = 0;
+    
+    // normal function call
+    if (llvm::isa<llvm::FunctionType>(funcval->getType())) {
+        llfnty = llvm::cast<llvm::FunctionType>(funcval->getType());
+    }
+    // pointer to something
+    else if (llvm::isa<llvm::PointerType>(funcval->getType())) {
+        // pointer to function pointer - I think this not really supposed to happen, but does :/
+        // seems like sometimes we get a func* other times a func**
+        if (llvm::isa<llvm::PointerType>(funcval->getType()->getContainedType(0))) {
+            funcval = new llvm::LoadInst(funcval,"tmp",p->scopebb());
+        }
+        
+        // function pointer
+        if (llvm::isa<llvm::FunctionType>(funcval->getType()->getContainedType(0))) {
+            //Logger::cout() << "function pointer type:\n" << *funcval << '\n';
+            llfnty = llvm::cast<llvm::FunctionType>(funcval->getType()->getContainedType(0));
+        }
+        // struct pointer - delegate
+        else if (llvm::isa<llvm::StructType>(funcval->getType()->getContainedType(0))) {
+            funcval = new llvm::GetElementPtrInst(funcval,zero,one,"tmp",p->scopebb());
+            funcval = new llvm::LoadInst(funcval,"tmp",p->scopebb());
+            const llvm::Type* ty = funcval->getType()->getContainedType(0);
+            llfnty = llvm::cast<llvm::FunctionType>(ty);
+        }
+        // unknown
+        else {
+            Logger::cout() << "what kind of pointer are we calling? : " << *funcval->getType() << '\n';
+        }
+    }
+    else {
+        Logger::cout() << "what are we calling? : " << *funcval << '\n';
+    }
+    assert(llfnty);
+    Logger::cout() << "Function LLVM type: " << *llfnty << '\n';
+
+    // argument handling
+    llvm::FunctionType::param_iterator argiter = llfnty->param_begin();
+    int j = 0;
+
+    // hidden struct return parameter
+    if (retinptr) {
+        if (!p->lvals.empty()) {
+            assert(llvm::isa<llvm::StructType>(p->toplval()->getType()->getContainedType(0)));
+            llargs[j] = p->toplval();
+            TY Dty = tf->next->ty;
+            if (Dty == Tstruct || Dty == Tdelegate || Dty == Tarray) {
+                e->inplace = true;
+            }
+            else
+            assert(0);
+        }
+        else {
+            llargs[j] = new llvm::AllocaInst(argiter->get()->getContainedType(0),"rettmp",p->topallocapoint());
+        }
+        ++j;
+        ++argiter;
+        e->type = elem::VAR;
+    }
+    else {
+        e->type = elem::VAL;
+    }
+
+    // this parameter
+    if (fn->arg) {
+        Logger::println("This Call");
+        if (fn->arg->getType() != argiter->get()) {
+            //Logger::cout() << *fn->thisparam << '|' << *argiter->get() << '\n';
+            llargs[j] = new llvm::BitCastInst(fn->arg, argiter->get(), "tmp", p->scopebb());
+        }
+        else {
+            llargs[j] = fn->arg;
+        }
+        ++j;
+        ++argiter;
+    }
+    // delegate context parameter
+    else if (delegateCall) {
+        Logger::println("Delegate Call");
+        llvm::Value* contextptr = new llvm::GetElementPtrInst(fn->mem,zero,zero,"tmp",p->scopebb());
+        llargs[j] = new llvm::LoadInst(contextptr,"tmp",p->scopebb());
+        ++j;
+        ++argiter;
+    }
+
+    // regular parameters
+    for (int i=0; i<arguments->dim; i++,j++)
+    {
+        Expression* argexp = (Expression*)arguments->data[i];
+        elem* arg = argexp->toElem(p);
+
+        Argument* fnarg = Argument::getNth(tf->parameters, i);
+
+        TY argty = argexp->type->ty;
+        if (argty == Tstruct || argty == Tdelegate || argty == Tarray) {
+            if (!fnarg || !fnarg->llvmCopy) {
+                llargs[j] = arg->getValue();
+                assert(llargs[j] != 0);
+            }
+            else {
+                llvm::Value* allocaInst = 0;
+                llvm::BasicBlock* entryblock = &p->topfunc()->front();
+                const llvm::PointerType* pty = llvm::cast<llvm::PointerType>(arg->mem->getType());
+                allocaInst = new llvm::AllocaInst(pty->getElementType(), "tmpparam", p->topallocapoint());
+                if (argty == Tstruct) {
+                    TypeStruct* ts = (TypeStruct*)argexp->type;
+                    LLVM_DtoStructCopy(ts,allocaInst,arg->mem);
+                }
+                else if (argty == Tdelegate) {
+                    LLVM_DtoDelegateCopy(allocaInst,arg->mem);
+                }
+                else if (argty == Tarray) {
+                    LLVM_DtoArrayAssign(allocaInst,arg->mem);
+                }
+                else
+                assert(0);
+
+                llargs[j] = allocaInst;
+                assert(llargs[j] != 0);
+            }
+        }
+        else if (!fnarg || fnarg->llvmCopy) {
+            llargs[j] = arg->getValue();
+            assert(llargs[j] != 0);
+        }
+        else {
+            llargs[j] = arg->mem;
+            assert(llargs[j] != 0);
+        }
+
+        delete arg;
+    }
+
+    // void returns cannot not be named
+    const char* varname = "";
+    if (llfnty->getReturnType() != llvm::Type::VoidTy)
+        varname = "tmp";
+
+    Logger::println("%d params passed", n);
+    for (int i=0; i<n; ++i)
+    {
+        Logger::cout() << *llargs[i] << '\n';
+    }
+
+    Logger::cout() << "Calling: " << *funcval->getType() << '\n';
+
+    // call the function
+    llvm::CallInst* call = new llvm::CallInst(funcval, llargs.begin(), llargs.end(), varname, p->scopebb());
+    e->val = call;
+
+    // set calling convention
+    if ((fn->funcdecl && (fn->funcdecl->llvmInternal != LLVMintrinsic)) || delegateCall)
+        call->setCallingConv(LLVM_DtoCallingConv(dlink));
+
+    delete fn;
+    return e;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem* CastExp::toElem(IRState* p)
+{
+    Logger::print("CastExp::toElem: %s\n", toChars());
+    LOG_SCOPE;
+    elem* e = new elem;
+    elem* u = e1->toElem(p);
+    const llvm::Type* totype = LLVM_DtoType(to);
+    Type* from = e1->type;
+    int lsz = from->size();
+    int rsz = to->size();
+
+    // this makes sure the strange lvalue casts don't screw things up
+    e->mem = u->mem;
+
+    if (from->isintegral()) {
+        if (to->isintegral()) {
+            if (lsz < rsz) {
+                Logger::cout() << *totype << '\n';
+                if (from->isunsigned() || from->ty == Tbool) {
+                    e->val = new llvm::ZExtInst(u->getValue(), totype, "tmp", p->scopebb());
+                } else {
+                    e->val = new llvm::SExtInst(u->getValue(), totype, "tmp", p->scopebb());
+                }
+            }
+            else if (lsz > rsz) {
+                e->val = new llvm::TruncInst(u->getValue(), totype, "tmp", p->scopebb());
+            }
+            else {
+                e->val = new llvm::BitCastInst(u->getValue(), totype, "tmp", p->scopebb());
+            }
+        }
+        else if (to->isfloating()) {
+            if (from->isunsigned()) {
+                e->val = new llvm::UIToFPInst(u->getValue(), totype, "tmp", p->scopebb());
+            }
+            else {
+                e->val = new llvm::SIToFPInst(u->getValue(), totype, "tmp", p->scopebb());
+            }
+        }
+        else {
+            assert(0);
+        }
+        //e->storeVal = u->storeVal ? u->storeVal : u->val;
+        e->type = elem::VAL;
+    }
+    else if (from->isfloating()) {
+        if (to->isfloating()) {
+            if ((from->ty == Tfloat80 || from->ty == Tfloat64) && (to->ty == Tfloat80 || to->ty == Tfloat64)) {
+                e->val = u->getValue();
+            }
+            else if (lsz < rsz) {
+                e->val = new llvm::FPExtInst(u->getValue(), totype, "tmp", p->scopebb());
+            }
+            else if (lsz > rsz) {
+                e->val = new llvm::FPTruncInst(u->getValue(), totype, "tmp", p->scopebb());
+            }
+            else {
+                assert(0);
+            }
+        }
+        else if (to->isintegral()) {
+            if (to->isunsigned()) {
+                e->val = new llvm::FPToUIInst(u->getValue(), totype, "tmp", p->scopebb());
+            }
+            else {
+                e->val = new llvm::FPToSIInst(u->getValue(), totype, "tmp", p->scopebb());
+            }
+        }
+        else {
+            assert(0);
+        }
+        e->type = elem::VAL;
+    }
+    else if (from->ty == Tclass) {
+        //assert(to->ty == Tclass);
+        e->val = new llvm::BitCastInst(u->getValue(), totype, "tmp", p->scopebb());
+        e->type = elem::VAL;
+    }
+    else if (from->ty == Tarray || from->ty == Tsarray) {
+        Logger::cout() << "from array or sarray" << '\n';
+        if (to->ty == Tpointer) {
+            Logger::cout() << "to pointer" << '\n';
+            assert(from->next == to->next);
+            llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
+            llvm::Value* one = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1, false);
+            llvm::Value* ptr = new llvm::GetElementPtrInst(u->getValue(),zero,one,"tmp",p->scopebb());
+            e->val = new llvm::LoadInst(ptr, "tmp", p->scopebb());
+            e->type = elem::VAL;
+        }
+        else if (to->ty == Tarray) {
+            Logger::cout() << "to array" << '\n';
+            assert(from->next->size() == to->next->size());
+            const llvm::Type* ptrty = LLVM_DtoType(to->next);
+            if (ptrty == llvm::Type::VoidTy)
+                ptrty = llvm::Type::Int8Ty;
+            ptrty = llvm::PointerType::get(ptrty);
+
+            if (u->type == elem::SLICE) {
+                e->mem = new llvm::BitCastInst(u->mem, ptrty, "tmp", p->scopebb());
+                e->arg = u->arg;
+            }
+            else {
+                llvm::Value* uval = u->getValue();
+                llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
+                llvm::Value* one = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1, false);
+                e->arg = new llvm::GetElementPtrInst(uval,zero,zero,"tmp",p->scopebb());
+                e->arg = new llvm::LoadInst(e->arg, "tmp", p->scopebb());
+
+                e->mem = new llvm::GetElementPtrInst(uval,zero,one,"tmp",p->scopebb());
+                e->mem = new llvm::LoadInst(e->mem, "tmp", p->scopebb());
+                e->mem = new llvm::BitCastInst(e->mem, ptrty, "tmp", p->scopebb());
+            }
+            e->type = elem::SLICE;
+        }
+        else if (to->ty == Tsarray) {
+            Logger::cout() << "to sarray" << '\n';
+            assert(0);
+        }
+        else {
+            assert(0);
+        }
+    }
+    else if (from->ty == Tpointer) {
+        if (to->ty == Tpointer || to->ty == Tclass) {
+            llvm::Value* src = u->getValue();
+            //Logger::cout() << *src << '|' << *totype << '\n';
+            e->val = new llvm::BitCastInst(src, totype, "tmp", p->scopebb());
+        }
+        else if (to->isintegral()) {
+            e->val = new llvm::PtrToIntInst(u->getValue(), totype, "tmp", p->scopebb());
+        }
+        else
+        assert(0);
+        e->type = elem::VAL;
+    }
+    else {
+        assert(0);
+    }
+    delete u;
+    return e;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem* SymOffExp::toElem(IRState* p)
+{
+    Logger::print("SymOffExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+    elem* e = 0;
+    if (VarDeclaration* vd = var->isVarDeclaration())
+    {
+        Logger::println("VarDeclaration");
+        if (vd->type->ty == Tstruct && !(type->ty == Tpointer && type->next == vd->type)) {
+            TypeStruct* vdt = (TypeStruct*)vd->type;
+            e = new elem;
+            llvm::Value* idx0 = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
+            llvm::Value* idx1 = llvm::ConstantInt::get(llvm::Type::Int32Ty, (uint64_t)vdt->sym->offsetToIndex(offset), false);
+            //const llvm::Type* _typ = llvm::GetElementPtrInst::getIndexedType(LLVM_DtoType(type), idx1);
+            llvm::Value* ptr = vd->llvmValue;
+            assert(ptr);
+            e->mem = new llvm::GetElementPtrInst(ptr,idx0,idx1,"tmp",p->scopebb());
+            e->type = elem::VAL;
+            e->field = true;
+        }
+        else if (vd->type->ty == Tsarray) {
+            /*e = new elem;
+            llvm::Value* idx0 = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
+            e->val = new llvm::GetElementPtrInst(vd->llvmValue,idx0,idx0,"tmp",p->scopebb());*/
+            e = new elem;
+            llvm::Value* idx0 = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
+            //llvm::Value* idx1 = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1, false);
+            e->mem = new llvm::GetElementPtrInst(vd->llvmValue,idx0,idx0,"tmp",p->scopebb());
+            e->type = elem::VAL;
+        }
+        else if (offset == 0) {
+            vd->toObjFile();
+            e = new elem;
+            e->mem = vd->llvmValue;
+            //e->vardecl = vd;
+            e->type = elem::VAL;
+        }
+        else {
+            assert(0);
+        }
+    }
+    else if (FuncDeclaration* fd = var->isFuncDeclaration())
+    {
+        Logger::println("FuncDeclaration");
+        e = new elem;
+        if (fd->llvmValue == 0)
+            fd->toObjFile();
+        e->val = fd->llvmValue;
+        //e->aspointer = true;
+        e->type = elem::FUNC;
+    }
+    assert(e != 0);
+    assert(e->type != elem::NONE);
+    return e;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem* PtrExp::toElem(IRState* p)
+{
+    Logger::print("PtrExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+    elem* e = new elem;
+    elem* a = e1->toElem(p);
+
+    if (a->mem)
+        Logger::cout() << "mem: " << *a->mem << '\n';
+    if (a->val)
+        Logger::cout() << "val: " << *a->val << '\n';
+
+    if (a->field)
+        e->mem = a->mem;
+    else
+        e->mem = a->getValue();
+    e->type = elem::VAR;
+
+    delete a;
+    return e;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem* DotVarExp::toElem(IRState* p)
+{
+    Logger::print("DotVarExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+    elem* e = new elem;
+
+    elem* l = e1->toElem(p);
+
+    Logger::print("e1->type=%s\n", e1->type->toChars());
+
+    if (VarDeclaration* vd = var->isVarDeclaration()) {
+        size_t vdoffset = (size_t)-1;
+        llvm::Value* src = 0;
+        if (e1->type->ty == Tpointer) {
+            assert(e1->type->next->ty == Tstruct);
+            TypeStruct* ts = (TypeStruct*)e1->type->next;
+            vdoffset = ts->sym->offsetToIndex(vd->offset);
+            Logger::println("Struct member offset:%d index:%d", vd->offset, vdoffset);
+            src = l->val;
+        }
+        else if (e1->type->ty == Tclass) {
+            TypeClass* tc = (TypeClass*)e1->type;
+            Logger::println("Class member offset: %d", vd->offset);
+            vdoffset = tc->sym->offsetToIndex(vd->offset);
+            src = l->getValue();
+        }
+        assert(vdoffset != (size_t)-1);
+        assert(src != 0);
+        llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
+        llvm::Value* offset = llvm::ConstantInt::get(llvm::Type::Int32Ty, vdoffset, false);
+        llvm::Value* arrptr = new llvm::GetElementPtrInst(src,zero,offset,"tmp",p->scopebb());
+        e->mem = arrptr;
+        Logger::cout() << "mem: " << *e->mem << '\n';
+        e->type = elem::VAR;
+    }
+    else if (FuncDeclaration* fdecl = var->isFuncDeclaration())
+    {
+        if (fdecl->llvmValue == 0)
+        {
+            fdecl->toObjFile();
+        }
+
+        llvm::Value* funcval = fdecl->llvmValue;
+        e->arg = l->getValue();
+
+        // virtual call
+        if (fdecl->isVirtual()) {
+            assert(fdecl->vtblIndex > 0);
+            assert(e1->type->ty == Tclass);
+
+            const llvm::Type* vtbltype = llvm::PointerType::get(llvm::ArrayType::get(llvm::PointerType::get(llvm::Type::Int8Ty),0));
+
+            llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
+            llvm::Value* vtblidx = llvm::ConstantInt::get(llvm::Type::Int32Ty, (size_t)fdecl->vtblIndex, false);
+            funcval = new llvm::GetElementPtrInst(e->arg, zero, zero, "tmp", p->scopebb());
+            funcval = new llvm::LoadInst(funcval,"tmp",p->scopebb());
+            funcval = new llvm::BitCastInst(funcval, vtbltype, "tmp", p->scopebb());
+            funcval = new llvm::GetElementPtrInst(funcval, zero, vtblidx, "tmp", p->scopebb());
+            funcval = new llvm::LoadInst(funcval,"tmp",p->scopebb());
+            funcval = new llvm::BitCastInst(funcval, fdecl->llvmValue->getType(), "tmp", p->scopebb());
+        }
+        e->val = funcval;
+        e->type = elem::VAL;
+    }
+    else {
+        printf("unknown: %s\n", var->toChars());
+        assert(0);
+    }
+
+    delete l;
+
+    return e;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem* ThisExp::toElem(IRState* p)
+{
+    Logger::print("ThisExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+    elem* e = new elem;
+
+    if (VarDeclaration* vd = var->isVarDeclaration()) {
+        assert(vd->llvmValue == 0);
+
+        llvm::Function* fn = p->topfunc();
+        assert(fn);
+
+        TypeFunction* tf = p->topfunctype();
+        assert(tf);
+
+        llvm::Value* v = 0;
+        if (tf->llvmRetInPtr)
+        v = ++fn->arg_begin();
+        else
+        v = fn->arg_begin();
+        assert(v);
+
+        e->val = v;
+        e->type = elem::VAL;
+    }
+    else {
+        assert(0);
+    }
+
+    return e;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem* AddrExp::toElem(IRState* p)
+{
+    Logger::print("AddrExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+    elem* e = e1->toElem(p);
+    e->field = true;
+    return e;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem* StructLiteralExp::toElem(IRState* p)
+{
+    Logger::print("StructLiteralExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+    elem* e = new elem;
+
+    // if there is no lval, this must be a static initializer for a global. correct?
+    if (p->lvals.empty())
+    {
+        // TODO
+        assert(0);
+    }
+    // otherwise write directly in the lvalue
+    else
+    {
+        llvm::Value* sptr = p->toplval();
+        assert(sptr);
+
+        llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
+
+        unsigned n = elements->dim;
+        for (unsigned i=0; i<n; ++i)
+        {
+            llvm::Value* offset = llvm::ConstantInt::get(llvm::Type::Int32Ty, i, false);
+            llvm::Value* arrptr = new llvm::GetElementPtrInst(sptr,zero,offset,"tmp",p->scopebb());
+
+            Expression* vx = (Expression*)elements->data[i];
+            if (vx != 0) {
+                elem* ve = vx->toElem(p);
+                //Logger::cout() << *ve->val << " | " << *arrptr << '\n';
+                new llvm::StoreInst(ve->getValue(), arrptr, p->scopebb());
+                delete ve;
+            }
+            else {
+                assert(0);
+            }
+        }
+    }
+
+    e->inplace = true;
+
+    return e;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem* IndexExp::toElem(IRState* p)
+{
+    Logger::print("IndexExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    elem* e = new elem;
+
+    elem* l = e1->toElem(p);
+
+    p->arrays.push_back(l->mem); // if $ is used it must be an array so this is fine.
+    elem* r = e2->toElem(p);
+    p->arrays.pop_back();
+
+    llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
+    llvm::Value* one = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1, false);
+
+    llvm::Value* arrptr = 0;
+    if (e1->type->ty == Tpointer) {
+        arrptr = new llvm::GetElementPtrInst(l->getValue(),r->getValue(),"tmp",p->scopebb());
+    }
+    else if (e1->type->ty == Tsarray) {
+        arrptr = new llvm::GetElementPtrInst(l->mem, zero, r->getValue(),"tmp",p->scopebb());
+    }
+    else if (e1->type->ty == Tarray) {
+        arrptr = new llvm::GetElementPtrInst(l->mem,zero,one,"tmp",p->scopebb());
+        arrptr = new llvm::LoadInst(arrptr,"tmp",p->scopebb());
+        arrptr = new llvm::GetElementPtrInst(arrptr,r->getValue(),"tmp",p->scopebb());
+    }
+    assert(arrptr);
+
+    e->mem = arrptr;
+    e->type = elem::VAR;
+
+    delete l;
+    delete r;
+
+    return e;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem* SliceExp::toElem(IRState* p)
+{
+    Logger::print("SliceExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    elem* v = e1->toElem(p);
+
+    elem* e = new elem;
+    assert(v->mem);
+    e->type = elem::SLICE;
+
+    llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
+    llvm::Value* one = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1, false);
+
+    // partial slice
+    if (lwr)
+    {
+        assert(upr);
+        p->arrays.push_back(v->mem);
+        elem* lo = lwr->toElem(p);
+
+        bool lwr_is_zero = false;
+        if (lo->type == elem::CONST)
+        {
+            assert(lo->val);
+            assert(llvm::isa<llvm::ConstantInt>(lo->val));
+
+            if (e1->type->ty == Tpointer) {
+                e->mem = v->getValue();
+            }
+            else if (e1->type->ty == Tarray) {
+                llvm::Value* tmp = new llvm::GetElementPtrInst(v->mem,zero,one,"tmp",p->scopebb());
+                e->mem = new llvm::LoadInst(tmp,"tmp",p->scopebb());
+            }
+            else
+            assert(e->mem);
+
+            llvm::ConstantInt* c = llvm::cast<llvm::ConstantInt>(lo->val);
+            if (!(lwr_is_zero = c->isZero())) {
+                e->mem = new llvm::GetElementPtrInst(e->mem,lo->val,"tmp",p->scopebb());
+            }
+        }
+        else
+        {
+            llvm::Value* tmp = new llvm::GetElementPtrInst(v->mem,zero,one,"tmp",p->scopebb());
+            tmp = new llvm::LoadInst(tmp,"tmp",p->scopebb());
+            e->mem = new llvm::GetElementPtrInst(tmp,lo->getValue(),"tmp",p->scopebb());
+        }
+
+        elem* up = upr->toElem(p);
+        p->arrays.pop_back();
+
+        if (up->type == elem::CONST)
+        {
+            assert(up->val);
+            assert(llvm::isa<llvm::ConstantInt>(up->val));
+            if (lwr_is_zero) {
+                e->arg = up->val;
+            }
+            else {
+                if (lo->type == elem::CONST) {
+                    llvm::Constant* clo = llvm::cast<llvm::Constant>(lo->val);
+                    llvm::Constant* cup = llvm::cast<llvm::Constant>(up->val);
+                    e->arg = llvm::ConstantExpr::getSub(cup, clo);
+                }
+                else {
+                    e->arg = llvm::BinaryOperator::createSub(up->val, lo->getValue(), "tmp", p->scopebb());
+                }
+            }
+        }
+        else
+        {
+            if (lwr_is_zero) {
+                e->arg = up->getValue();
+            }
+            else {
+                e->arg = llvm::BinaryOperator::createSub(up->getValue(), lo->getValue(), "tmp", p->scopebb());
+            }
+        }
+
+        delete lo;
+        delete up;
+    }
+    // full slice
+    else
+    {
+        e->mem = v->mem;
+    }
+
+    delete v;
+
+    return e;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem* CmpExp::toElem(IRState* p)
+{
+    Logger::print("CmpExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    elem* e = new elem;
+
+    elem* l = e1->toElem(p);
+    elem* r = e2->toElem(p);
+
+    assert(e1->type == e2->type);
+
+    Type* t = e1->type;
+
+    if (t->isintegral())
+    {
+        llvm::ICmpInst::Predicate cmpop;
+        switch(op)
+        {
+        case TOKlt:
+            cmpop = t->isunsigned() ? llvm::ICmpInst::ICMP_ULT : llvm::ICmpInst::ICMP_SLT;
+            break;
+        case TOKle:
+            cmpop = t->isunsigned() ? llvm::ICmpInst::ICMP_ULE : llvm::ICmpInst::ICMP_SLE;
+            break;
+        case TOKgt:
+            cmpop = t->isunsigned() ? llvm::ICmpInst::ICMP_UGT : llvm::ICmpInst::ICMP_SGT;
+            break;
+        case TOKge:
+            cmpop = t->isunsigned() ? llvm::ICmpInst::ICMP_UGE : llvm::ICmpInst::ICMP_SGE;
+            break;
+        default:
+            assert(0);
+        }
+        e->val = new llvm::ICmpInst(cmpop, l->getValue(), r->getValue(), "tmp", p->scopebb());
+    }
+    else if (t->isfloating())
+    {
+        llvm::FCmpInst::Predicate cmpop;
+        switch(op)
+        {
+        case TOKlt:
+            cmpop = llvm::FCmpInst::FCMP_OLT;break;
+        case TOKle:
+            cmpop = llvm::FCmpInst::FCMP_OLE;break;
+        case TOKgt:
+            cmpop = llvm::FCmpInst::FCMP_OGT;break;
+        case TOKge:
+            cmpop = llvm::FCmpInst::FCMP_OGE;break;
+        case TOKunord:
+            cmpop = llvm::FCmpInst::FCMP_UNO;break;
+        case TOKule:
+            cmpop = llvm::FCmpInst::FCMP_ULE;break;
+        case TOKul:
+            cmpop = llvm::FCmpInst::FCMP_ULT;break;
+        case TOKuge:
+            cmpop = llvm::FCmpInst::FCMP_UGE;break;
+        case TOKug:
+            cmpop = llvm::FCmpInst::FCMP_UGT;break;
+        case TOKue:
+            cmpop = llvm::FCmpInst::FCMP_UEQ;break;
+        case TOKlg:
+            cmpop = llvm::FCmpInst::FCMP_ONE;break;
+        case TOKleg:
+            cmpop = llvm::FCmpInst::FCMP_ORD;break;
+
+        default:
+            assert(0);
+        }
+        e->val = new llvm::FCmpInst(cmpop, l->getValue(), r->getValue(), "tmp", p->scopebb());
+    }
+    else
+    {
+        assert(0 && "Unsupported CmpExp type");
+    }
+
+    delete l;
+    delete r;
+
+    e->type = elem::VAL;
+
+    return e;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem* EqualExp::toElem(IRState* p)
+{
+    Logger::print("EqualExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    elem* e = new elem;
+
+    elem* l = e1->toElem(p);
+    elem* r = e2->toElem(p);
+
+    assert(e1->type == e2->type);
+
+    Type* t = e1->type;
+
+    if (t->isintegral() || t->ty == Tpointer)
+    {
+        llvm::ICmpInst::Predicate cmpop;
+        switch(op)
+        {
+        case TOKequal:
+            cmpop = llvm::ICmpInst::ICMP_EQ;
+            break;
+        case TOKnotequal:
+            cmpop = llvm::ICmpInst::ICMP_NE;
+            break;
+        default:
+            assert(0);
+        }
+        e->val = new llvm::ICmpInst(cmpop, l->getValue(), r->getValue(), "tmp", p->scopebb());
+    }
+    else if (t->isfloating())
+    {
+        llvm::FCmpInst::Predicate cmpop;
+        switch(op)
+        {
+        case TOKequal:
+            cmpop = llvm::FCmpInst::FCMP_OEQ;
+            break;
+        case TOKnotequal:
+            cmpop = llvm::FCmpInst::FCMP_UNE;
+            break;
+        default:
+            assert(0);
+        }
+        e->val = new llvm::FCmpInst(cmpop, l->getValue(), r->getValue(), "tmp", p->scopebb());
+    }
+    else if (t->ty == Tarray)
+    {
+        // array comparison invokes the typeinfo runtime
+        assert(0);
+    }
+    else
+    {
+        assert(0 && "Unsupported EqualExp type");
+    }
+
+    delete l;
+    delete r;
+
+    e->type = elem::VAL;
+
+    return e;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem* PostExp::toElem(IRState* p)
+{
+    Logger::print("PostExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    elem* l = e1->toElem(p);
+    elem* r = e2->toElem(p);
+
+    elem* e = new elem;
+    e->mem = l->mem;
+    e->val = l->getValue();
+    e->type = elem::VAL;
+
+    llvm::Value* val = e->val;
+    llvm::Value* post = 0;
+
+    if (e1->type->isintegral())
+    {
+        assert(e2->type->isintegral());
+        llvm::Value* one = llvm::ConstantInt::get(val->getType(), 1, !e2->type->isunsigned());
+        if (op == TOKplusplus) {
+            post = llvm::BinaryOperator::createAdd(val,one,"tmp",p->scopebb());
+        }
+        else if (op == TOKminusminus) {
+            post = llvm::BinaryOperator::createSub(val,one,"tmp",p->scopebb());
+        }
+    }
+    else if (e1->type->ty == Tpointer)
+    {
+        assert(e2->type->isintegral());
+        llvm::Constant* minusone = llvm::ConstantInt::get(LLVM_DtoSize_t(),(uint64_t)-1,true);
+        llvm::Constant* plusone = llvm::ConstantInt::get(LLVM_DtoSize_t(),(uint64_t)1,false);
+        llvm::Constant* whichone = (op == TOKplusplus) ? plusone : minusone;
+        post = new llvm::GetElementPtrInst(val, whichone, "tmp", p->scopebb());
+    }
+    else if (e1->type->isfloating())
+    {
+        assert(e2->type->isfloating());
+        llvm::Value* one = llvm::ConstantFP::get(val->getType(), 1.0f);
+        if (op == TOKplusplus) {
+            post = llvm::BinaryOperator::createAdd(val,one,"tmp",p->scopebb());
+        }
+        else if (op == TOKminusminus) {
+            post = llvm::BinaryOperator::createSub(val,one,"tmp",p->scopebb());
+        }
+    }
+    else
+    assert(post);
+
+    //llvm::Value* tostore = l->storeVal ? l->storeVal : l->val;
+    new llvm::StoreInst(post,l->mem,p->scopebb());
+
+    delete l;
+    delete r;
+
+    return e;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem* NewExp::toElem(IRState* p)
+{
+    Logger::print("NewExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    assert(!thisexp);
+    assert(!newargs);
+    assert(newtype);
+    //assert(!arguments);
+    //assert(!member);
+    assert(!allocator);
+
+    elem* e = new elem;
+
+    const llvm::Type* t = LLVM_DtoType(newtype);
+
+    if (onstack) {
+        assert(newtype->ty == Tclass);
+        e->mem = new llvm::AllocaInst(t->getContainedType(0),"tmp",p->topallocapoint());
+    }
+    else {
+        if (newtype->ty == Tclass) {
+            e->mem = new llvm::MallocInst(t->getContainedType(0),"tmp",p->scopebb());
+        }
+        else if (newtype->ty == Tarray) {
+            t = LLVM_DtoType(newtype->next);
+            assert(arguments);
+            if (arguments->dim == 1) {
+                elem* sz = ((Expression*)arguments->data[0])->toElem(p);
+                llvm::Value* dimval = sz->getValue();
+                llvm::Value* usedimval = dimval;
+                if (dimval->getType() != llvm::Type::Int32Ty)
+                    usedimval = new llvm::TruncInst(dimval, llvm::Type::Int32Ty,"tmp",p->scopebb());
+                e->mem = new llvm::MallocInst(t,usedimval,"tmp",p->scopebb());
+
+                LLVM_DtoSetArray(p->toplval(), dimval, e->mem);
+                delete sz;
+            }
+            else {
+                assert(0);
+            }
+        }
+        else {
+            e->mem = new llvm::MallocInst(t,"tmp",p->scopebb());
+        }
+    }
+
+    if (newtype->ty == Tclass) {
+        // first apply the static initializer
+        assert(e->mem);
+        LLVM_DtoInitClass((TypeClass*)newtype, e->mem);
+
+        // then call constructor
+        if (arguments) {
+            std::vector<llvm::Value*> ctorargs;
+            ctorargs.push_back(e->mem);
+            for (size_t i=0; i<arguments->dim; ++i)
+            {
+                Expression* ex = (Expression*)arguments->data[i];
+                Logger::println("arg=%s", ex->toChars());
+                elem* exe = ex->toElem(p);
+                assert(exe->getValue());
+                ctorargs.push_back(exe->getValue());
+                delete exe;
+            }
+            assert(member);
+            assert(member->llvmValue);
+            new llvm::CallInst(member->llvmValue, ctorargs.begin(), ctorargs.end(), "", p->scopebb());
+        }
+    }
+    else if (newtype->ty == Tstruct) {
+        TypeStruct* ts = (TypeStruct*)newtype;
+        if (ts->isZeroInit()) {
+            LLVM_DtoStructZeroInit(ts,e->mem);
+        }
+        else {
+            LLVM_DtoStructCopy(ts,e->mem,ts->llvmInit);
+        }
+    }
+
+    e->inplace = true;
+    e->type = elem::VAR;
+    
+    return e;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem* DeleteExp::toElem(IRState* p)
+{
+    Logger::print("DeleteExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    //assert(e1->type->ty != Tclass);
+
+    elem* v = e1->toElem(p);
+    llvm::Value* val = v->getValue();
+    llvm::Value* ldval = 0;
+
+    const llvm::Type* t = val->getType();
+    llvm::Constant* z = llvm::Constant::getNullValue(t);
+
+    if (e1->type->ty == Tpointer) {
+        ldval = v->getValue();
+        new llvm::FreeInst(ldval, p->scopebb());
+
+        Logger::cout() << *z << '\n';
+        Logger::cout() << *val << '\n';
+        new llvm::StoreInst(z, v->mem, p->scopebb());
+    }
+    else if (e1->type->ty == Tclass) {
+        TypeClass* tc = (TypeClass*)e1->type;
+        LLVM_DtoCallClassDtors(tc, val);
+
+        if (v->vardecl && !v->vardecl->onstack) {
+            new llvm::FreeInst(val, p->scopebb());
+        }
+        new llvm::StoreInst(z, v->mem, p->scopebb());
+    }
+    else if (e1->type->ty == Tarray) {
+        // must be on the heap (correct?)
+        ldval = v->getValue();
+        
+        llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
+        llvm::Value* one = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1, false);
+        
+        llvm::Value* ptr = new llvm::GetElementPtrInst(ldval,zero,one,"tmp",p->scopebb());
+        ptr = new llvm::LoadInst(ptr,"tmp",p->scopebb());
+        new llvm::FreeInst(ptr, p->scopebb());
+        LLVM_DtoNullArray(val);
+    }
+    else {
+        assert(0);
+    }
+
+    delete v;
+
+    // this expression produces no useful data
+    return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem* ArrayLengthExp::toElem(IRState* p)
+{
+    Logger::print("ArrayLengthExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    elem* e = new elem;
+    elem* u = e1->toElem(p);
+
+    llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
+    llvm::Value* ptr = new llvm::GetElementPtrInst(u->mem,zero,zero,"tmp",p->scopebb());
+    e->val = new llvm::LoadInst(ptr, "tmp", p->scopebb());
+    e->type = elem::VAL;
+
+    delete u;
+
+    return e;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem* AssertExp::toElem(IRState* p)
+{
+    Logger::print("AssertExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    elem* e = new elem;
+    elem* u = e1->toElem(p);
+    elem* m = msg ? msg->toElem(p) : 0;
+
+    std::vector<llvm::Value*> llargs;
+    llargs.resize(3);
+    llargs[0] = LLVM_DtoBoolean(u->getValue());
+    llargs[1] = llvm::ConstantInt::get(llvm::Type::Int32Ty, loc.linnum, false);
+    llargs[2] = m ? m->val : llvm::ConstantPointerNull::get(llvm::PointerType::get(llvm::Type::Int8Ty));
+    
+    delete m;
+    delete u;
+    
+    //Logger::cout() << *llargs[0] << '|' << *llargs[1] << '\n';
+    
+    llvm::Function* fn = LLVM_D_GetRuntimeFunction(p->module, "_d_assert");
+    assert(fn);
+    llvm::CallInst* call = new llvm::CallInst(fn, llargs.begin(), llargs.end(), "", p->scopebb());
+    call->setCallingConv(llvm::CallingConv::C);
+
+    return e;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem* NotExp::toElem(IRState* p)
+{
+    Logger::print("NotExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    elem* e = new elem;
+    elem* u = e1->toElem(p);
+
+    llvm::Value* b = LLVM_DtoBoolean(u->getValue());
+
+    llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int1Ty, 0, true);
+    e->val = new llvm::ICmpInst(llvm::ICmpInst::ICMP_EQ,b,zero,"tmp",p->scopebb());
+    e->type = elem::VAL;
+
+    delete u;
+
+    return e;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem* AndAndExp::toElem(IRState* p)
+{
+    Logger::print("AndAndExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    // allocate a temporary for the final result. failed to come up with a better way :/
+    llvm::Value* resval = 0;
+    llvm::BasicBlock* entryblock = &p->topfunc()->front();
+    resval = new llvm::AllocaInst(llvm::Type::Int1Ty,"andandtmp",p->topallocapoint());
+    
+    elem* e = new elem;
+    elem* u = e1->toElem(p);
+
+    llvm::BasicBlock* oldend = p->scopeend();
+    llvm::BasicBlock* andand = new llvm::BasicBlock("andand", gIR->topfunc(), oldend);
+    llvm::BasicBlock* andandend = new llvm::BasicBlock("andandend", gIR->topfunc(), oldend);
+    
+    llvm::Value* ubool = LLVM_DtoBoolean(u->getValue());
+    new llvm::StoreInst(ubool,resval,p->scopebb());
+    new llvm::BranchInst(andand,andandend,ubool,p->scopebb());
+    
+    p->scope() = IRScope(andand, andandend);
+    elem* v = e2->toElem(p);
+
+    llvm::Value* vbool = LLVM_DtoBoolean(v->getValue());
+    llvm::Value* uandvbool = llvm::BinaryOperator::create(llvm::BinaryOperator::And, ubool, vbool,"tmp",p->scopebb());
+    new llvm::StoreInst(uandvbool,resval,p->scopebb());
+    new llvm::BranchInst(andandend,p->scopebb());
+
+    delete u;
+    delete v;
+
+    p->scope() = IRScope(andandend, oldend);
+    
+    e->val = new llvm::LoadInst(resval,"tmp",p->scopebb());
+    e->type = elem::VAL;
+
+    return e;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem* OrOrExp::toElem(IRState* p)
+{
+    Logger::print("OrOrExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    // allocate a temporary for the final result. failed to come up with a better way :/
+    llvm::Value* resval = 0;
+    llvm::BasicBlock* entryblock = &p->topfunc()->front();
+    resval = new llvm::AllocaInst(llvm::Type::Int1Ty,"orortmp",p->topallocapoint());
+    
+    elem* e = new elem;
+    elem* u = e1->toElem(p);
+
+    llvm::BasicBlock* oldend = p->scopeend();
+    llvm::BasicBlock* oror = new llvm::BasicBlock("oror", gIR->topfunc(), oldend);
+    llvm::BasicBlock* ororend = new llvm::BasicBlock("ororend", gIR->topfunc(), oldend);
+    
+    llvm::Value* ubool = LLVM_DtoBoolean(u->getValue());
+    new llvm::StoreInst(ubool,resval,p->scopebb());
+    new llvm::BranchInst(ororend,oror,ubool,p->scopebb());
+    
+    p->scope() = IRScope(oror, ororend);
+    elem* v = e2->toElem(p);
+
+    llvm::Value* vbool = LLVM_DtoBoolean(v->getValue());
+    new llvm::StoreInst(vbool,resval,p->scopebb());
+    new llvm::BranchInst(ororend,p->scopebb());
+
+    delete u;
+    delete v;
+
+    p->scope() = IRScope(ororend, oldend);
+    
+    e->val = new llvm::LoadInst(resval,"tmp",p->scopebb());
+    e->type = elem::VAL;
+
+    return e;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+#define BinBitExp(X,Y) \
+elem* X##Exp::toElem(IRState* p) \
+{ \
+    Logger::print("%sExp::toElem: %s | %s\n", #X, toChars(), type->toChars()); \
+    LOG_SCOPE; \
+    elem* e = new elem; \
+    elem* u = e1->toElem(p); \
+    elem* v = e2->toElem(p); \
+    e->val = llvm::BinaryOperator::create(llvm::Instruction::Y, u->getValue(), v->getValue(), "tmp", p->scopebb()); \
+    e->type = elem::VAL; \
+    delete u; \
+    delete v; \
+    return e; \
+} \
+\
+elem* X##AssignExp::toElem(IRState* p) \
+{ \
+    Logger::print("%sAssignExp::toElem: %s | %s\n", #X, toChars(), type->toChars()); \
+    LOG_SCOPE; \
+    elem* u = e1->toElem(p); \
+    elem* v = e2->toElem(p); \
+    llvm::Value* tmp = llvm::BinaryOperator::create(llvm::Instruction::Y, u->getValue(), v->getValue(), "tmp", p->scopebb()); \
+    Logger::cout() << *tmp << '|' << *u->mem << '\n'; \
+    new llvm::StoreInst(LLVM_DtoPointedType(u->mem, tmp), u->mem, p->scopebb()); \
+    delete u; \
+    delete v; \
+    elem* e = new elem; \
+    e->mem = u->mem; \
+    e->type = elem::VAR; \
+    return e; \
+}
+
+BinBitExp(And,And);
+BinBitExp(Or,Or);
+BinBitExp(Xor,Xor);
+BinBitExp(Shl,Shl);
+BinBitExp(Shr,AShr);
+BinBitExp(Ushr,LShr);
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem* HaltExp::toElem(IRState* p)
+{
+    Logger::print("HaltExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    std::vector<llvm::Value*> llargs;
+    llargs.resize(3);
+    llargs[0] = llvm::ConstantInt::get(llvm::Type::Int1Ty, 0, false);
+    llargs[1] = llvm::ConstantInt::get(llvm::Type::Int32Ty, loc.linnum, false);
+    llargs[2] = llvm::ConstantPointerNull::get(llvm::PointerType::get(llvm::Type::Int8Ty));
+    
+    //Logger::cout() << *llargs[0] << '|' << *llargs[1] << '\n';
+    
+    llvm::Function* fn = LLVM_D_GetRuntimeFunction(p->module, "_d_assert");
+    assert(fn);
+    llvm::CallInst* call = new llvm::CallInst(fn, llargs.begin(), llargs.end(), "", p->scopebb());
+    call->setCallingConv(llvm::CallingConv::C);
+    
+    //new llvm::UnreachableInst(p->scopebb());
+
+    return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem* DelegateExp::toElem(IRState* p)
+{
+    Logger::print("DelegateExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    elem* e = new elem;
+    elem* u = e1->toElem(p);
+    
+    llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
+    llvm::Value* one = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1, false);
+    
+    const llvm::Type* int8ptrty = llvm::PointerType::get(llvm::Type::Int8Ty);
+
+    llvm::Value* lval = p->toplval();
+
+    llvm::Value* context = new llvm::GetElementPtrInst(lval,zero,zero,"tmp",p->scopebb());
+    llvm::Value* castcontext = new llvm::BitCastInst(u->getValue(),int8ptrty,"tmp",p->scopebb());
+    new llvm::StoreInst(castcontext, context, p->scopebb());
+    
+    llvm::Value* fptr = new llvm::GetElementPtrInst(lval,zero,one,"tmp",p->scopebb());
+    
+    assert(func->llvmValue);
+    llvm::Value* castfptr = new llvm::BitCastInst(func->llvmValue,fptr->getType()->getContainedType(0),"tmp",p->scopebb());
+    new llvm::StoreInst(castfptr, fptr, p->scopebb());
+    
+    e->inplace = true;
+    
+    delete u;
+    return e;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem* IdentityExp::toElem(IRState* p)
+{
+    Logger::print("IdentityExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    elem* u = e1->toElem(p);
+    elem* v = e2->toElem(p);
+
+    elem* e = new elem;
+
+    llvm::Value* l = u->getValue();
+    llvm::Value* r = 0;
+    if (v->type == elem::NUL)
+    r = llvm::ConstantPointerNull::get(llvm::cast<llvm::PointerType>(l->getType()));
+    else
+    r = v->getValue();
+
+    llvm::ICmpInst::Predicate pred = (op == TOKidentity) ? llvm::ICmpInst::ICMP_EQ : llvm::ICmpInst::ICMP_NE;
+    e->val = new llvm::ICmpInst(pred, l, r, "tmp", p->scopebb());
+    e->type = elem::VAL;
+
+    delete u;
+    delete v;
+
+    return e;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem* CommaExp::toElem(IRState* p)
+{
+    Logger::print("CommaExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    elem* u = e1->toElem(p);
+    elem* v = e2->toElem(p);
+    delete u;
+    return v;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem* CondExp::toElem(IRState* p)
+{
+    Logger::print("CondExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    const llvm::Type* resty = LLVM_DtoType(type);
+
+    // allocate a temporary for the final result. failed to come up with a better way :/
+    llvm::BasicBlock* entryblock = &p->topfunc()->front();
+    llvm::Value* resval = new llvm::AllocaInst(resty,"condtmp",p->topallocapoint());
+
+    llvm::BasicBlock* oldend = p->scopeend();
+    llvm::BasicBlock* condtrue = new llvm::BasicBlock("condtrue", gIR->topfunc(), oldend);
+    llvm::BasicBlock* condfalse = new llvm::BasicBlock("condfalse", gIR->topfunc(), oldend);
+    llvm::BasicBlock* condend = new llvm::BasicBlock("condend", gIR->topfunc(), oldend);
+
+    elem* c = econd->toElem(p);
+    llvm::Value* cond_val = LLVM_DtoBoolean(c->getValue());
+    delete c;
+    new llvm::BranchInst(condtrue,condfalse,cond_val,p->scopebb());
+
+    p->scope() = IRScope(condtrue, condfalse);
+    elem* u = e1->toElem(p);
+    Logger::cout() << *u->val << '|' << *resval << '\n'; \
+    new llvm::StoreInst(u->getValue(),resval,p->scopebb());
+    new llvm::BranchInst(condend,p->scopebb());
+    delete u;
+
+    p->scope() = IRScope(condfalse, condend);
+    elem* v = e2->toElem(p);
+    new llvm::StoreInst(v->getValue(),resval,p->scopebb());
+    new llvm::BranchInst(condend,p->scopebb());
+    delete v;
+
+    p->scope() = IRScope(condend, oldend);
+
+    elem* e = new elem;
+    e->val = new llvm::LoadInst(resval,"tmp",p->scopebb());
+    e->type = elem::VAL;
+    return e;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+elem* ComExp::toElem(IRState* p)
+{
+    Logger::print("ComExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    elem* e = new elem;
+    elem* u = e1->toElem(p);
+
+    llvm::Value* value = u->getValue();
+    llvm::Value* minusone = llvm::ConstantInt::get(value->getType(), -1, true);
+    e->val = llvm::BinaryOperator::create(llvm::Instruction::Xor, value, minusone, "tmp", p->scopebb());
+
+    delete u;
+
+    e->type = elem::VAL;
+
+    return e;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+#define STUB(x) elem *x::toElem(IRState * p) {error("Exp type "#x" not implemented: %s", toChars()); fatal(); return 0; }
+//STUB(IdentityExp);
+//STUB(CondExp);
+//STUB(EqualExp);
+STUB(InExp);
+//STUB(CmpExp);
+//STUB(AndAndExp);
+//STUB(OrOrExp);
+//STUB(AndExp);
+//STUB(AndAssignExp);
+//STUB(OrExp);
+//STUB(OrAssignExp);
+//STUB(XorExp);
+//STUB(XorAssignExp);
+//STUB(ShrExp);
+//STUB(ShrAssignExp);
+//STUB(ShlExp);
+//STUB(ShlAssignExp);
+//STUB(UshrExp);
+//STUB(UshrAssignExp);
+//STUB(DivExp);
+//STUB(DivAssignExp);
+//STUB(MulExp);
+//STUB(MulAssignExp);
+//STUB(ModExp);
+//STUB(ModAssignExp);
+STUB(CatExp);
+STUB(CatAssignExp);
+//STUB(AddExp);
+//STUB(AddAssignExp);
+STUB(Expression);
+//STUB(MinExp);
+//STUB(MinAssignExp);
+//STUB(PostExp);
+//STUB(NullExp);
+//STUB(ThisExp);
+//STUB(CallExp);
+STUB(DotTypeExp);
+STUB(TypeDotIdExp);
+//STUB(DotVarExp);
+//STUB(AssertExp);
+STUB(FuncExp);
+//STUB(DelegateExp);
+//STUB(VarExp);
+//STUB(DeclarationExp);
+//STUB(NewExp);
+//STUB(SymOffExp);
+STUB(ScopeExp);
+//STUB(AssignExp);
+
+STUB(TypeExp);
+//STUB(RealExp);
+STUB(ComplexExp);
+//STUB(StringExp);
+//STUB(IntegerExp);
+STUB(BoolExp);
+
+//STUB(NotExp);
+//STUB(ComExp);
+STUB(NegExp);
+//STUB(PtrExp);
+//STUB(AddrExp);
+//STUB(SliceExp);
+//STUB(CastExp);
+//STUB(DeleteExp);
+//STUB(IndexExp);
+//STUB(CommaExp);
+//STUB(ArrayLengthExp);
+//STUB(HaltExp);
+STUB(RemoveExp);
+STUB(ArrayLiteralExp);
+STUB(AssocArrayLiteralExp);
+//STUB(StructLiteralExp);
+
+unsigned Type::totym() { return 0; }
+
+type *
+Type::toCtype() {
+    return 0;
+}
+
+type * Type::toCParamtype()
+{
+    return 0;
+}
+Symbol * Type::toSymbol()
+{
+    return 0;
+}
+
+type *
+TypeTypedef::toCtype()
+{
+    return 0;
+}
+
+type *
+TypeTypedef::toCParamtype()
+{
+    return 0;
+}
+
+void
+TypedefDeclaration::toDebug()
+{
+}
+
+
+type *
+TypeEnum::toCtype()
+{
+    return 0;
+}
+
+type *
+TypeStruct::toCtype()
+{
+    return 0;
+}
+
+void
+StructDeclaration::toDebug()
+{
+}
+
+Symbol * TypeClass::toSymbol()
+{
+    return 0;
+}
+
+unsigned TypeFunction::totym()
+{
+    return 0;
+}
+
+type *
+TypeFunction::toCtype()
+{
+    return 0;
+}
+
+type *
+TypeSArray::toCtype()
+{
+    return 0;
+}
+
+type *TypeSArray::toCParamtype() { return 0; }
+
+type *
+TypeDArray::toCtype()
+{
+    return 0;
+}
+
+type *
+TypeAArray::toCtype()
+{
+    return 0;
+}
+
+type *
+TypePointer::toCtype()
+{
+    return 0;
+}
+
+type *
+TypeDelegate::toCtype()
+{
+    return 0;
+}
+
+type *
+TypeClass::toCtype()
+{
+    return 0;
+}
+
+void
+ClassDeclaration::toDebug()
+{
+}
+
+/* --------------------------------------------------------------------------------------- */
+
+void CompoundStatement::toIR(IRState* p)
+{
+    static int csi = 0;
+    Logger::println("CompoundStatement::toIR(%d):\n<<<\n%s>>>", csi++, toChars());
+    LOG_SCOPE;
+
+    /*
+    const char* labelname;
+    bool insterm = false;
+
+    if (!p->scopes()) {
+        labelname = "bb";
+        insterm = true;
+    }
+    else
+        labelname = "entry";
+
+    //if (!llvm::isa<llvm::TerminatorInst>(p->topfunc()->back().back()))
+    //    insterm = true;
+
+    llvm::BasicBlock* bb = new llvm::BasicBlock(labelname, p->topfunc());
+
+    if (insterm) {
+        new llvm::BranchInst(bb,p->topbb());
+    }
+
+    p->bbs.push(bb);
+    */
+
+    size_t n = statements->dim;
+    for (size_t i=0; i<n; i++)
+    {
+        Statement* s = (Statement*)statements->data[i];
+        if (s)
+        s->toIR(p);
+        else
+        Logger::println("NULL statement found in CompoundStatement !! :S");
+    }
+
+    //p->bbs.pop();
+}
+
+void ReturnStatement::toIR(IRState* p)
+{
+    static int rsi = 0;
+    Logger::println("ReturnStatement::toIR(%d): %s", rsi++, toChars());
+    LOG_SCOPE;
+
+    if (exp)
+    {
+        TY expty = exp->type->ty;
+        if (p->topfunc()->getReturnType() == llvm::Type::VoidTy) {
+            assert(expty == Tstruct || expty == Tdelegate || expty == Tarray);
+
+            TypeFunction* f = p->topfunctype();
+            assert(f->llvmRetInPtr && f->llvmRetArg);
+
+            p->lvals.push_back(f->llvmRetArg);
+            elem* e = exp->toElem(p);
+            p->lvals.pop_back();
+
+            // structliterals do this themselves
+            // also they dont produce any value
+            if (expty == Tstruct) {
+                if (!e->inplace) {
+                    TypeStruct* ts = (TypeStruct*)exp->type;
+                    assert(e->mem);
+                    LLVM_DtoStructCopy(ts,f->llvmRetArg,e->mem);
+                }
+            }
+            else if (expty == Tdelegate) {
+                // do nothing, handled by the DelegateExp
+                LLVM_DtoDelegateCopy(f->llvmRetArg,e->mem);
+            }
+            else if (expty == Tarray) {
+                if (e->type == elem::SLICE) {
+                    LLVM_DtoSetArray(f->llvmRetArg,e->arg,e->mem);
+                }
+                // else the return value is a variable and should already have been assigned by now
+            }
+            else
+            assert(0);
+
+            new llvm::ReturnInst(p->scopebb());
+            delete e;
+        }
+        else {
+            elem* e = exp->toElem(p);
+            llvm::Value* v = e->getValue();
+            Logger::cout() << *v << '\n';
+            new llvm::ReturnInst(v, p->scopebb());
+            delete e;
+        }
+    }
+    else
+    {
+        if (p->topfunc()->getReturnType() == llvm::Type::VoidTy)
+            new llvm::ReturnInst(p->scopebb());
+        else
+            new llvm::UnreachableInst(p->scopebb());
+    }
+
+    p->scope().returned = true;
+}
+
+void ExpStatement::toIR(IRState* p)
+{
+    static int esi = 0;
+    Logger::println("ExpStatement::toIR(%d): %s", esi++, toChars());
+    LOG_SCOPE;
+
+    if (exp != 0) {
+        elem* e = exp->toElem(p);
+        delete e;
+    }
+    /*elem* e = exp->toElem(p);
+    p->buf.printf("%s", e->toChars());
+    delete e;
+    p->buf.writenl();*/
+}
+
+void IfStatement::toIR(IRState* p)
+{
+    static int wsi = 0;
+    Logger::println("IfStatement::toIR(%d): %s", wsi++, toChars());
+    LOG_SCOPE;
+
+    elem* cond_e = condition->toElem(p);
+    llvm::Value* cond_val = cond_e->getValue();
+    delete cond_e;
+
+    llvm::BasicBlock* oldend = gIR->scopeend();
+
+    llvm::BasicBlock* ifbb = new llvm::BasicBlock("if", gIR->topfunc(), oldend);
+    llvm::BasicBlock* endbb = new llvm::BasicBlock("endif", gIR->topfunc(), oldend);
+    llvm::BasicBlock* elsebb = 0;
+    if (elsebody) {
+        elsebb = new llvm::BasicBlock("else", gIR->topfunc(), endbb);
+    }
+    else {
+        elsebb = endbb;
+    }
+
+    if (cond_val->getType() != llvm::Type::Int1Ty) {
+        Logger::cout() << "if conditional: " << *cond_val << '\n';
+        cond_val = LLVM_DtoBoolean(cond_val);
+    }
+    llvm::Value* ifgoback = new llvm::BranchInst(ifbb, elsebb, cond_val, gIR->scopebegin());
+
+    // replace current scope
+    gIR->scope() = IRScope(ifbb,elsebb);
+
+    bool endifUsed = false;
+
+    // do scoped statements
+    ifbody->toIR(p);
+    if (!gIR->scopereturned()) {
+        new llvm::BranchInst(endbb,gIR->scopebegin());
+        endifUsed = true;
+    }
+
+    if (elsebody) {
+        //assert(0);
+        gIR->scope() = IRScope(elsebb,endbb);
+        elsebody->toIR(p);
+        if (!gIR->scopereturned()) {
+            new llvm::BranchInst(endbb,gIR->scopebegin());
+            endifUsed = true;
+        }
+    }
+
+    // rewrite the scope
+    gIR->scope() = IRScope(endbb,oldend);
+}
+
+void ScopeStatement::toIR(IRState* p)
+{
+    static int wsi = 0;
+    Logger::println("ScopeStatement::toIR(%d): %s", wsi++, toChars());
+    LOG_SCOPE;
+
+    llvm::BasicBlock* oldend = gIR->scopeend();
+
+    IRScope irs;
+    irs.begin = new llvm::BasicBlock("scope", gIR->topfunc(), oldend);
+    irs.end = new llvm::BasicBlock("endscope", gIR->topfunc(), oldend);
+
+    // pass the previous BB into this
+    new llvm::BranchInst(irs.begin, gIR->scopebegin());
+
+    gIR->scope() = irs;
+
+    statement->toIR(p);
+    if (!gIR->scopereturned()) {
+        new llvm::BranchInst(irs.end, gIR->scopebegin());
+    }
+
+    // rewrite the scope
+    gIR->scope() = IRScope(irs.end,oldend);
+}
+
+void WhileStatement::toIR(IRState* p)
+{
+    static int wsi = 0;
+    Logger::println("WhileStatement::toIR(%d): %s", wsi++, toChars());
+    LOG_SCOPE;
+
+    // create while blocks
+    llvm::BasicBlock* oldend = gIR->scopeend();
+    llvm::BasicBlock* whilebb = new llvm::BasicBlock("whilecond", gIR->topfunc(), oldend);
+    llvm::BasicBlock* endbb = new llvm::BasicBlock("endwhile", gIR->topfunc(), oldend);
+
+    // move into the while block
+    new llvm::BranchInst(whilebb, gIR->scopebegin());
+
+    // replace current scope
+    gIR->scope() = IRScope(whilebb,endbb);
+
+    // create the condition
+    elem* cond_e = condition->toElem(p);
+    llvm::Value* cond_val = LLVM_DtoBoolean(cond_e->getValue());
+    delete cond_e;
+
+    // while body block
+    llvm::BasicBlock* whilebodybb = new llvm::BasicBlock("whilebody", gIR->topfunc(), endbb);
+
+    // conditional branch
+    llvm::Value* ifbreak = new llvm::BranchInst(whilebodybb, endbb, cond_val, whilebb);
+
+    // rewrite scope
+    gIR->scope() = IRScope(whilebodybb,endbb);
+
+    // do while body code
+    body->toIR(p);
+
+    // loop
+    new llvm::BranchInst(whilebb, gIR->scopebegin());
+
+    // rewrite the scope
+    gIR->scope() = IRScope(endbb,oldend);
+}
+
+void DoStatement::toIR(IRState* p)
+{
+    static int wsi = 0;
+    Logger::println("DoStatement::toIR(%d): %s", wsi++, toChars());
+    LOG_SCOPE;
+
+    // create while blocks
+    llvm::BasicBlock* oldend = gIR->scopeend();
+    llvm::BasicBlock* dowhilebb = new llvm::BasicBlock("dowhile", gIR->topfunc(), oldend);
+    llvm::BasicBlock* endbb = new llvm::BasicBlock("enddowhile", gIR->topfunc(), oldend);
+
+    // move into the while block
+    new llvm::BranchInst(dowhilebb, gIR->scopebegin());
+
+    // replace current scope
+    gIR->scope() = IRScope(dowhilebb,endbb);
+
+    // do do-while body code
+    body->toIR(p);
+
+    // create the condition
+    elem* cond_e = condition->toElem(p);
+    llvm::Value* cond_val = LLVM_DtoBoolean(cond_e->getValue());
+    delete cond_e;
+
+    // conditional branch
+    llvm::Value* ifbreak = new llvm::BranchInst(dowhilebb, endbb, cond_val, gIR->scopebegin());
+
+    // rewrite the scope
+    gIR->scope() = IRScope(endbb,oldend);
+}
+
+void ForStatement::toIR(IRState* p)
+{
+    static int wsi = 0;
+    Logger::println("ForStatement::toIR(%d): %s", wsi++, toChars());
+    LOG_SCOPE;
+
+    // create for blocks
+    llvm::BasicBlock* oldend = gIR->scopeend();
+    llvm::BasicBlock* forbb = new llvm::BasicBlock("forcond", gIR->topfunc(), oldend);
+    llvm::BasicBlock* forbodybb = new llvm::BasicBlock("forbody", gIR->topfunc(), oldend);
+    llvm::BasicBlock* forincbb = new llvm::BasicBlock("forinc", gIR->topfunc(), oldend);
+    llvm::BasicBlock* endbb = new llvm::BasicBlock("endfor", gIR->topfunc(), oldend);
+
+    // init
+    if (init != 0)
+    init->toIR(p);
+
+    // move into the for condition block, ie. start the loop
+    new llvm::BranchInst(forbb, gIR->scopebegin());
+
+    IRScope loop;
+    loop.begin = forincbb;
+    loop.end = endbb;
+    p->loopbbs.push_back(loop);
+
+    // replace current scope
+    gIR->scope() = IRScope(forbb,forbodybb);
+
+    // create the condition
+    elem* cond_e = condition->toElem(p);
+    llvm::Value* cond_val = LLVM_DtoBoolean(cond_e->getValue());
+    delete cond_e;
+
+    // conditional branch
+    llvm::Value* ifbreak = new llvm::BranchInst(forbodybb, endbb, cond_val, forbb);
+
+    // rewrite scope
+    gIR->scope() = IRScope(forbodybb,forincbb);
+
+    // do for body code
+    body->toIR(p);
+
+    // move into the for increment block
+    new llvm::BranchInst(forincbb, gIR->scopebegin());
+    gIR->scope() = IRScope(forincbb, endbb);
+
+    // increment
+    if (increment) {
+        elem* inc = increment->toElem(p);
+        delete inc;
+    }
+
+    // loop
+    new llvm::BranchInst(forbb, gIR->scopebegin());
+
+    p->loopbbs.pop_back();
+
+    // rewrite the scope
+    gIR->scope() = IRScope(endbb,oldend);
+}
+
+void BreakStatement::toIR(IRState* p)
+{
+    static int wsi = 0;
+    Logger::println("BreakStatement::toIR(%d): %s", wsi++, toChars());
+    LOG_SCOPE;
+
+    if (ident != 0) {
+        Logger::println("ident = %s", ident->toChars());
+        assert(0);
+    }
+    else {
+        new llvm::BranchInst(gIR->loopbbs.back().end, gIR->scopebegin());
+    }
+}
+
+void ContinueStatement::toIR(IRState* p)
+{
+    static int wsi = 0;
+    Logger::println("ContinueStatement::toIR(%d): %s", wsi++, toChars());
+    LOG_SCOPE;
+
+    if (ident != 0) {
+        Logger::println("ident = %s", ident->toChars());
+        assert(0);
+    }
+    else {
+        new llvm::BranchInst(gIR->loopbbs.back().begin, gIR->scopebegin());
+    }
+}
+
+void OnScopeStatement::toIR(IRState* p)
+{
+    static int wsi = 0;
+    Logger::println("OnScopeStatement::toIR(%d): %s", wsi++, toChars());
+    LOG_SCOPE;
+
+    assert(statement);
+    //statement->toIR(p); // this seems to be redundant
+}
+
+void TryFinallyStatement::toIR(IRState* p)
+{
+    static int wsi = 0;
+    Logger::println("TryFinallyStatement::toIR(%d): %s", wsi++, toChars());
+    LOG_SCOPE;
+
+    llvm::BasicBlock* oldend = gIR->scopeend();
+
+    llvm::BasicBlock* trybb = new llvm::BasicBlock("try", gIR->topfunc(), oldend);
+    llvm::BasicBlock* finallybb = new llvm::BasicBlock("finally", gIR->topfunc(), oldend);
+    llvm::BasicBlock* endbb = new llvm::BasicBlock("endtryfinally", gIR->topfunc(), oldend);
+
+    // pass the previous BB into this
+    new llvm::BranchInst(trybb, gIR->scopebegin());
+
+    gIR->scope() = IRScope(trybb,finallybb);
+
+    assert(body);
+    body->toIR(p);
+    new llvm::BranchInst(finallybb, gIR->scopebegin());
+
+    // rewrite the scope
+    gIR->scope() = IRScope(finallybb,endbb);
+
+    assert(finalbody);
+    finalbody->toIR(p);
+    new llvm::BranchInst(endbb, gIR->scopebegin());
+
+    // rewrite the scope
+    gIR->scope() = IRScope(endbb,oldend);
+}
+
+void TryCatchStatement::toIR(IRState* p)
+{
+    static int wsi = 0;
+    Logger::println("TryCatchStatement::toIR(%d): %s", wsi++, toChars());
+    LOG_SCOPE;
+
+    assert(0 && "try-catch is not properly");
+
+    assert(body);
+    body->toIR(p);
+
+    assert(catches);
+    for(size_t i=0; i<catches->dim; ++i)
+    {
+        Catch* c = (Catch*)catches->data[i];
+        c->handler->toIR(p);
+    }
+}
+
+void ThrowStatement::toIR(IRState* p)
+{
+    static int wsi = 0;
+    Logger::println("ThrowStatement::toIR(%d): %s", wsi++, toChars());
+    LOG_SCOPE;
+
+    assert(0 && "throw is not implemented");
+
+    assert(exp);
+    elem* e = exp->toElem(p);
+    delete e;
+}
+
+#define STUBST(x) void x::toIR(IRState * p) {error("Statement type "#x" not implemented: %s", toChars());fatal();}
+//STUBST(BreakStatement);
+//STUBST(ForStatement);
+STUBST(WithStatement);
+STUBST(SynchronizedStatement);
+//STUBST(ReturnStatement);
+//STUBST(ContinueStatement);
+STUBST(DefaultStatement);
+STUBST(CaseStatement);
+STUBST(SwitchStatement);
+STUBST(SwitchErrorStatement);
+STUBST(Statement);
+//STUBST(IfStatement);
+STUBST(ForeachStatement);
+//STUBST(DoStatement);
+//STUBST(WhileStatement);
+//STUBST(ExpStatement);
+//STUBST(CompoundStatement);
+//STUBST(ScopeStatement);
+STUBST(AsmStatement);
+//STUBST(TryCatchStatement);
+//STUBST(TryFinallyStatement);
+STUBST(VolatileStatement);
+STUBST(LabelStatement);
+//STUBST(ThrowStatement);
+STUBST(GotoCaseStatement);
+STUBST(GotoDefaultStatement);
+STUBST(GotoStatement);
+STUBST(UnrolledLoopStatement);
+//STUBST(OnScopeStatement);
+
+
+void
+EnumDeclaration::toDebug()
+{
+
+}
+
+int
+Dsymbol::cvMember(unsigned char*)
+{
+    return 0;
+}
+int
+EnumDeclaration::cvMember(unsigned char*)
+{
+    return 0;
+}
+int
+FuncDeclaration::cvMember(unsigned char*)
+{
+    return 0;
+}
+int
+VarDeclaration::cvMember(unsigned char*)
+{
+    return 0;
+}
+int
+TypedefDeclaration::cvMember(unsigned char*)
+{
+    return 0;
+}
+
+void obj_includelib(char*){}
+
+AsmStatement::AsmStatement(Loc loc, Token *tokens) :
+    Statement(loc)
+{
+}
+Statement *AsmStatement::syntaxCopy() {
+    return 0;
+}
+
+Statement *AsmStatement::semantic(Scope *sc)
+{
+    return Statement::semantic(sc);
+}
+
+
+void AsmStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    Statement::toCBuffer(buf, hgs);
+}
+
+int AsmStatement::comeFrom()
+{
+    return FALSE;
+}
+
+void
+backend_init()
+{
+    //LLVM_D_InitRuntime();
+    // lazily loaded
+}
+
+void
+backend_term()
+{
+    LLVM_D_FreeRuntime();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen/tollvm.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,1089 @@
+#include <iostream>
+
+#include "llvm/Constants.h"
+#include "llvm/Type.h"
+#include "llvm/DerivedTypes.h"
+#include "llvm/GlobalValue.h"
+#include "llvm/Instructions.h"
+#include "llvm/CallingConv.h"
+
+#include "mtype.h"
+#include "dsymbol.h"
+#include "aggregate.h"
+#include "declaration.h"
+#include "init.h"
+
+#include "tollvm.h"
+#include "irstate.h"
+#include "logger.h"
+#include "runtime.h"
+#include "elem.h"
+
+const llvm::Type* LLVM_DtoType(Type* t)
+{
+    assert(t);
+    switch (t->ty)
+    {
+    // integers
+    case Tint8:
+    case Tuns8:
+    case Tchar:
+        return (const llvm::Type*)llvm::Type::Int8Ty;
+    case Tint16:
+    case Tuns16:
+    case Twchar:
+        return (const llvm::Type*)llvm::Type::Int16Ty;
+    case Tint32:
+    case Tuns32:
+    case Tdchar:
+        return (const llvm::Type*)llvm::Type::Int32Ty;
+    case Tint64:
+    case Tuns64:
+        return (const llvm::Type*)llvm::Type::Int64Ty;
+
+    case Tbool:
+        return (const llvm::Type*)llvm::ConstantInt::getTrue()->getType();
+
+    // floats
+    case Tfloat32:
+        return llvm::Type::FloatTy;
+    case Tfloat64:
+    case Tfloat80:
+        return llvm::Type::DoubleTy;
+
+    // pointers
+    case Tpointer: {
+        assert(t->next);
+        if (t->next->ty == Tvoid)
+            return (const llvm::Type*)llvm::PointerType::get(llvm::Type::Int8Ty);
+        else
+            return (const llvm::Type*)llvm::PointerType::get(LLVM_DtoType(t->next));
+    }
+
+    // arrays
+    case Tarray:
+        return LLVM_DtoArrayType(t);
+    case Tsarray:
+        return LLVM_DtoStaticArrayType(t);
+
+    // void
+    case Tvoid:
+        return llvm::Type::VoidTy;
+
+    // aggregates
+    case Tstruct:    {
+        if (t->llvmType == 0)
+        {
+            // recursive or cyclic declaration
+            if (!gIR->structs.empty())
+            {
+                IRStruct* found = 0;
+                for (IRState::StructVector::iterator i=gIR->structs.begin(); i!=gIR->structs.end(); ++i)
+                {
+                    if (t == i->type)
+                    {
+                        return i->recty.get();
+                    }
+                }
+            }
+
+            // forward declaration
+            TypeStruct* ts = (TypeStruct*)t;
+            assert(ts->sym);
+            ts->sym->toObjFile();
+        }
+        return t->llvmType;
+    }
+
+    case Tclass:    {
+        if (t->llvmType == 0)
+        {
+            TypeClass* tc = (TypeClass*)t;
+            assert(tc->sym);
+            if (!tc->sym->llvmInProgress) {
+                tc->sym->toObjFile();
+            }
+            else {
+                //assert(0 && "circular class referencing");
+                return llvm::OpaqueType::get();
+            }
+        }
+        return llvm::PointerType::get(t->llvmType);
+    }
+
+    // functions
+    case Tfunction:
+    {
+        if (t->llvmType == 0) {
+            return LLVM_DtoFunctionType(t);
+        }
+        else {
+            return t->llvmType;
+        }
+    }
+    
+    // delegates
+    case Tdelegate:
+    {
+        if (t->llvmType == 0) {
+            return LLVM_DtoDelegateType(t);
+        }
+        else {
+            return t->llvmType;
+        }
+    }
+
+    // typedefs
+    case Ttypedef:
+    {
+        Type* bt = t->toBasetype();
+        assert(bt);
+        return LLVM_DtoType(bt);
+    }
+
+    default:
+        printf("trying to convert unknown type with value %d\n", t->ty);
+        assert(0);
+    }
+    return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::FunctionType* LLVM_DtoFunctionType(Type* t, const llvm::Type* thisparam)
+{
+    TypeFunction* f = (TypeFunction*)t;
+
+    // parameter types
+    const llvm::Type* rettype;
+    std::vector<const llvm::Type*> paramvec;
+
+    TY retty = f->next->ty;
+
+    if (retty == Tstruct || retty == Tdelegate || retty == Tarray) {
+        rettype = llvm::PointerType::get(LLVM_DtoType(f->next));
+        paramvec.push_back(rettype);
+        rettype = llvm::Type::VoidTy;
+    }
+    else {
+        Type* rt = f->next;
+        if (rt)
+        rettype = LLVM_DtoType(rt);
+        else
+        assert(0);
+    }
+
+    if (thisparam) {
+        paramvec.push_back(thisparam);
+    }
+
+    size_t n = Argument::dim(f->parameters);
+    for (int i=0; i < n; ++i) {
+        Argument* arg = Argument::getNth(f->parameters, i);
+        // ensure scalar
+        Type* argT = arg->type;
+        assert(argT);
+        paramvec.push_back(LLVM_DtoType(argT));
+    }
+
+    Logger::cout() << "Return type: " << *rettype << '\n';
+
+    llvm::FunctionType* functype = llvm::FunctionType::get(rettype, paramvec, f->varargs);
+    return functype;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::FunctionType* LLVM_DtoFunctionType(FuncDeclaration* fdecl)
+{
+    TypeFunction* f = (TypeFunction*)fdecl->type;
+    assert(f != 0);
+
+    // has already been pulled in by a reference to (
+    if (f->llvmType != 0) {
+        return llvm::cast<llvm::FunctionType>(f->llvmType);
+    }
+
+    // return value type
+    const llvm::Type* rettype;
+    const llvm::Type* actualRettype;
+    Type* rt = f->next;
+    bool retinptr = false;
+    bool usesthis = false;
+
+    if (fdecl->isMain()) {
+        rettype = llvm::Type::Int32Ty;
+        actualRettype = rettype;
+    }
+    else if (rt) {
+        if (rt->ty == Tstruct || rt->ty == Tdelegate || rt->ty == Tarray) {
+            rettype = llvm::PointerType::get(LLVM_DtoType(rt));
+            actualRettype = llvm::Type::VoidTy;
+            f->llvmRetInPtr = retinptr = true;
+        }
+        else {
+            rettype = LLVM_DtoType(rt);
+            actualRettype = rettype;
+        }
+    }
+    else {
+        assert(0);
+    }
+
+    // parameter types
+    std::vector<const llvm::Type*> paramvec;
+
+    if (retinptr) {
+        Logger::print("returning through pointer parameter\n");
+        paramvec.push_back(rettype);
+    }
+
+    if (fdecl->needThis() && fdecl->vthis) {
+        Logger::print("this is: %s\n", fdecl->vthis->type->toChars());
+        paramvec.push_back(LLVM_DtoType(fdecl->vthis->type));
+        usesthis = true;
+    }
+
+    size_t n = Argument::dim(f->parameters);
+    for (int i=0; i < n; ++i) {
+        Argument* arg = Argument::getNth(f->parameters, i);
+        // ensure scalar
+        Type* argT = arg->type;
+        assert(argT);
+
+        if ((arg->storageClass & STCref) || (arg->storageClass & STCout)) {
+            //assert(arg->vardecl);
+            //arg->vardecl->refparam = true;
+        }
+        else
+            arg->llvmCopy = true;
+
+        const llvm::Type* at = LLVM_DtoType(argT);
+        if (llvm::isa<llvm::StructType>(at)) {
+            Logger::println("struct param");
+            paramvec.push_back(llvm::PointerType::get(at));
+        }
+        else if (llvm::isa<llvm::ArrayType>(at)) {
+            Logger::println("sarray param");
+            assert(argT->ty == Tsarray);
+            //paramvec.push_back(llvm::PointerType::get(at->getContainedType(0)));
+            paramvec.push_back(llvm::PointerType::get(at));
+        }
+        else {
+            if (!arg->llvmCopy) {
+                Logger::println("ref param");
+                at = llvm::PointerType::get(at);
+            }
+            else {
+                Logger::println("in param");
+            }
+            paramvec.push_back(at);
+        }
+    }
+
+    // construct function type
+    bool isvararg = f->varargs;
+    llvm::FunctionType* functype = llvm::FunctionType::get(actualRettype, paramvec, isvararg);
+
+    f->llvmType = functype;
+    return functype;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::StructType* LLVM_DtoDelegateType(Type* t)
+{
+    const llvm::Type* i8ptr = llvm::PointerType::get(llvm::Type::Int8Ty);
+    const llvm::Type* func = LLVM_DtoFunctionType(t->next, i8ptr);
+    const llvm::Type* funcptr = llvm::PointerType::get(func);
+
+    std::vector<const llvm::Type*> types;
+    types.push_back(i8ptr);
+    types.push_back(funcptr);
+    return llvm::StructType::get(types);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::Type* LLVM_DtoStructType(Type* t)
+{
+    assert(0);
+    std::vector<const llvm::Type*> types;
+    return llvm::StructType::get(types);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::StructType* LLVM_DtoArrayType(Type* t)
+{
+    assert(t->next);
+    const llvm::Type* at = LLVM_DtoType(t->next);
+    const llvm::Type* arrty;
+
+    /*if (t->ty == Tsarray) {
+        TypeSArray* tsa = (TypeSArray*)t;
+        assert(tsa->dim->type->isintegral());
+        arrty = llvm::ArrayType::get(at,tsa->dim->toUInteger());
+    }
+    else {
+        arrty = llvm::ArrayType::get(at,0);
+    }*/
+    if (at == llvm::Type::VoidTy) {
+        at = llvm::Type::Int8Ty;
+    }
+    arrty = llvm::PointerType::get(at);
+
+    std::vector<const llvm::Type*> members;
+    if (global.params.is64bit)
+        members.push_back(llvm::Type::Int64Ty);
+    else
+        members.push_back(llvm::Type::Int32Ty);
+
+    members.push_back(arrty);
+
+    return llvm::StructType::get(members);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::ArrayType* LLVM_DtoStaticArrayType(Type* t)
+{
+    if (t->llvmType)
+        return llvm::cast<llvm::ArrayType>(t->llvmType);
+
+    assert(t->ty == Tsarray);
+    assert(t->next);
+
+    const llvm::Type* at = LLVM_DtoType(t->next);
+
+    TypeSArray* tsa = (TypeSArray*)t;
+    assert(tsa->dim->type->isintegral());
+    llvm::ArrayType* arrty = llvm::ArrayType::get(at,tsa->dim->toUInteger());
+
+    tsa->llvmType = arrty;
+    return arrty;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+static llvm::Function* LLVM_DeclareMemIntrinsic(const char* name, int bits, bool set=false)
+{
+    assert(bits == 32 || bits == 64);
+    const llvm::Type* int8ty =    (const llvm::Type*)llvm::Type::Int8Ty;
+    const llvm::Type* int32ty =   (const llvm::Type*)llvm::Type::Int32Ty;
+    const llvm::Type* int64ty =   (const llvm::Type*)llvm::Type::Int64Ty;
+    const llvm::Type* int8ptrty = (const llvm::Type*)llvm::PointerType::get(llvm::Type::Int8Ty);
+    const llvm::Type* voidty =    (const llvm::Type*)llvm::Type::VoidTy;
+
+    assert(gIR);
+    assert(gIR->module);
+
+    // parameter types
+    std::vector<const llvm::Type*> pvec;
+    pvec.push_back(int8ptrty);
+    pvec.push_back(set?int8ty:int8ptrty);
+    pvec.push_back(bits==32?int32ty:int64ty);
+    pvec.push_back(int32ty);
+    llvm::FunctionType* functype = llvm::FunctionType::get(voidty, pvec, false);
+    return new llvm::Function(functype, llvm::GlobalValue::ExternalLinkage, name, gIR->module);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+// llvm.memset.i32
+static llvm::Function* LLVM_DeclareMemSet32()
+{
+    static llvm::Function* _func = 0;
+    if (_func == 0) {
+        _func = LLVM_DeclareMemIntrinsic("llvm.memset.i32", 32, true);
+    }
+    return _func;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+static llvm::Function* LLVM_DeclareMemSet64()
+{
+    static llvm::Function* _func = 0;
+    if (_func == 0) {
+        _func = LLVM_DeclareMemIntrinsic("llvm.memset.i64", 64, true);
+    }
+    return _func;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+// llvm.memcpy.i32
+static llvm::Function* LLVM_DeclareMemCpy32()
+{
+    static llvm::Function* _func = 0;
+    if (_func == 0) {
+        _func = LLVM_DeclareMemIntrinsic("llvm.memcpy.i32", 32);
+    }
+    return _func;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+// llvm.memcpy.i64
+static llvm::Function* LLVM_DeclareMemCpy64()
+{
+    static llvm::Function* _func = 0;
+    if (_func == 0) {
+        _func = LLVM_DeclareMemIntrinsic("llvm.memcpy.i64", 64);
+    }
+    return _func;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::Value* LLVM_DtoStructZeroInit(TypeStruct* t, llvm::Value* v)
+{
+    assert(gIR);
+    uint64_t n = gTargetData->getTypeSize(t->llvmType);
+    //llvm::Type* sarrty = llvm::PointerType::get(llvm::ArrayType::get(llvm::Type::Int8Ty, n));
+    llvm::Type* sarrty = llvm::PointerType::get(llvm::Type::Int8Ty);
+
+    llvm::Value* sarr = new llvm::BitCastInst(v,sarrty,"tmp",gIR->scopebb());
+
+    llvm::Function* fn = LLVM_DeclareMemSet32();
+    std::vector<llvm::Value*> llargs;
+    llargs.resize(4);
+    llargs[0] = sarr;
+    llargs[1] = llvm::ConstantInt::get(llvm::Type::Int8Ty, 0, false);
+    llargs[2] = llvm::ConstantInt::get(llvm::Type::Int32Ty, n, false);
+    llargs[3] = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
+
+    llvm::Value* ret = new llvm::CallInst(fn, llargs.begin(), llargs.end(), "", gIR->scopebb());
+
+    return ret;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::Value* LLVM_DtoStructCopy(TypeStruct* t, llvm::Value* dst, llvm::Value* src)
+{
+    assert(dst->getType() == src->getType());
+    assert(gIR);
+
+    uint64_t n = gTargetData->getTypeSize(t->llvmType);
+    //llvm::Type* sarrty = llvm::PointerType::get(llvm::ArrayType::get(llvm::Type::Int8Ty, n));
+    llvm::Type* arrty = llvm::PointerType::get(llvm::Type::Int8Ty);
+
+    llvm::Value* dstarr = new llvm::BitCastInst(dst,arrty,"tmp",gIR->scopebb());
+    llvm::Value* srcarr = new llvm::BitCastInst(src,arrty,"tmp",gIR->scopebb());
+
+    llvm::Function* fn = LLVM_DeclareMemCpy32();
+    std::vector<llvm::Value*> llargs;
+    llargs.resize(4);
+    llargs[0] = dstarr;
+    llargs[1] = srcarr;
+    llargs[2] = llvm::ConstantInt::get(llvm::Type::Int32Ty, n, false);
+    llargs[3] = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
+
+    return new llvm::CallInst(fn, llargs.begin(), llargs.end(), "", gIR->scopebb());
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+llvm::Constant* LLVM_DtoStructInitializer(StructInitializer* si)
+{
+    llvm::StructType* structtype = llvm::cast<llvm::StructType>(si->ad->llvmType);
+    size_t n = structtype->getNumElements();
+
+    assert(si->value.dim == si->vars.dim);
+
+    std::vector<llvm::Constant*> inits;
+    inits.resize(n, NULL);
+    for (int i = 0; i < si->value.dim; ++i)
+    {
+        Initializer* ini = (Initializer*)si->value.data[i];
+        assert(ini);
+
+        VarDeclaration* vd = (VarDeclaration*)si->vars.data[i];
+        assert(vd);
+        Logger::println("vars[%d] = %s", i, vd->toChars());
+        unsigned idx = si->ad->offsetToIndex(vd->offset);
+
+        llvm::Constant* v = 0;
+
+        if (ExpInitializer* ex = ini->isExpInitializer())
+        {
+            elem* e = ex->exp->toElem(gIR);
+            v = llvm::cast<llvm::Constant>(e->val);
+            delete e;
+        }
+        else if (StructInitializer* si = ini->isStructInitializer())
+        {
+            v = LLVM_DtoStructInitializer(si);
+        }
+        else if (ArrayInitializer* ai = ini->isArrayInitializer())
+        {
+            v = LLVM_DtoArrayInitializer(ai);
+        }
+        else if (ini->isVoidInitializer())
+        {
+            v = llvm::UndefValue::get(structtype->getElementType(idx));
+        }
+        else
+        assert(v);
+
+        inits[idx] = v;
+    }
+
+    // fill out nulls
+    assert(si->ad->llvmInitZ);
+    if (si->ad->llvmInitZ->isNullValue())
+    {
+        for (int i = 0; i < n; ++i)
+        {
+            if (inits[i] == 0)
+            {
+                inits[i] = llvm::Constant::getNullValue(structtype->getElementType(i));
+            }
+        }
+    }
+    else
+    {
+        for (int i = 0; i < n; ++i)
+        {
+            if (inits[i] == 0)
+            {
+                inits[i] = si->ad->llvmInitZ->getOperand(i);
+            }
+        }
+    }
+
+    return llvm::ConstantStruct::get(structtype, inits);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::Value* LLVM_DtoNullArray(llvm::Value* v)
+{
+    assert(gIR);
+    d_uns64 n = (global.params.is64bit) ? 16 : 8;
+
+    llvm::Type* i8p_ty = llvm::PointerType::get(llvm::Type::Int8Ty);
+
+    llvm::Value* arr = new llvm::BitCastInst(v,i8p_ty,"tmp",gIR->scopebb());
+
+    llvm::Function* fn = LLVM_DeclareMemSet32();
+    std::vector<llvm::Value*> llargs;
+    llargs.resize(4);
+    llargs[0] = arr;
+    llargs[1] = llvm::ConstantInt::get(llvm::Type::Int8Ty, 0, false);
+    llargs[2] = llvm::ConstantInt::get(llvm::Type::Int32Ty, n, false);
+    llargs[3] = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
+
+    //Logger::cout() << *fn << '|' << *fn->getType() << '\n';
+    //Logger::cout() << "to null array call: " << *llargs[0] << '|' << *llargs[1] << '|' << *llargs[2] << '|' << *llargs[3] << '\n';
+
+    llvm::Value* ret = new llvm::CallInst(fn, llargs.begin(), llargs.end(), "", gIR->scopebb());
+
+    return ret;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::Value* LLVM_DtoNullDelegate(llvm::Value* v)
+{
+    assert(gIR);
+    d_uns64 n = (global.params.is64bit) ? 16 : 8;
+
+    llvm::Type* i8p_ty = llvm::PointerType::get(llvm::Type::Int8Ty);
+
+    llvm::Value* arr = new llvm::BitCastInst(v,i8p_ty,"tmp",gIR->scopebb());
+
+    llvm::Function* fn = LLVM_DeclareMemSet32();
+    std::vector<llvm::Value*> llargs;
+    llargs.resize(4);
+    llargs[0] = arr;
+    llargs[1] = llvm::ConstantInt::get(llvm::Type::Int8Ty, 0, false);
+    llargs[2] = llvm::ConstantInt::get(llvm::Type::Int32Ty, n, false);
+    llargs[3] = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
+
+    llvm::Value* ret = new llvm::CallInst(fn, llargs.begin(), llargs.end(), "", gIR->scopebb());
+
+    return ret;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::Value* LLVM_DtoDelegateCopy(llvm::Value* dst, llvm::Value* src)
+{
+    assert(dst->getType() == src->getType());
+    assert(gIR);
+
+    d_uns64 n = (global.params.is64bit) ? 16 : 8;
+
+    llvm::Type* arrty = llvm::PointerType::get(llvm::Type::Int8Ty);
+
+    llvm::Value* dstarr = new llvm::BitCastInst(dst,arrty,"tmp",gIR->scopebb());
+    llvm::Value* srcarr = new llvm::BitCastInst(src,arrty,"tmp",gIR->scopebb());
+
+    llvm::Function* fn = LLVM_DeclareMemCpy32();
+    std::vector<llvm::Value*> llargs;
+    llargs.resize(4);
+    llargs[0] = dstarr;
+    llargs[1] = srcarr;
+    llargs[2] = llvm::ConstantInt::get(llvm::Type::Int32Ty, n, false);
+    llargs[3] = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
+
+    return new llvm::CallInst(fn, llargs.begin(), llargs.end(), "", gIR->scopebb());
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::Value* LLVM_DtoArrayAssign(llvm::Value* dst, llvm::Value* src)
+{
+    assert(gIR);
+    if (dst->getType() == src->getType())
+    {
+        d_uns64 n = (global.params.is64bit) ? 16 : 8;
+
+        llvm::Type* arrty = llvm::PointerType::get(llvm::Type::Int8Ty);
+
+        llvm::Value* dstarr = new llvm::BitCastInst(dst,arrty,"tmp",gIR->scopebb());
+        llvm::Value* srcarr = new llvm::BitCastInst(src,arrty,"tmp",gIR->scopebb());
+
+        llvm::Function* fn = LLVM_DeclareMemCpy32();
+        std::vector<llvm::Value*> llargs;
+        llargs.resize(4);
+        llargs[0] = dstarr;
+        llargs[1] = srcarr;
+        llargs[2] = llvm::ConstantInt::get(llvm::Type::Int32Ty, n, false);
+        llargs[3] = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
+
+        return new llvm::CallInst(fn, llargs.begin(), llargs.end(), "", gIR->scopebb());
+    }
+    else
+    {
+        if (!llvm::isa<llvm::ArrayType>(src->getType()->getContainedType(0)))
+        {
+            Logger::cout() << "invalid: " << *src << '\n';
+            assert(0);
+        }
+        const llvm::ArrayType* arrty = llvm::cast<llvm::ArrayType>(src->getType()->getContainedType(0));
+        llvm::Type* dstty = llvm::PointerType::get(arrty->getElementType());
+
+        llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
+        llvm::Value* one = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1, false);
+
+        llvm::Value* dstlen = new llvm::GetElementPtrInst(dst,zero,zero,"tmp",gIR->scopebb());
+        llvm::Value* srclen = llvm::ConstantInt::get(LLVM_DtoSize_t(), arrty->getNumElements(), false);
+        new llvm::StoreInst(srclen, dstlen, gIR->scopebb());
+
+        llvm::Value* dstptr = new llvm::GetElementPtrInst(dst,zero,one,"tmp",gIR->scopebb());
+        llvm::Value* srcptr = new llvm::BitCastInst(src,dstty,"tmp",gIR->scopebb());
+        new llvm::StoreInst(srcptr, dstptr, gIR->scopebb());
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+void LLVM_DtoArrayInit(llvm::Value* l, llvm::Value* r)
+{
+    const llvm::PointerType* ptrty = llvm::cast<llvm::PointerType>(l->getType());
+    if (llvm::isa<llvm::ArrayType>(ptrty->getContainedType(0)))
+    {
+        const llvm::ArrayType* arrty = llvm::cast<llvm::ArrayType>(ptrty->getContainedType(0));
+        llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
+
+        std::vector<llvm::Value*> args;
+        args.resize(3);
+        args[0] = new llvm::GetElementPtrInst(l,zero,zero,"tmp",gIR->scopebb());
+        args[1] = llvm::ConstantInt::get(LLVM_DtoSize_t(), arrty->getNumElements(), false);
+        args[2] = r;
+        
+        const char* funcname = NULL;
+        
+        if (llvm::isa<llvm::PointerType>(arrty->getElementType())) {
+            funcname = "_d_array_init_pointer";
+            
+            const llvm::Type* dstty = llvm::PointerType::get(llvm::PointerType::get(llvm::Type::Int8Ty));
+            if (args[0]->getType() != dstty)
+                args[0] = new llvm::BitCastInst(args[0],dstty,"tmp",gIR->scopebb());
+            
+            const llvm::Type* valty = llvm::PointerType::get(llvm::Type::Int8Ty);
+            if (args[2]->getType() != valty)
+                args[2] = new llvm::BitCastInst(args[2],valty,"tmp",gIR->scopebb());
+        }
+        else if (r->getType() == llvm::Type::Int1Ty) {
+            funcname = "_d_array_init_i1";
+        }
+        else if (r->getType() == llvm::Type::Int8Ty) {
+            funcname = "_d_array_init_i8";
+        }
+        else if (r->getType() == llvm::Type::Int16Ty) {
+            funcname = "_d_array_init_i16";
+        }
+        else if (r->getType() == llvm::Type::Int32Ty) {
+            funcname = "_d_array_init_i32";
+        }
+        else if (r->getType() == llvm::Type::Int64Ty) {
+            funcname = "_d_array_init_i64";
+        }
+        else if (r->getType() == llvm::Type::FloatTy) {
+            funcname = "_d_array_init_float";
+        }
+        else if (r->getType() == llvm::Type::DoubleTy) {
+            funcname = "_d_array_init_double";
+        }
+        else {
+            assert(0);
+        }
+        
+        Logger::cout() << *args[0] << '|' << *args[2] << '\n';
+        
+        llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, funcname);
+        assert(fn);
+        llvm::CallInst* call = new llvm::CallInst(fn, args.begin(), args.end(), "", gIR->scopebb());
+        call->setCallingConv(llvm::CallingConv::C);
+        
+        Logger::println("array init call ok");
+    }
+    else if (llvm::isa<llvm::StructType>(ptrty->getContainedType(0)))
+    {
+        assert(0 && "Only static arrays support initialisers atm");
+    }
+    else
+    assert(0);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+void LLVM_DtoSetArray(llvm::Value* arr, llvm::Value* dim, llvm::Value* ptr)
+{
+    const llvm::StructType* st = llvm::cast<llvm::StructType>(arr->getType()->getContainedType(0));
+    //const llvm::PointerType* pt = llvm::cast<llvm::PointerType>(r->getType());
+    
+    llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
+    llvm::Value* one = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1, false);
+
+    llvm::Value* arrdim = new llvm::GetElementPtrInst(arr,zero,zero,"tmp",gIR->scopebb());
+    new llvm::StoreInst(dim, arrdim, gIR->scopebb());
+    
+    llvm::Value* arrptr = new llvm::GetElementPtrInst(arr,zero,one,"tmp",gIR->scopebb());
+    new llvm::StoreInst(ptr, arrptr, gIR->scopebb());
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+llvm::Constant* LLVM_DtoArrayInitializer(ArrayInitializer* arrinit)
+{
+    Logger::println("arr init begin");
+    assert(arrinit->type->ty == Tsarray);
+    TypeSArray* t = (TypeSArray*)arrinit->type;
+    integer_t tdim = t->dim->toInteger();
+
+    std::vector<llvm::Constant*> inits(tdim, 0);
+
+    const llvm::Type* elemty = LLVM_DtoType(arrinit->type->next);
+
+    assert(arrinit->index.dim == arrinit->value.dim);
+    for (int i=0,j=0; i < tdim; ++i)
+    {
+        Initializer* init = 0;
+        Expression* idx = (Expression*)arrinit->index.data[j];
+
+        if (idx)
+        {
+            integer_t k = idx->toInteger();
+            if (i == k)
+            {
+                init = (Initializer*)arrinit->value.data[j];
+                assert(init);
+                ++j;
+            }
+        }
+        else
+        {
+            init = (Initializer*)arrinit->value.data[j];
+            ++j;
+        }
+
+        llvm::Constant* v = 0;
+
+        if (!init)
+        {
+            elem* e = t->next->defaultInit()->toElem(gIR);
+            v = llvm::cast<llvm::Constant>(e->val);
+            delete e;
+        }
+        else if (ExpInitializer* ex = init->isExpInitializer())
+        {
+            elem* e = ex->exp->toElem(gIR);
+            v = llvm::cast<llvm::Constant>(e->val);
+            delete e;
+        }
+        else if (StructInitializer* si = init->isStructInitializer())
+        {
+            v = LLVM_DtoStructInitializer(si);
+        }
+        else if (ArrayInitializer* ai = init->isArrayInitializer())
+        {
+            v = LLVM_DtoArrayInitializer(ai);
+        }
+        else if (init->isVoidInitializer())
+        {
+            v = llvm::UndefValue::get(elemty);
+        }
+        else
+        assert(v);
+
+        inits[i] = v;
+    }
+
+    llvm::ArrayType* arrty = LLVM_DtoStaticArrayType(t);
+    return llvm::ConstantArray::get(arrty, inits);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+void LLVM_DtoArrayCopy(elem* dst, elem* src)
+{
+    assert(0);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::GlobalValue::LinkageTypes LLVM_DtoLinkage(PROT prot, uint stc)
+{
+    switch(prot)
+    {
+    case PROTprivate:
+        return llvm::GlobalValue::InternalLinkage;
+
+    case PROTpublic:
+    case PROTpackage:
+    case PROTprotected:
+    case PROTexport:
+        return llvm::GlobalValue::ExternalLinkage;
+
+    case PROTundefined:
+    case PROTnone:
+        assert(0 && "Unsupported linkage type");
+    }
+    return llvm::GlobalValue::ExternalLinkage;
+
+/*      ExternalLinkage = 0, LinkOnceLinkage, WeakLinkage, AppendingLinkage,
+  InternalLinkage, DLLImportLinkage, DLLExportLinkage, ExternalWeakLinkage,
+  GhostLinkage */
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+unsigned LLVM_DtoCallingConv(LINK l)
+{
+    if (l == LINKc)
+        return llvm::CallingConv::C;
+    else if (l == LINKd || l == LINKdefault)
+        return llvm::CallingConv::Fast;
+    else if (l == LINKwindows)
+        return llvm::CallingConv::X86_StdCall;
+    else
+        assert(0 && "Unsupported calling convention");
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::Value* LLVM_DtoPointedType(llvm::Value* ptr, llvm::Value* val)
+{
+    const llvm::Type* ptrTy = ptr->getType()->getContainedType(0);
+    const llvm::Type* valTy = val->getType();
+    // ptr points to val's type
+    if (ptrTy == valTy)
+    {
+        return val;
+    }
+    // ptr is integer pointer
+    else if (ptrTy->isInteger())
+    {
+        // val is integer
+        assert(valTy->isInteger());
+        const llvm::IntegerType* pt = llvm::cast<const llvm::IntegerType>(ptrTy);
+        const llvm::IntegerType* vt = llvm::cast<const llvm::IntegerType>(valTy);
+        if (pt->getBitWidth() < vt->getBitWidth()) {
+            return new llvm::TruncInst(val, pt, "tmp", gIR->scopebb());
+        }
+        else
+        assert(0);
+    }
+    // something else unsupported
+    else
+    {
+        Logger::cout() << *ptrTy << '|' << *valTy << '\n';
+        assert(0);
+    }
+    return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::Value* LLVM_DtoBoolean(llvm::Value* val)
+{
+    const llvm::Type* t = val->getType();
+    if (t->isInteger())
+    {
+        if (t == llvm::Type::Int1Ty)
+            return val;
+        else {
+            llvm::Value* zero = llvm::ConstantInt::get(t, 0, false);
+            return new llvm::ICmpInst(llvm::ICmpInst::ICMP_NE, val, zero, "tmp", gIR->scopebb());
+        }
+    }
+    else if (llvm::isa<llvm::PointerType>(t)) {
+        const llvm::Type* st = LLVM_DtoSize_t();
+        llvm::Value* ptrasint = new llvm::PtrToIntInst(val,st,"tmp",gIR->scopebb());
+        llvm::Value* zero = llvm::ConstantInt::get(st, 0, false);
+        return new llvm::ICmpInst(llvm::ICmpInst::ICMP_NE, ptrasint, zero, "tmp", gIR->scopebb());
+    }
+    else
+    {
+        Logger::cout() << *t << '\n';
+    }
+    assert(0);
+    return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+const llvm::Type* LLVM_DtoSize_t()
+{
+    if (global.params.is64bit)
+    return llvm::Type::Int64Ty;
+    else
+    return llvm::Type::Int32Ty;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+void LLVM_DtoMain()
+{
+    // emit main function llvm style
+    // int main(int argc, char**argv, char**env);
+
+    assert(gIR != 0);
+    IRState& ir = *gIR;
+
+    assert(ir.emitMain && ir.mainFunc);
+
+    // parameter types
+    std::vector<const llvm::Type*> pvec;
+    pvec.push_back((const llvm::Type*)llvm::Type::Int32Ty);
+    const llvm::Type* chPtrType = (const llvm::Type*)llvm::PointerType::get(llvm::Type::Int8Ty);
+    pvec.push_back((const llvm::Type*)llvm::PointerType::get(chPtrType));
+    pvec.push_back((const llvm::Type*)llvm::PointerType::get(chPtrType));
+    const llvm::Type* rettype = (const llvm::Type*)llvm::Type::Int32Ty;
+
+    llvm::FunctionType* functype = llvm::FunctionType::get(rettype, pvec, false);
+    llvm::Function* func = new llvm::Function(functype,llvm::GlobalValue::ExternalLinkage,"main",ir.module);
+
+    llvm::BasicBlock* bb = new llvm::BasicBlock("entry",func);
+
+    // call static ctors
+    llvm::Function* fn = LLVM_D_GetRuntimeFunction(ir.module,"_d_run_module_ctors");
+    new llvm::CallInst(fn,"",bb);
+
+    // call user main function
+    llvm::CallInst* call = new llvm::CallInst(ir.mainFunc,"ret",bb);
+    call->setCallingConv(ir.mainFunc->getCallingConv());
+
+    // call static dtors
+    fn = LLVM_D_GetRuntimeFunction(ir.module,"_d_run_module_dtors");
+    new llvm::CallInst(fn,"",bb);
+
+    // return
+    new llvm::ReturnInst(call,bb);
+
+    /*
+    // return value type
+    const llvm::Type* rettype;
+    Type* rt = f->next;
+    if (rt) {
+        rettype = LLVM_DtoType(rt);
+    }
+    else {
+        assert(0);
+    }
+
+    llvm::FunctionType* functype = llvm::FunctionType::get(rettype, paramvec, false);
+    */
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+void LLVM_DtoCallClassDtors(TypeClass* tc, llvm::Value* instance)
+{
+    Array* arr = &tc->sym->dtors;
+    for (size_t i=0; i<arr->dim; i++)
+    {
+        FuncDeclaration* fd = (FuncDeclaration*)arr->data[i];
+        assert(fd->llvmValue);
+        new llvm::CallInst(fd->llvmValue, instance, "", gIR->scopebb());
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+void LLVM_DtoInitClass(TypeClass* tc, llvm::Value* dst)
+{
+    assert(tc->llvmInit);
+    assert(dst->getType() == tc->llvmInit->getType());
+    assert(gIR);
+
+    assert(tc->llvmType);
+    uint64_t n = gTargetData->getTypeSize(tc->llvmType);
+    llvm::Type* arrty = llvm::PointerType::get(llvm::Type::Int8Ty);
+
+    llvm::Value* dstarr = new llvm::BitCastInst(dst,arrty,"tmp",gIR->scopebb());
+    llvm::Value* srcarr = new llvm::BitCastInst(tc->llvmInit,arrty,"tmp",gIR->scopebb());
+
+    llvm::Function* fn = LLVM_DeclareMemCpy32();
+    std::vector<llvm::Value*> llargs;
+    llargs.resize(4);
+    llargs[0] = dstarr;
+    llargs[1] = srcarr;
+    llargs[2] = llvm::ConstantInt::get(llvm::Type::Int32Ty, n, false);
+    llargs[3] = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
+
+    new llvm::CallInst(fn, llargs.begin(), llargs.end(), "", gIR->scopebb());
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::Constant* LLVM_DtoInitializer(Type* type, Initializer* init)
+{
+    llvm::Constant* _init = 0;
+    if (!init)
+    {
+        elem* e = type->defaultInit()->toElem(gIR);
+        if (!e->inplace && !e->isNull()) {
+            _init = llvm::cast<llvm::Constant>(e->getValue());
+        }
+        delete e;
+    }
+    else if (ExpInitializer* ex = init->isExpInitializer())
+    {
+        elem* e = ex->exp->toElem(gIR);
+        if (!e->inplace && !e->isNull()) {
+            _init = llvm::cast<llvm::Constant>(e->getValue());
+        }
+        delete e;
+    }
+    else if (StructInitializer* si = init->isStructInitializer())
+    {
+        _init = LLVM_DtoStructInitializer(si);
+    }
+    else if (ArrayInitializer* ai = init->isArrayInitializer())
+    {
+        _init = LLVM_DtoArrayInitializer(ai);
+    }
+    else if (init->isVoidInitializer())
+    {
+        const llvm::Type* ty = LLVM_DtoType(type);
+        _init = llvm::Constant::getNullValue(ty);
+    }
+    else {
+        Logger::println("unsupported initializer: %s", init->toChars());
+    }
+    return _init;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen/tollvm.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,44 @@
+// D -> LLVM helpers
+
+struct StructInitializer;
+
+const llvm::Type* LLVM_DtoType(Type* t);
+
+llvm::Type* LLVM_DtoStructType(Type* t);
+llvm::Value* LLVM_DtoStructZeroInit(TypeStruct* t, llvm::Value* v);
+llvm::Value* LLVM_DtoStructCopy(TypeStruct* t, llvm::Value* dst, llvm::Value* src);
+llvm::Constant* LLVM_DtoStructInitializer(StructInitializer* si);
+
+llvm::FunctionType* LLVM_DtoFunctionType(Type* t, const llvm::Type* thisparam = 0);
+llvm::FunctionType* LLVM_DtoFunctionType(FuncDeclaration* fdecl);
+
+llvm::StructType* LLVM_DtoDelegateType(Type* t);
+llvm::Value* LLVM_DtoNullDelegate(llvm::Value* v);
+llvm::Value* LLVM_DtoDelegateCopy(llvm::Value* dst, llvm::Value* src);
+
+llvm::StructType* LLVM_DtoArrayType(Type* t);
+llvm::ArrayType* LLVM_DtoStaticArrayType(Type* t);
+llvm::Value* LLVM_DtoNullArray(llvm::Value* v);
+llvm::Value* LLVM_DtoArrayAssign(llvm::Value* l, llvm::Value* r);
+void LLVM_DtoSetArray(llvm::Value* arr, llvm::Value* dim, llvm::Value* ptr);
+llvm::Constant* LLVM_DtoArrayInitializer(ArrayInitializer* si);
+void LLVM_DtoArrayCopy(elem* dst, elem* src);
+
+void LLVM_DtoArrayInit(llvm::Value* l, llvm::Value* r);
+
+llvm::GlobalValue::LinkageTypes LLVM_DtoLinkage(PROT prot, uint stc);
+unsigned LLVM_DtoCallingConv(LINK l);
+
+llvm::Value* LLVM_DtoPointedType(llvm::Value* ptr, llvm::Value* val);
+llvm::Value* LLVM_DtoBoolean(llvm::Value* val);
+
+const llvm::Type* LLVM_DtoSize_t();
+
+void LLVM_DtoMain();
+
+void LLVM_DtoCallClassDtors(TypeClass* tc, llvm::Value* instance);
+void LLVM_DtoInitClass(TypeClass* tc, llvm::Value* dst);
+
+llvm::Constant* LLVM_DtoInitializer(Type* type, Initializer* init);
+
+#include "enums.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen/toobj.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,816 @@
+
+// Copyright (c) 1999-2004 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <cstddef>
+#include <iostream>
+#include <fstream>
+
+#include "llvm/Type.h"
+#include "llvm/Constants.h"
+#include "llvm/DerivedTypes.h"
+#include "llvm/Instructions.h"
+#include "llvm/Analysis/Verifier.h"
+#include "llvm/Bitcode/ReaderWriter.h"
+
+#include "llvm/Target/TargetData.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetMachineRegistry.h"
+
+#include "mars.h"
+#include "module.h"
+#include "mtype.h"
+#include "declaration.h"
+#include "statement.h"
+#include "enum.h"
+#include "aggregate.h"
+#include "init.h"
+#include "attrib.h"
+#include "id.h"
+#include "import.h"
+#include "template.h"
+#include "irstate.h"
+#include "elem.h"
+#include "logger.h"
+
+#include "tollvm.h"
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+void
+Module::genobjfile()
+{
+    Logger::cout() << "Generating module: " << (md ? md->toChars() : toChars()) << '\n';
+    LOG_SCOPE;
+
+    deleteObjFile();
+
+    IRState ir;
+    gIR = &ir;
+
+    ir.dmodule = this;
+
+    std::string mname(toChars());
+    if (md != 0)
+        mname = md->toChars();
+    ir.module = new llvm::Module(mname);
+
+    std::string target_triple(global.params.tt_arch);
+    target_triple.append(global.params.tt_os);
+    ir.module->setTargetTriple(target_triple);
+    ir.module->setDataLayout(global.params.data_layout);
+
+    gTargetData = new llvm::TargetData(ir.module);
+
+    for (int k=0; k < members->dim; k++) {
+        Dsymbol* dsym = (Dsymbol*)(members->data[k]);
+        assert(dsym);
+        dsym->toObjFile();
+    }
+
+    delete gTargetData;
+    gTargetData = 0;
+
+    std::string verifyErr;
+    if (llvm::verifyModule(*ir.module,llvm::ReturnStatusAction,&verifyErr))
+    {
+        error("%s", verifyErr.c_str());
+        fatal();
+    }
+
+    if (ir.emitMain) {
+        LLVM_DtoMain();
+    }
+
+    // run passes
+    // TODO
+
+    /*if (global.params.llvmLL) {
+        //assert(0);
+        std::ofstream os(llfile->name->toChars());
+        //llvm::WriteAssemblyToFile(ir.module, os);
+        ir.module->print(os);
+    }*/
+
+    //if (global.params.llvmBC) {
+        Logger::println("Writing LLVM bitcode\n");
+        std::ofstream os(bcfile->name->toChars(), std::ios::binary);
+        llvm::WriteBitcodeToFile(ir.module, os);
+    //}
+
+    delete ir.module;
+    gIR = NULL;
+}
+
+/* ================================================================== */
+
+// Put out instance of ModuleInfo for this Module
+
+void Module::genmoduleinfo()
+{
+}
+
+/* ================================================================== */
+
+void Dsymbol::toObjFile()
+{
+    warning("Ignoring Dsymbol::toObjFile for %s", toChars());
+}
+
+/* ================================================================== */
+
+void Declaration::toObjFile()
+{
+    warning("Ignoring Declaration::toObjFile for %s", toChars());
+}
+
+/* ================================================================== */
+
+unsigned AggregateDeclaration::offsetToIndex(unsigned os)
+{
+    for (unsigned i=0; i<fields.dim; ++i) {
+        VarDeclaration* vd = (VarDeclaration*)fields.data[i];
+        if (os == vd->offset)
+            return i;
+    }
+    assert(0 && "Offset not found in any aggregate field");
+    return 0;
+}
+
+/* ================================================================== */
+
+static unsigned LLVM_ClassOffsetToIndex(ClassDeclaration* cd, unsigned os, unsigned& idx)
+{
+    // start at the bottom of the inheritance chain
+    if (cd->baseClass != 0) {
+        unsigned o = LLVM_ClassOffsetToIndex(cd->baseClass, os, idx);
+        if (o != (unsigned)-1)
+            return o;
+    }
+
+    // check this class
+    unsigned i;
+    for (i=0; i<cd->fields.dim; ++i) {
+        VarDeclaration* vd = (VarDeclaration*)cd->fields.data[i];
+        if (os == vd->offset)
+            return i+idx;
+    }
+    idx += i;
+
+    return (unsigned)-1;
+}
+
+unsigned ClassDeclaration::offsetToIndex(unsigned os)
+{
+    unsigned idx = 0;
+    unsigned r = LLVM_ClassOffsetToIndex(this, os, idx);
+    assert(r != (unsigned)-1 && "Offset not found in any aggregate field");
+    return r+1; // vtable is 0
+}
+
+/* ================================================================== */
+
+void InterfaceDeclaration::toObjFile()
+{
+    warning("Ignoring InterfaceDeclaration::toObjFile for %s", toChars());
+}
+
+/* ================================================================== */
+
+void StructDeclaration::toObjFile()
+{
+    TypeStruct* ts = (TypeStruct*)type;
+    if (llvmType != 0)
+        return;
+
+    static int sdi = 0;
+    Logger::print("StructDeclaration::toObjFile(%d): %s\n", sdi++, toChars());
+    LOG_SCOPE;
+
+    gIR->structs.push_back(IRStruct(ts));
+
+    std::vector<FuncDeclaration*> mfs;
+
+    for (int k=0; k < members->dim; k++) {
+        Dsymbol* dsym = (Dsymbol*)(members->data[k]);
+
+        // need late generation of member functions
+        // they need the llvm::StructType to exist to take the 'this' parameter
+        if (FuncDeclaration* fd = dsym->isFuncDeclaration()) {
+            mfs.push_back(fd);
+        }
+        else {
+            dsym->toObjFile();
+        }
+    }
+
+    llvm::StructType* structtype = llvm::StructType::get(gIR->topstruct().fields);
+
+    // refine abstract types for stuff like: struct S{S* next;}
+    if (gIR->topstruct().recty != 0)
+    {
+        llvm::PATypeHolder& pa = gIR->topstruct().recty;
+        llvm::cast<llvm::OpaqueType>(pa.get())->refineAbstractTypeTo(structtype);
+        structtype = llvm::cast<llvm::StructType>(pa.get());
+    }
+
+    ts->llvmType = structtype;
+    llvmType = structtype;
+
+    if (parent->isModule()) {
+        gIR->module->addTypeName(mangle(),ts->llvmType);
+    }
+
+    // generate static data
+    llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::ExternalLinkage;
+    llvm::Constant* _init = 0;
+
+    // always generate the constant initalizer
+    if (!zeroInit) {
+        Logger::println("Not zero initialized");
+        //assert(tk == gIR->topstruct().size());
+        #ifndef LLVMD_NO_LOGGER
+        Logger::cout() << *structtype << '\n';
+        for (size_t k=0; k<gIR->topstruct().inits.size(); ++k) {
+            Logger::cout() << "Type:" << '\n';
+            Logger::cout() << *gIR->topstruct().inits[k]->getType() << '\n';
+            Logger::cout() << "Value:" << '\n';
+            Logger::cout() << *gIR->topstruct().inits[k] << '\n';
+        }
+        Logger::cout() << "Initializer printed" << '\n';
+        #endif
+        llvmInitZ = llvm::ConstantStruct::get(structtype,gIR->topstruct().inits);
+    }
+    else {
+        Logger::println("Zero initialized");
+        llvmInitZ = llvm::ConstantAggregateZero::get(structtype);
+    }
+
+    // only provide the constant initializer for the defining module
+    if (getModule() == gIR->dmodule)
+    {
+        _init = llvmInitZ;
+    }
+
+    std::string initname(mangle());
+    initname.append("__initZ");
+    llvm::GlobalVariable* initvar = new llvm::GlobalVariable(ts->llvmType, true, _linkage, _init, initname, gIR->module);
+    ts->llvmInit = initvar;
+
+    // generate member functions
+    size_t n = mfs.size();
+    for (size_t i=0; i<n; ++i) {
+        mfs[i]->toObjFile();
+    }
+
+    llvmDModule = gIR->dmodule;
+
+    gIR->structs.pop_back();
+
+    // generate typeinfo
+    type->getTypeInfo(NULL);    // generate TypeInfo
+}
+
+/* ================================================================== */
+
+static void LLVM_AddBaseClassData(BaseClasses* bcs)
+{
+    // add base class data members first
+    for (int j=0; j<bcs->dim; j++)
+    {
+        BaseClass* bc = (BaseClass*)(bcs->data[j]);
+        assert(bc);
+        LLVM_AddBaseClassData(&bc->base->baseclasses);
+        for (int k=0; k < bc->base->members->dim; k++) {
+            Dsymbol* dsym = (Dsymbol*)(bc->base->members->data[k]);
+            if (dsym->isVarDeclaration())
+            {
+                dsym->toObjFile();
+            }
+        }
+    }
+}
+
+void ClassDeclaration::toObjFile()
+{
+    TypeClass* ts = (TypeClass*)type;
+    if (ts->llvmType != 0 || llvmInProgress)
+        return;
+
+    llvmInProgress = true;
+
+    static int fdi = 0;
+    Logger::print("ClassDeclaration::toObjFile(%d): %s\n", fdi++, toChars());
+    LOG_SCOPE;
+
+    gIR->structs.push_back(IRStruct());
+    gIR->classes.push_back(this);
+    gIR->classmethods.push_back(IRState::FuncDeclVec());
+    gIR->queueClassMethods.push_back(true);
+
+    // add vtable
+    const llvm::Type* vtabty = llvm::PointerType::get(llvm::Type::Int8Ty);
+    gIR->topstruct().fields.push_back(vtabty);
+    gIR->topstruct().inits.push_back(0);
+
+    // base classes first
+    LLVM_AddBaseClassData(&baseclasses);
+
+    // then add own members
+    for (int k=0; k < members->dim; k++) {
+        Dsymbol* dsym = (Dsymbol*)(members->data[k]);
+        dsym->toObjFile();
+    }
+
+    llvm::StructType* structtype = llvm::StructType::get(gIR->topstruct().fields);
+    ts->llvmType = structtype;
+    llvmType = structtype;
+
+    bool emit_vtable = false;
+    bool define_vtable = false;
+    if (parent->isModule()) {
+        gIR->module->addTypeName(mangle(),ts->llvmType);
+        emit_vtable = true;
+        define_vtable = (getModule() == gIR->dmodule);
+    }
+    else {
+        assert(0 && "class parent is not a module");
+    }
+
+    // generate member functions
+    gIR->queueClassMethods.back() = false;
+    IRState::FuncDeclVec& mfs = gIR->classmethods.back();
+    size_t n = mfs.size();
+    for (size_t i=0; i<n; ++i) {
+        mfs[i]->toObjFile();
+    }
+
+    // create vtable initializer
+    if (emit_vtable)
+    {
+        llvm::GlobalVariable* vtblVar = 0;
+        std::vector<llvm::Constant*> inits;
+        inits.reserve(vtbl.dim);
+        for (int k=0; k < vtbl.dim; k++)
+        {
+            Dsymbol* dsym = (Dsymbol*)vtbl.data[k];
+            assert(dsym);
+            //Logger::cout() << "vtblsym: " << dsym->toChars() << '\n';
+
+            if (FuncDeclaration* fd = dsym->isFuncDeclaration()) {
+                fd->toObjFile();
+                Logger::cout() << "casting to constant" << *fd->llvmValue << '\n';
+                llvm::Constant* c = llvm::cast<llvm::Constant>(fd->llvmValue);
+                c = llvm::ConstantExpr::getBitCast(c, llvm::PointerType::get(llvm::Type::Int8Ty));
+                inits.push_back(c);
+            }
+            else if (ClassDeclaration* cd = dsym->isClassDeclaration()) {
+                llvm::Constant* c = llvm::Constant::getNullValue(llvm::PointerType::get(llvm::Type::Int8Ty));
+                inits.push_back(c);
+            }
+            else
+            assert(0);
+        }
+        if (!inits.empty())
+        {
+            llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::ExternalLinkage;
+            std::string varname(mangle());
+            varname.append("__vtblZ");
+            const llvm::ArrayType* vtbl_ty = llvm::ArrayType::get(llvm::PointerType::get(llvm::Type::Int8Ty), inits.size());
+            vtblVar = new llvm::GlobalVariable(vtbl_ty, true, _linkage, 0, varname, gIR->module);
+            if (define_vtable) {
+                //Logger::cout() << "vtbl:::" << '\n' << *vtbl_st << '\n';// << " == | == " << _init << '\n';
+                llvm::Constant* _init = llvm::ConstantArray::get(vtbl_ty, inits);
+                vtblVar->setInitializer(_init);
+            }
+            llvmVtbl = vtblVar;
+        }
+
+        ////////////////////////////////////////////////////////////////////////////////
+
+        // generate initializer
+        llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::ExternalLinkage;
+        llvm::Constant* _init = 0;
+
+        // first field is always the vtable
+        assert(vtblVar != 0);
+        llvm::Constant* vtbl_init_var = llvm::ConstantExpr::getBitCast(vtblVar, llvm::PointerType::get(llvm::Type::Int8Ty));
+        gIR->topstruct().inits[0] = vtbl_init_var;
+
+        //assert(tk == gIR->topstruct().size());
+        #ifndef LLVMD_NO_LOGGER
+        Logger::cout() << *structtype << '\n';
+        for (size_t k=0; k<gIR->topstruct().inits.size(); ++k)
+            Logger::cout() << *gIR->topstruct().inits[k] << '\n';
+        #endif
+        _init = llvm::ConstantStruct::get(structtype,gIR->topstruct().inits);
+        assert(_init);
+        std::string initname(mangle());
+        initname.append("__initZ");
+        Logger::cout() << *_init << '\n';
+        llvm::GlobalVariable* initvar = new llvm::GlobalVariable(ts->llvmType, true, _linkage, 0, initname, gIR->module);
+        ts->llvmInit = initvar;
+        if (define_vtable) {
+            initvar->setInitializer(_init);
+        }
+    }
+
+    gIR->queueClassMethods.pop_back();
+    gIR->classmethods.pop_back();
+    gIR->classes.pop_back();
+    gIR->structs.pop_back();
+
+    llvmInProgress = false;
+}
+
+/******************************************
+ * Get offset of base class's vtbl[] initializer from start of csym.
+ * Returns ~0 if not this csym.
+ */
+
+unsigned ClassDeclaration::baseVtblOffset(BaseClass *bc)
+{
+  return ~0;
+}
+
+/* ================================================================== */
+
+void VarDeclaration::toObjFile()
+{
+    static int vdi = 0;
+    Logger::print("VarDeclaration::toObjFile(%d): %s | %s\n", vdi++, toChars(), type->toChars());
+    LOG_SCOPE;
+    llvm::Module* M = gIR->module;
+
+    // handle bind pragma
+    if (llvmInternal == LLVMbind) {
+        Logger::println("var is bound: %s", llvmInternal1);
+        llvmValue = M->getGlobalVariable(llvmInternal1);  
+        assert(llvmValue);
+        return;
+    }
+
+    // global variable or magic
+    if (!parent || parent->isModule())
+    {
+        bool _isconst = isConst();
+        if (!_isconst)
+            _isconst = (storage_class & STCconst) ? true : false; // doesn't seem to work ):
+        llvm::GlobalValue::LinkageTypes _linkage = LLVM_DtoLinkage(protection, storage_class);
+        const llvm::Type* _type = LLVM_DtoType(type);
+
+        llvm::Constant* _init = 0;
+        bool _signed = !type->isunsigned();
+
+        _init = LLVM_DtoInitializer(type, init);
+
+        assert(_type);
+        assert(_init);
+        //Logger::cout() << "initializer: " << *_init << '\n';
+        if (_type != _init->getType()) {
+            Logger::cout() << "got type '" << *_init->getType() << "' expected '" << *_type << "'\n";
+            // zero initalizer
+            if (_init->isNullValue())
+                _init = llvm::Constant::getNullValue(_type);
+            // pointer to global constant (struct.init)
+            else if (llvm::isa<llvm::GlobalVariable>(_init))
+            {
+                assert(_init->getType()->getContainedType(0) == _type);
+                llvm::GlobalVariable* gv = llvm::cast<llvm::GlobalVariable>(_init);
+                assert(type->ty == Tstruct);
+                TypeStruct* ts = (TypeStruct*)type;
+                assert(ts->sym->llvmInitZ);
+                _init = ts->sym->llvmInitZ;
+            }
+            // array single value init
+            else if (llvm::isa<llvm::ArrayType>(_type))
+            {
+                const llvm::ArrayType* at = llvm::cast<llvm::ArrayType>(_type);
+                assert(_type->getContainedType(0) == _init->getType());
+                std::vector<llvm::Constant*> initvals;
+                initvals.resize(at->getNumElements(), _init);
+                _init = llvm::ConstantArray::get(at, initvals);
+            }
+            else
+            assert(0);
+        }
+
+        Logger::println("Creating global variable");
+        std::string _name(mangle());
+        llvm::GlobalVariable* gvar = new llvm::GlobalVariable(_type,_isconst,_linkage,_init,_name,M);
+        llvmValue = gvar;
+
+        //if (storage_class & STCprivate)
+        //    gvar->setVisibility(llvm::GlobalValue::ProtectedVisibility);
+    }
+
+    // inside aggregate declaration. declare a field.
+    else
+    {
+        Logger::println("Aggregate var declaration: '%s' offset=%d", toChars(), offset);
+
+        const llvm::Type* _type = LLVM_DtoType(type);
+        gIR->topstruct().fields.push_back(_type);
+
+        llvm::Constant* _init = LLVM_DtoInitializer(type, init);
+        if (_type != _init->getType())
+        {
+            if (llvm::isa<llvm::ArrayType>(_type))
+            {
+                const llvm::ArrayType* arrty = llvm::cast<llvm::ArrayType>(_type);
+                uint64_t n = arrty->getNumElements();
+                std::vector<llvm::Constant*> vals(n,_init);
+                _init = llvm::ConstantArray::get(arrty, vals);
+            }
+            else
+            assert(0);
+        }
+        gIR->topstruct().inits.push_back(_init);
+    }
+
+    Logger::println("VarDeclaration::toObjFile is done");
+}
+
+/* ================================================================== */
+
+void TypedefDeclaration::toObjFile()
+{
+    static int tdi = 0;
+    Logger::print("TypedefDeclaration::toObjFile(%d): %s\n", tdi++, toChars());
+    LOG_SCOPE;
+
+    // TODO
+}
+
+/* ================================================================== */
+
+void EnumDeclaration::toObjFile()
+{
+    warning("Ignoring EnumDeclaration::toObjFile for %s", toChars());
+}
+
+/* ================================================================== */
+
+void FuncDeclaration::toObjFile()
+{
+    if (llvmValue != 0 && llvmDModule == gIR->dmodule) {
+        return;
+    }
+
+    // has already been pulled in by a reference to (
+    if (!gIR->queueClassMethods.empty() && gIR->queueClassMethods.back()) {
+        Logger::println("queueing %s", toChars());
+        assert(!gIR->classmethods.empty());
+        gIR->classmethods.back().push_back(this);
+        return; // will be generated later when the this parameter has a type
+    }
+
+    static int fdi = 0;
+    Logger::print("FuncDeclaration::toObjFile(%d,%s): %s\n", fdi++, needThis()?"this":"static",toChars());
+    LOG_SCOPE;
+
+    if (llvmInternal == LLVMintrinsic && fbody) {
+        error("intrinsics cannot have function bodies");
+        fatal();
+    }
+
+    TypeFunction* f = (TypeFunction*)type;
+    assert(f != 0);
+
+    // return value type
+    const llvm::Type* rettype;
+    const llvm::Type* actualRettype;
+    Type* rt = f->next;
+    bool retinptr = false;
+    bool usesthis = false;
+
+    if (isMain()) {
+        rettype = llvm::Type::Int32Ty;
+        actualRettype = rettype;
+        gIR->emitMain = true;
+    }
+    else if (rt) {
+        if (rt->ty == Tstruct || rt->ty == Tdelegate || rt->ty == Tarray) {
+            rettype = llvm::PointerType::get(LLVM_DtoType(rt));
+            actualRettype = llvm::Type::VoidTy;
+            f->llvmRetInPtr = retinptr = true;
+        }
+        else {
+            rettype = LLVM_DtoType(rt);
+            actualRettype = rettype;
+        }
+    }
+    else {
+        assert(0);
+    }
+
+    // parameter types
+    std::vector<const llvm::Type*> paramvec;
+
+    if (retinptr) {
+        Logger::print("returning through pointer parameter\n");
+        paramvec.push_back(rettype);
+    }
+
+    if (needThis()) {
+        if (AggregateDeclaration* ad = isMember()) {
+            Logger::print("isMember = this is: %s\n", ad->type->toChars());
+            const llvm::Type* thisty = LLVM_DtoType(ad->type);
+            if (llvm::isa<llvm::StructType>(thisty))
+                thisty = llvm::PointerType::get(thisty);
+            paramvec.push_back(thisty);
+            usesthis = true;
+        }
+        else
+        assert(0);
+    }
+
+    size_t n = Argument::dim(f->parameters);
+    for (int i=0; i < n; ++i) {
+        Argument* arg = Argument::getNth(f->parameters, i);
+        // ensure scalar
+        Type* argT = arg->type;
+        assert(argT);
+
+        if ((arg->storageClass & STCref) || (arg->storageClass & STCout)) {
+            //assert(arg->vardecl);
+            //arg->vardecl->refparam = true;
+        }
+        else
+            arg->llvmCopy = true;
+
+        const llvm::Type* at = LLVM_DtoType(argT);
+        if (llvm::isa<llvm::StructType>(at)) {
+            Logger::println("struct param");
+            paramvec.push_back(llvm::PointerType::get(at));
+        }
+        else if (llvm::isa<llvm::ArrayType>(at)) {
+            Logger::println("sarray param");
+            assert(argT->ty == Tsarray);
+            //paramvec.push_back(llvm::PointerType::get(at->getContainedType(0)));
+            paramvec.push_back(llvm::PointerType::get(at));
+        }
+        else {
+            if (!arg->llvmCopy) {
+                Logger::println("ref param");
+                at = llvm::PointerType::get(at);
+            }
+            else {
+                Logger::println("in param");
+            }
+            paramvec.push_back(at);
+        }
+    }
+    
+    // construct function
+    bool isvararg = f->varargs;
+    llvm::FunctionType* functype = llvm::FunctionType::get(actualRettype, paramvec, isvararg);
+    
+    // mangled name
+    char* mangled_name = (llvmInternal == LLVMintrinsic) ? llvmInternal1 : mangle();
+    llvm::Function* func = gIR->module->getFunction(mangled_name);
+    
+    // make the function
+    /*if (func != 0) {
+        llvmValue = func;
+        f->llvmType = functype;
+        return; // already pulled in from a forward declaration
+    }
+    else */
+    if (func == 0) {
+        func = new llvm::Function(functype,LLVM_DtoLinkage(protection, storage_class),mangled_name,gIR->module);
+    }
+
+    if (llvmInternal != LLVMintrinsic)
+        func->setCallingConv(LLVM_DtoCallingConv(f->linkage));
+
+    llvmValue = func;
+    f->llvmType = functype;
+
+    if (isMain()) {
+        gIR->mainFunc = func;
+    }
+
+    // name parameters
+    llvm::Function::arg_iterator iarg = func->arg_begin();
+    int k = 0;
+    int nunnamed = 0;
+    if (retinptr) {
+        iarg->setName("retval");
+        f->llvmRetArg = iarg;
+        ++iarg;
+    }
+    if (usesthis) {
+        iarg->setName("this");
+        ++iarg;
+    }
+    for (; iarg != func->arg_end(); ++iarg)
+    {
+        Argument* arg = Argument::getNth(f->parameters, k++);
+        //arg->llvmValue = iarg;
+        //printf("identifier: '%s' %p\n", arg->ident->toChars(), arg->ident);
+        if (arg->ident != 0) {
+            if (arg->vardecl) {
+                arg->vardecl->llvmValue = iarg;
+            }
+            iarg->setName(arg->ident->toChars());
+        }
+        else {
+            ++nunnamed;
+        }
+    }
+
+    // only members of the current module maybe be defined
+    if (getModule() == gIR->dmodule)
+    {
+        bool allow_fbody = true;
+        // handle static constructor / destructor
+        if (isStaticCtorDeclaration() || isStaticDtorDeclaration()) {
+            const llvm::ArrayType* sctor_type = llvm::ArrayType::get(llvm::PointerType::get(functype),1);
+            //Logger::cout() << "static ctor type: " << *sctor_type << '\n';
+            
+            llvm::Constant* sctor_func = llvm::cast<llvm::Constant>(llvmValue);
+            //Logger::cout() << "static ctor func: " << *sctor_func << '\n';
+            
+            llvm::Constant* sctor_init = 0;
+            if (llvmInternal == LLVMnull)
+            {
+                llvm::Constant* sctor_init_null = llvm::Constant::getNullValue(sctor_func->getType());
+                sctor_init = llvm::ConstantArray::get(sctor_type,&sctor_init_null,1);
+                allow_fbody = false;
+            }
+            else
+            {
+                sctor_init = llvm::ConstantArray::get(sctor_type,&sctor_func,1);
+            }
+            
+            //Logger::cout() << "static ctor init: " << *sctor_init << '\n';
+            
+            
+            // output the llvm.global_ctors array
+            const char* varname = isStaticCtorDeclaration() ? "_d_module_ctor_array" : "_d_module_dtor_array";
+            llvm::GlobalVariable* sctor_arr = new llvm::GlobalVariable(sctor_type, false, llvm::GlobalValue::AppendingLinkage, sctor_init, varname, gIR->module);
+        }
+
+        // function definition
+        if (allow_fbody && fbody != 0)
+        {
+            assert(nunnamed == 0);
+            gIR->funcs.push(func);
+            gIR->functypes.push(f);
+
+            IRScope irs;
+            irs.begin = new llvm::BasicBlock("entry",func);
+            irs.end = new llvm::BasicBlock("endentry",func);
+
+            //assert(gIR->scopes.empty());
+            gIR->scopes.push_back(irs);
+                
+                // create alloca point
+                f->llvmAllocaPoint = new llvm::BitCastInst(llvm::ConstantInt::get(llvm::Type::Int32Ty,0,false),llvm::Type::Int32Ty,"alloca point",gIR->scopebb());
+                
+                // output function body
+                fbody->toIR(gIR);
+
+                // llvm requires all basic blocks to end with a TerminatorInst but DMD does not put a return statement
+                // in automatically, so we do it here.
+                if (!isMain() && (gIR->scopebb()->empty() || !llvm::isa<llvm::TerminatorInst>(gIR->scopebb()->back()))) {
+                    // pass the previous block into this block
+                    //new llvm::BranchInst(irs.end, irs.begin);
+                    new llvm::ReturnInst(gIR->scopebb());
+                }
+                
+                // erase alloca point
+                f->llvmAllocaPoint->eraseFromParent();
+                f->llvmAllocaPoint = 0;
+
+            gIR->scopes.pop_back();
+            //assert(gIR->scopes.empty());
+
+            gIR->functypes.pop();
+            gIR->funcs.pop();
+
+            // get rid of the endentry block, it's never used
+            func->getBasicBlockList().pop_back();
+
+            // if the last block is empty now, it must be unreachable or it's a bug somewhere else
+            llvm::BasicBlock* lastbb = &func->getBasicBlockList().back();
+            if (lastbb->empty()) {
+                new llvm::UnreachableInst(lastbb);
+            }
+        }
+    }
+    else
+    {
+        Logger::println("only declaration");
+    }
+
+    llvmDModule = gIR->dmodule;
+
+    Logger::println("FuncDeclaration done\n");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen/typinf.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,403 @@
+
+
+// Copyright (c) 1999-2004 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <cstdio>
+#include <cassert>
+
+#include "mars.h"
+#include "module.h"
+#include "mtype.h"
+#include "scope.h"
+#include "init.h"
+#include "expression.h"
+#include "attrib.h"
+#include "declaration.h"
+#include "template.h"
+#include "id.h"
+#include "enum.h"
+#include "import.h"
+#include "aggregate.h"
+
+#include "logger.h"
+
+/*******************************************
+
+ * Get a canonicalized form of the TypeInfo for use with the internal
+
+ * runtime library routines. Canonicalized in that static arrays are
+
+ * represented as dynamic arrays, enums are represented by their
+
+ * underlying type, etc. This reduces the number of TypeInfo's needed,
+
+ * so we can use the custom internal ones more.
+
+ */
+
+
+
+Expression *Type::getInternalTypeInfo(Scope *sc)
+
+{   TypeInfoDeclaration *tid;
+
+    Expression *e;
+
+    Type *t;
+
+    static TypeInfoDeclaration *internalTI[TMAX];
+
+
+
+    //printf("Type::getInternalTypeInfo() %s\n", toChars());
+
+    t = toBasetype();
+
+    switch (t->ty)
+
+    {
+
+    case Tsarray:
+
+        t = t->next->arrayOf(); // convert to corresponding dynamic array type
+
+        break;
+
+
+
+    case Tclass:
+
+        if (((TypeClass *)t)->sym->isInterfaceDeclaration())
+
+        break;
+
+        goto Linternal;
+
+
+
+    case Tarray:
+
+        if (t->next->ty != Tclass)
+
+        break;
+
+        goto Linternal;
+
+
+
+    case Tfunction:
+
+    case Tdelegate:
+
+    case Tpointer:
+
+    Linternal:
+
+        tid = internalTI[t->ty];
+
+        if (!tid)
+
+        {   tid = new TypeInfoDeclaration(t, 1);
+
+        internalTI[t->ty] = tid;
+
+        }
+
+        e = new VarExp(0, tid);
+
+        e = e->addressOf(sc);
+
+        e->type = tid->type;    // do this so we don't get redundant dereference
+
+        return e;
+
+
+
+    default:
+
+        break;
+
+    }
+
+    //printf("\tcalling getTypeInfo() %s\n", t->toChars());
+
+    return t->getTypeInfo(sc);
+
+}
+
+
+
+
+
+/****************************************************
+
+ * Get the exact TypeInfo.
+
+ */
+
+
+
+Expression *Type::getTypeInfo(Scope *sc)
+
+{
+
+    Expression *e;
+
+    Type *t;
+
+
+
+    //printf("Type::getTypeInfo() %p, %s\n", this, toChars());
+
+    t = merge();    // do this since not all Type's are merge'd
+
+    if (!t->vtinfo)
+
+    {   t->vtinfo = t->getTypeInfoDeclaration();
+
+    assert(t->vtinfo);
+
+
+
+    /* If this has a custom implementation in std/typeinfo, then
+
+     * do not generate a COMDAT for it.
+
+     */
+
+    if (!t->builtinTypeInfo())
+
+    {   // Generate COMDAT
+
+        if (sc)         // if in semantic() pass
+
+        {   // Find module that will go all the way to an object file
+
+        Module *m = sc->module->importedFrom;
+
+        m->members->push(t->vtinfo);
+
+        }
+
+        else            // if in obj generation pass
+
+        {
+
+        t->vtinfo->toObjFile();
+
+        }
+
+    }
+
+    }
+
+    e = new VarExp(0, t->vtinfo);
+
+    //e = e->addressOf(sc);
+    e->type = t->vtinfo->type;      // do this so we don't get redundant dereference
+
+    return e;
+
+}
+
+
+
+TypeInfoDeclaration *Type::getTypeInfoDeclaration()
+
+{
+
+    //printf("Type::getTypeInfoDeclaration() %s\n", toChars());
+
+    return new TypeInfoDeclaration(this, 0);
+
+}
+
+
+
+TypeInfoDeclaration *TypeTypedef::getTypeInfoDeclaration()
+
+{
+
+    return new TypeInfoTypedefDeclaration(this);
+
+}
+
+
+
+TypeInfoDeclaration *TypePointer::getTypeInfoDeclaration()
+
+{
+
+    return new TypeInfoPointerDeclaration(this);
+
+}
+
+
+
+TypeInfoDeclaration *TypeDArray::getTypeInfoDeclaration()
+
+{
+
+    return new TypeInfoArrayDeclaration(this);
+
+}
+
+
+
+TypeInfoDeclaration *TypeSArray::getTypeInfoDeclaration()
+
+{
+
+    return new TypeInfoStaticArrayDeclaration(this);
+
+}
+
+
+
+TypeInfoDeclaration *TypeAArray::getTypeInfoDeclaration()
+
+{
+
+    return new TypeInfoAssociativeArrayDeclaration(this);
+
+}
+
+
+
+TypeInfoDeclaration *TypeStruct::getTypeInfoDeclaration()
+
+{
+
+    return new TypeInfoStructDeclaration(this);
+
+}
+
+
+
+TypeInfoDeclaration *TypeClass::getTypeInfoDeclaration()
+
+{
+
+    if (sym->isInterfaceDeclaration())
+
+    return new TypeInfoInterfaceDeclaration(this);
+
+    else
+
+    return new TypeInfoClassDeclaration(this);
+
+}
+
+
+
+TypeInfoDeclaration *TypeEnum::getTypeInfoDeclaration()
+
+{
+
+    return new TypeInfoEnumDeclaration(this);
+
+}
+
+
+
+TypeInfoDeclaration *TypeFunction::getTypeInfoDeclaration()
+
+{
+
+    return new TypeInfoFunctionDeclaration(this);
+
+}
+enum RET TypeFunction::retStyle()
+
+{
+
+    return RETstack;
+
+}
+
+
+TypeInfoDeclaration *TypeDelegate::getTypeInfoDeclaration()
+
+{
+
+    return new TypeInfoDelegateDeclaration(this);
+
+}
+
+
+
+TypeInfoDeclaration *TypeTuple::getTypeInfoDeclaration()
+
+{
+
+    return new TypeInfoTupleDeclaration(this);
+
+}
+
+
+void TypeInfoDeclaration::toDt(dt_t **pdt)
+{
+}
+
+void TypeInfoTypedefDeclaration::toDt(dt_t **pdt)
+{
+}
+
+void TypeInfoStructDeclaration::toDt(dt_t **pdt)
+{
+}
+
+void TypeInfoClassDeclaration::toDt(dt_t **pdt)
+{
+}
+
+void TypeInfoDeclaration::toObjFile()
+{
+    Logger::println("TypeInfoDeclaration::toObjFile()");
+    LOG_SCOPE;
+    Logger::println("type = '%s'", tinfo->toChars());
+
+    
+}
+
+/* ========================================================================= */
+
+/* These decide if there's an instance for them already in std.typeinfo,
+ * because then the compiler doesn't need to build one.
+ */
+
+int Type::builtinTypeInfo()
+{
+    return 0;
+}
+
+int TypeBasic::builtinTypeInfo()
+{
+    return 1;
+}
+
+int TypeDArray::builtinTypeInfo()
+{
+    return 0;
+}
+
+/* ========================================================================= */
+
+/***************************************
+ * Create a static array of TypeInfo references
+ * corresponding to an array of Expression's.
+ * Used to supply hidden _arguments[] value for variadic D functions.
+ */
+
+Expression *createTypeInfoArray(Scope *sc, Expression *args[], int dim)
+{
+    assert(0);
+    return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/build.sh	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+if [ "$1" = "gdb" ]; then
+dc_cmd="gdb --args llvmdmd"
+else
+dc_cmd="llvmdc"
+fi
+
+$dc_cmd internal/contract.d \
+        internal/arrays.d \
+        internal/moduleinit.d \
+        -c -noruntime -odobj || exit 1
+
+$dc_cmd internal/objectimpl.d -c -odobj || exit 1
+
+llvm-as -f -o=obj/moduleinit_backend.bc internal/moduleinit_backend.ll || exit 1
+
+llvm-link -f -o=obj/all.bc obj/contract.bc obj/arrays.bc obj/moduleinit.bc obj/objectimpl.bc obj/moduleinit_backend.bc || return 1
+
+opt -f -std-compile-opts -o=../lib/llvmdcore.bc obj/all.bc || exit 1
+
+if [ "$1" = "ll" ]; then
+    llvm-dis -f -o=all.ll ../lib/llvmdcore.bc || exit 1
+fi
+
+echo SUCCESS
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/clean.sh	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+rm *.bc *.s *.o
+rm ../lib/llvmdcore.bc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/crc32.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2001, 2002
+ * Pavel "EvilOne" Minayev
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation.  Author makes no representations about
+ * the suitability of this software for any purpose. It is provided
+ * "as is" without express or implied warranty.
+ */
+
+// CRC-32 calculation
+module crc32;
+
+private uint[256] crc32_table =
+[
+0x00000000,0x77073096,0xee0e612c,0x990951ba,0x076dc419,0x706af48f,0xe963a535,
+0x9e6495a3,0x0edb8832,0x79dcb8a4,0xe0d5e91e,0x97d2d988,0x09b64c2b,0x7eb17cbd,
+0xe7b82d07,0x90bf1d91,0x1db71064,0x6ab020f2,0xf3b97148,0x84be41de,0x1adad47d,
+0x6ddde4eb,0xf4d4b551,0x83d385c7,0x136c9856,0x646ba8c0,0xfd62f97a,0x8a65c9ec,
+0x14015c4f,0x63066cd9,0xfa0f3d63,0x8d080df5,0x3b6e20c8,0x4c69105e,0xd56041e4,
+0xa2677172,0x3c03e4d1,0x4b04d447,0xd20d85fd,0xa50ab56b,0x35b5a8fa,0x42b2986c,
+0xdbbbc9d6,0xacbcf940,0x32d86ce3,0x45df5c75,0xdcd60dcf,0xabd13d59,0x26d930ac,
+0x51de003a,0xc8d75180,0xbfd06116,0x21b4f4b5,0x56b3c423,0xcfba9599,0xb8bda50f,
+0x2802b89e,0x5f058808,0xc60cd9b2,0xb10be924,0x2f6f7c87,0x58684c11,0xc1611dab,
+0xb6662d3d,0x76dc4190,0x01db7106,0x98d220bc,0xefd5102a,0x71b18589,0x06b6b51f,
+0x9fbfe4a5,0xe8b8d433,0x7807c9a2,0x0f00f934,0x9609a88e,0xe10e9818,0x7f6a0dbb,
+0x086d3d2d,0x91646c97,0xe6635c01,0x6b6b51f4,0x1c6c6162,0x856530d8,0xf262004e,
+0x6c0695ed,0x1b01a57b,0x8208f4c1,0xf50fc457,0x65b0d9c6,0x12b7e950,0x8bbeb8ea,
+0xfcb9887c,0x62dd1ddf,0x15da2d49,0x8cd37cf3,0xfbd44c65,0x4db26158,0x3ab551ce,
+0xa3bc0074,0xd4bb30e2,0x4adfa541,0x3dd895d7,0xa4d1c46d,0xd3d6f4fb,0x4369e96a,
+0x346ed9fc,0xad678846,0xda60b8d0,0x44042d73,0x33031de5,0xaa0a4c5f,0xdd0d7cc9,
+0x5005713c,0x270241aa,0xbe0b1010,0xc90c2086,0x5768b525,0x206f85b3,0xb966d409,
+0xce61e49f,0x5edef90e,0x29d9c998,0xb0d09822,0xc7d7a8b4,0x59b33d17,0x2eb40d81,
+0xb7bd5c3b,0xc0ba6cad,0xedb88320,0x9abfb3b6,0x03b6e20c,0x74b1d29a,0xead54739,
+0x9dd277af,0x04db2615,0x73dc1683,0xe3630b12,0x94643b84,0x0d6d6a3e,0x7a6a5aa8,
+0xe40ecf0b,0x9309ff9d,0x0a00ae27,0x7d079eb1,0xf00f9344,0x8708a3d2,0x1e01f268,
+0x6906c2fe,0xf762575d,0x806567cb,0x196c3671,0x6e6b06e7,0xfed41b76,0x89d32be0,
+0x10da7a5a,0x67dd4acc,0xf9b9df6f,0x8ebeeff9,0x17b7be43,0x60b08ed5,0xd6d6a3e8,
+0xa1d1937e,0x38d8c2c4,0x4fdff252,0xd1bb67f1,0xa6bc5767,0x3fb506dd,0x48b2364b,
+0xd80d2bda,0xaf0a1b4c,0x36034af6,0x41047a60,0xdf60efc3,0xa867df55,0x316e8eef,
+0x4669be79,0xcb61b38c,0xbc66831a,0x256fd2a0,0x5268e236,0xcc0c7795,0xbb0b4703,
+0x220216b9,0x5505262f,0xc5ba3bbe,0xb2bd0b28,0x2bb45a92,0x5cb36a04,0xc2d7ffa7,
+0xb5d0cf31,0x2cd99e8b,0x5bdeae1d,0x9b64c2b0,0xec63f226,0x756aa39c,0x026d930a,
+0x9c0906a9,0xeb0e363f,0x72076785,0x05005713,0x95bf4a82,0xe2b87a14,0x7bb12bae,
+0x0cb61b38,0x92d28e9b,0xe5d5be0d,0x7cdcefb7,0x0bdbdf21,0x86d3d2d4,0xf1d4e242,
+0x68ddb3f8,0x1fda836e,0x81be16cd,0xf6b9265b,0x6fb077e1,0x18b74777,0x88085ae6,
+0xff0f6a70,0x66063bca,0x11010b5c,0x8f659eff,0xf862ae69,0x616bffd3,0x166ccf45,
+0xa00ae278,0xd70dd2ee,0x4e048354,0x3903b3c2,0xa7672661,0xd06016f7,0x4969474d,
+0x3e6e77db,0xaed16a4a,0xd9d65adc,0x40df0b66,0x37d83bf0,0xa9bcae53,0xdebb9ec5,
+0x47b2cf7f,0x30b5ffe9,0xbdbdf21c,0xcabac28a,0x53b39330,0x24b4a3a6,0xbad03605,
+0xcdd70693,0x54de5729,0x23d967bf,0xb3667a2e,0xc4614ab8,0x5d681b02,0x2a6f2b94,
+0xb40bbe37,0xc30c8ea1,0x5a05df1b,0x2d02ef8d
+];
+
+uint init_crc32()
+{
+	return cast(uint)-1;
+}
+
+uint update_crc32(ubyte val, uint crc)
+{
+	return crc32_table[cast(ubyte) crc ^ val] ^ (crc >> 8);
+}
+
+uint update_crc32(char val, uint crc)
+{
+	return update_crc32(cast(ubyte) val, crc);
+}
+
+uint strcrc32(char[] s)
+{
+	uint crc = init_crc32();
+	for (size_t i = 0; i < s.length; i++)
+		crc = update_crc32(s[i], crc);
+	return crc;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/dsss.conf	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,2 @@
+[std/typeinfo]
+type=library
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/gcstats.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,15 @@
+// Copyright (c) 1999-2002 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// www.digitalmars.com
+
+struct GCStats
+{
+    size_t poolsize;		// total size of pool
+    size_t usedsize;		// bytes allocated
+    size_t freeblocks;		// number of blocks marked FREE
+    size_t freelistsize;		// total of memory on free lists
+    size_t pageblocks;		// number of blocks marked PAGE
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/internal/arrays.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,67 @@
+module internal.arrays;
+
+extern(C):
+
+void _d_array_init_i1(bool* a, size_t n, bool v)
+{
+    auto p = a;
+    auto end = a+n;
+    while (p !is end)
+        *p++ = v;
+}
+
+void _d_array_init_i8(ubyte* a, size_t n, ubyte v)
+{
+    auto p = a;
+    auto end = a+n;
+    while (p !is end)
+        *p++ = v;
+}
+
+void _d_array_init_i16(ushort* a, size_t n, ushort v)
+{
+    auto p = a;
+    auto end = a+n;
+    while (p !is end)
+        *p++ = v;
+}
+
+void _d_array_init_i32(uint* a, size_t n, uint v)
+{
+    auto p = a;
+    auto end = a+n;
+    while (p !is end)
+        *p++ = v;
+}
+
+void _d_array_init_i64(ulong* a, size_t n, ulong v)
+{
+    auto p = a;
+    auto end = a+n;
+    while (p !is end)
+        *p++ = v;
+}
+
+void _d_array_init_float(float* a, size_t n, float v)
+{
+    auto p = a;
+    auto end = a+n;
+    while (p !is end)
+        *p++ = v;
+}
+
+void _d_array_init_double(double* a, size_t n, double v)
+{
+    auto p = a;
+    auto end = a+n;
+    while (p !is end)
+        *p++ = v;
+}
+
+void _d_array_init_pointer(void** a, size_t n, void* v)
+{
+    auto p = a;
+    auto end = a+n;
+    while (p !is end)
+        *p++ = v;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/internal/contract.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,13 @@
+module internal.contract;
+
+extern(C):
+
+void exit(int);
+
+void _d_assert(bool cond, uint line, char* msg)
+{
+    if (!cond) {
+        printf("Aborted(%u): %s\n", line, msg);
+        exit(1);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/internal/moduleinit.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,24 @@
+module internal.moduleinit;
+
+private alias extern(C) void function() fptr_t;
+
+extern(C):
+
+fptr_t* _d_get_module_ctors();
+fptr_t* _d_get_module_dtors();
+
+void _d_run_module_ctors()
+{
+    auto p = _d_get_module_ctors();
+    while(*p) {
+        (*p++)();
+    }
+}
+
+void _d_run_module_dtors()
+{
+    auto p = _d_get_module_dtors();
+    while(*p) {
+        (*p++)();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/internal/moduleinit_backend.ll	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,15 @@
+; ModuleID = 'internal.moduleinit_backend'
+@_d_module_ctor_array = appending global [1 x void ()*] zeroinitializer
+@_d_module_dtor_array = appending global [1 x void ()*] zeroinitializer
+
+define void ()** @_d_get_module_ctors() {
+entry:
+        %tmp = getelementptr [1 x void ()*]* @_d_module_ctor_array, i32 0, i32 0
+        ret void ()** %tmp
+}
+
+define void ()** @_d_get_module_dtors() {
+entry:
+        %tmp = getelementptr [1 x void ()*]* @_d_module_dtor_array, i32 0, i32 0
+        ret void ()** %tmp
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/internal/objectimpl.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,1075 @@
+
+/**
+ * Part of the D programming language runtime library.
+ * Forms the symbols available to all D programs. Includes
+ * Object, which is the root of the class object hierarchy.
+ *
+ * This module is implicitly imported.
+ * Macros:
+ *  WIKI = Phobos/Object
+ */
+
+/*
+ *  Copyright (C) 2004-2007 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+
+module object;
+
+//import std.outofmemory;
+
+extern (C)
+{   /// C's printf function.
+    int printf(char *, ...);
+
+    int memcmp(void *, void *, size_t);
+    void* memcpy(void *, void *, size_t);
+    void* calloc(size_t, size_t);
+    void* realloc(void*, size_t);
+    void free(void*);
+
+    //Object _d_newclass(ClassInfo ci);
+}
+
+/// Standard boolean type.
+alias bool bit;
+
+version (LLVM64)
+{
+    /**
+     * An unsigned integral type large enough to span the memory space. Use for
+     * array indices and pointer offsets for maximal portability to
+     * architectures that have different memory address ranges. This is
+     * analogous to C's size_t.
+     */
+    alias ulong size_t;
+
+    /**
+     * A signed integral type large enough to span the memory space. Use for
+     * pointer differences and for size_t differences for maximal portability to
+     * architectures that have different memory address ranges. This is
+     * analogous to C's ptrdiff_t.
+     */
+    alias long ptrdiff_t;
+
+    alias ulong hash_t;
+}
+else
+{
+    alias uint size_t;
+    alias int ptrdiff_t;
+    alias uint hash_t;
+}
+
+/+
+/* *************************
+ * Internal struct pointed to by the hidden .monitor member.
+ */
+struct Monitor
+{
+    void delegate(Object)[] delegates;
+
+    /* More stuff goes here defined by internal/monitor.c */
+}
++/
+
+/******************
+ * All D class objects inherit from Object.
+ */
+class Object
+{
+    void print()
+    {
+    char[] s = toString();
+    printf("%.*s\n", s.length, s.ptr);
+    }
+
+    /**
+     * Convert Object to a human readable string.
+     */
+    char[] toString()
+    {
+    //return this.classinfo.name;
+    return "classinfo.name not yet implemented";
+    }
+
+    /**
+     * Compute hash function for Object.
+     */
+    hash_t toHash()
+    {
+    // BUG: this prevents a compacting GC from working, needs to be fixed
+    return cast(uint)cast(void *)this;
+    }
+
+    /**
+     * Compare with another Object obj.
+     * Returns:
+     *  $(TABLE
+     *  $(TR $(TD this &lt; obj) $(TD &lt; 0))
+     *  $(TR $(TD this == obj) $(TD 0))
+     *  $(TR $(TD this &gt; obj) $(TD &gt; 0))
+     *  )
+     */
+    int opCmp(Object o)
+    {
+    // BUG: this prevents a compacting GC from working, needs to be fixed
+    //return cast(int)cast(void *)this - cast(int)cast(void *)o;
+
+    //throw new Error("need opCmp for class " ~ this.classinfo.name);
+    assert(0);
+    return 0;
+    }
+
+    /**
+     * Returns !=0 if this object does have the same contents as obj.
+     */
+    int opEquals(Object o)
+    {
+    return cast(int)(this is o);
+    }
+
+    /* **
+     * Call delegate dg, passing this to it, when this object gets destroyed.
+     * Use extreme caution, as the list of delegates is stored in a place
+     * not known to the gc. Thus, if any objects pointed to by one of these
+     * delegates gets freed by the gc, calling the delegate will cause a
+     * crash.
+     * This is only for use by library developers, as it will need to be
+     * redone if weak pointers are added or a moving gc is developed.
+     */
+    final void notifyRegister(void delegate(Object) dg)
+    {
+    //printf("notifyRegister(dg = %llx, o = %p)\n", dg, this);
+    /+synchronized (this)
+    {
+        Monitor* m = cast(Monitor*)(cast(void**)this)[1];
+        foreach (inout x; m.delegates)
+        {
+        if (!x || x == dg)
+        {   x = dg;
+            return;
+        }
+        }
+
+        // Increase size of delegates[]
+        auto len = m.delegates.length;
+        auto startlen = len;
+        if (len == 0)
+        {
+        len = 4;
+        auto p = calloc((void delegate(Object)).sizeof, len);
+        if (!p)
+            _d_OutOfMemory();
+        m.delegates = (cast(void delegate(Object)*)p)[0 .. len];
+        }
+        else
+        {
+        len += len + 4;
+        auto p = realloc(m.delegates.ptr, (void delegate(Object)).sizeof * len);
+        if (!p)
+            _d_OutOfMemory();
+        m.delegates = (cast(void delegate(Object)*)p)[0 .. len];
+        m.delegates[startlen .. len] = null;
+        }
+        m.delegates[startlen] = dg;
+    }+/
+    }
+
+    /* **
+     * Remove delegate dg from the notify list.
+     * This is only for use by library developers, as it will need to be
+     * redone if weak pointers are added or a moving gc is developed.
+     */
+    final void notifyUnRegister(void delegate(Object) dg)
+    {
+    /+synchronized (this)
+    {
+        Monitor* m = cast(Monitor*)(cast(void**)this)[1];
+        foreach (inout x; m.delegates)
+        {
+        if (x == dg)
+            x = null;
+        }
+    }+/
+    }
+
+    /******
+     * Create instance of class specified by classname.
+     * The class must either have no constructors or have
+     * a default constructor.
+     * Returns:
+     *  null if failed
+     */
+    static Object factory(char[] classname)
+    {
+    /+auto ci = ClassInfo.find(classname);
+    if (ci)
+    {
+        return ci.create();
+    }+/
+    return null;
+    }
+}
+
+/+
+extern (C) void _d_notify_release(Object o)
+{
+    //printf("_d_notify_release(o = %p)\n", o);
+    Monitor* m = cast(Monitor*)(cast(void**)o)[1];
+    if (m.delegates.length)
+    {
+    auto dgs = m.delegates;
+    synchronized (o)
+    {
+        dgs = m.delegates;
+        m.delegates = null;
+    }
+
+    foreach (dg; dgs)
+    {
+        if (dg)
+        {   //printf("calling dg = %llx (%p)\n", dg, o);
+        dg(o);
+        }
+    }
+
+    free(dgs.ptr);
+    }
+}
+
+
+/**
+ * Information about an interface.
+ * A pointer to this appears as the first entry in the interface's vtbl[].
+ */
+struct Interface
+{
+    ClassInfo classinfo;    /// .classinfo for this interface (not for containing class)
+    void *[] vtbl;
+    int offset;         /// offset to Interface 'this' from Object 'this'
+}
+
+import std.moduleinit;
+/**
+ * Runtime type information about a class. Can be retrieved for any class type
+ * or instance by using the .classinfo property.
+ * A pointer to this appears as the first entry in the class's vtbl[].
+ */
+class ClassInfo : Object
+{
+    byte[] init;        /** class static initializer
+                 * (init.length gives size in bytes of class)
+                 */
+    char[] name;        /// class name
+    void *[] vtbl;      /// virtual function pointer table
+    Interface[] interfaces; /// interfaces this class implements
+    ClassInfo base;     /// base class
+    void *destructor;
+    void (*classInvariant)(Object);
+    uint flags;
+    //  1:          // IUnknown
+    //  2:          // has no possible pointers into GC memory
+    //  4:          // has offTi[] member
+    //  8:          // has constructors
+    void *deallocator;
+    OffsetTypeInfo[] offTi;
+    void function(Object) defaultConstructor;   // default Constructor
+
+    /*************
+     * Search all modules for ClassInfo corresponding to classname.
+     * Returns: null if not found
+     */
+    static ClassInfo find(char[] classname)
+    {
+    foreach (m; ModuleInfo.modules())
+    {
+        //writefln("module %s, %d", m.name, m.localClasses.length);
+        foreach (c; m.localClasses)
+        {
+        //writefln("\tclass %s", c.name);
+        if (c.name == classname)
+            return c;
+        }
+    }
+    return null;
+    }
+
+    /********************
+     * Create instance of Object represented by 'this'.
+     */
+    Object create()
+    {
+    if (flags & 8 && !defaultConstructor)
+        return null;
+    Object o = _d_newclass(this);
+    if (flags & 8 && defaultConstructor)
+    {
+        defaultConstructor(o);
+    }
+    return o;
+    }
+}
+
+private import std.string;
+
+/**
+ * Array of pairs giving the offset and type information for each
+ * member in an aggregate.
+ */
+struct OffsetTypeInfo
+{
+    size_t offset;  /// Offset of member from start of object
+    TypeInfo ti;    /// TypeInfo for this member
+}
+
+
+/**
+ * Runtime type information about a type.
+ * Can be retrieved for any type using a
+ * <a href="../expression.html#typeidexpression">TypeidExpression</a>.
+ */
+class TypeInfo
+{
+    hash_t toHash()
+    {   hash_t hash;
+
+    foreach (char c; this.toString())
+        hash = hash * 9 + c;
+    return hash;
+    }
+
+    int opCmp(Object o)
+    {
+    if (this is o)
+        return 0;
+    TypeInfo ti = cast(TypeInfo)o;
+    if (ti is null)
+        return 1;
+    return std.string.cmp(this.toString(), ti.toString());
+    }
+
+    int opEquals(Object o)
+    {
+    /* TypeInfo instances are singletons, but duplicates can exist
+     * across DLL's. Therefore, comparing for a name match is
+     * sufficient.
+     */
+    if (this is o)
+        return 1;
+    TypeInfo ti = cast(TypeInfo)o;
+    return cast(int)(ti && this.toString() == ti.toString());
+    }
+
+    /// Returns a hash of the instance of a type.
+    hash_t getHash(void *p) { return cast(uint)p; }
+
+    /// Compares two instances for equality.
+    int equals(void *p1, void *p2) { return cast(int)(p1 == p2); }
+
+    /// Compares two instances for &lt;, ==, or &gt;.
+    int compare(void *p1, void *p2) { return 0; }
+
+    /// Returns size of the type.
+    size_t tsize() { return 0; }
+
+    /// Swaps two instances of the type.
+    void swap(void *p1, void *p2)
+    {
+    size_t n = tsize();
+    for (size_t i = 0; i < n; i++)
+    {   byte t;
+
+        t = (cast(byte *)p1)[i];
+        (cast(byte *)p1)[i] = (cast(byte *)p2)[i];
+        (cast(byte *)p2)[i] = t;
+    }
+    }
+
+    /// Get TypeInfo for 'next' type, as defined by what kind of type this is,
+    /// null if none.
+    TypeInfo next() { return null; }
+
+    /// Return default initializer, null if default initialize to 0
+    void[] init() { return null; }
+
+    /// Get flags for type: 1 means GC should scan for pointers
+    uint flags() { return 0; }
+
+    /// Get type information on the contents of the type; null if not available
+    OffsetTypeInfo[] offTi() { return null; }
+}
+
+class TypeInfo_Typedef : TypeInfo
+{
+    char[] toString() { return name; }
+
+    int opEquals(Object o)
+    {   TypeInfo_Typedef c;
+
+    return cast(int)
+        (this is o ||
+        ((c = cast(TypeInfo_Typedef)o) !is null &&
+         this.name == c.name &&
+         this.base == c.base));
+    }
+
+    hash_t getHash(void *p) { return base.getHash(p); }
+    int equals(void *p1, void *p2) { return base.equals(p1, p2); }
+    int compare(void *p1, void *p2) { return base.compare(p1, p2); }
+    size_t tsize() { return base.tsize(); }
+    void swap(void *p1, void *p2) { return base.swap(p1, p2); }
+
+    TypeInfo next() { return base.next(); }
+    uint flags() { return base.flags(); }
+    void[] init() { return m_init.length ? m_init : base.init(); }
+
+    TypeInfo base;
+    char[] name;
+    void[] m_init;
+}
+
+class TypeInfo_Enum : TypeInfo_Typedef
+{
+}
+
+class TypeInfo_Pointer : TypeInfo
+{
+    char[] toString() { return m_next.toString() ~ "*"; }
+
+    int opEquals(Object o)
+    {   TypeInfo_Pointer c;
+
+    return this is o ||
+        ((c = cast(TypeInfo_Pointer)o) !is null &&
+         this.m_next == c.m_next);
+    }
+
+    hash_t getHash(void *p)
+    {
+        return cast(uint)*cast(void* *)p;
+    }
+
+    int equals(void *p1, void *p2)
+    {
+        return cast(int)(*cast(void* *)p1 == *cast(void* *)p2);
+    }
+
+    int compare(void *p1, void *p2)
+    {
+    if (*cast(void* *)p1 < *cast(void* *)p2)
+        return -1;
+    else if (*cast(void* *)p1 > *cast(void* *)p2)
+        return 1;
+    else
+        return 0;
+    }
+
+    size_t tsize()
+    {
+    return (void*).sizeof;
+    }
+
+    void swap(void *p1, void *p2)
+    {   void* tmp;
+    tmp = *cast(void**)p1;
+    *cast(void**)p1 = *cast(void**)p2;
+    *cast(void**)p2 = tmp;
+    }
+
+    TypeInfo next() { return m_next; }
+    uint flags() { return 1; }
+
+    TypeInfo m_next;
+}
+
+class TypeInfo_Array : TypeInfo
+{
+    char[] toString() { return value.toString() ~ "[]"; }
+
+    int opEquals(Object o)
+    {   TypeInfo_Array c;
+
+    return cast(int)
+           (this is o ||
+        ((c = cast(TypeInfo_Array)o) !is null &&
+         this.value == c.value));
+    }
+
+    hash_t getHash(void *p)
+    {   size_t sz = value.tsize();
+    hash_t hash = 0;
+    void[] a = *cast(void[]*)p;
+    for (size_t i = 0; i < a.length; i++)
+        hash += value.getHash(a.ptr + i * sz);
+        return hash;
+    }
+
+    int equals(void *p1, void *p2)
+    {
+    void[] a1 = *cast(void[]*)p1;
+    void[] a2 = *cast(void[]*)p2;
+    if (a1.length != a2.length)
+        return 0;
+    size_t sz = value.tsize();
+    for (size_t i = 0; i < a1.length; i++)
+    {
+        if (!value.equals(a1.ptr + i * sz, a2.ptr + i * sz))
+        return 0;
+    }
+        return 1;
+    }
+
+    int compare(void *p1, void *p2)
+    {
+    void[] a1 = *cast(void[]*)p1;
+    void[] a2 = *cast(void[]*)p2;
+    size_t sz = value.tsize();
+    size_t len = a1.length;
+
+        if (a2.length < len)
+            len = a2.length;
+        for (size_t u = 0; u < len; u++)
+        {
+            int result = value.compare(a1.ptr + u * sz, a2.ptr + u * sz);
+            if (result)
+                return result;
+        }
+        return cast(int)a1.length - cast(int)a2.length;
+    }
+
+    size_t tsize()
+    {
+    return (void[]).sizeof;
+    }
+
+    void swap(void *p1, void *p2)
+    {   void[] tmp;
+    tmp = *cast(void[]*)p1;
+    *cast(void[]*)p1 = *cast(void[]*)p2;
+    *cast(void[]*)p2 = tmp;
+    }
+
+    TypeInfo value;
+
+    TypeInfo next()
+    {
+    return value;
+    }
+
+    uint flags() { return 1; }
+}
+
+class TypeInfo_StaticArray : TypeInfo
+{
+    char[] toString()
+    {
+    return value.toString() ~ "[" ~ std.string.toString(len) ~ "]";
+    }
+
+    int opEquals(Object o)
+    {   TypeInfo_StaticArray c;
+
+    return cast(int)
+           (this is o ||
+        ((c = cast(TypeInfo_StaticArray)o) !is null &&
+         this.len == c.len &&
+         this.value == c.value));
+    }
+
+    hash_t getHash(void *p)
+    {   size_t sz = value.tsize();
+    hash_t hash = 0;
+    for (size_t i = 0; i < len; i++)
+        hash += value.getHash(p + i * sz);
+        return hash;
+    }
+
+    int equals(void *p1, void *p2)
+    {
+    size_t sz = value.tsize();
+
+        for (size_t u = 0; u < len; u++)
+        {
+        if (!value.equals(p1 + u * sz, p2 + u * sz))
+        return 0;
+        }
+        return 1;
+    }
+
+    int compare(void *p1, void *p2)
+    {
+    size_t sz = value.tsize();
+
+        for (size_t u = 0; u < len; u++)
+        {
+            int result = value.compare(p1 + u * sz, p2 + u * sz);
+            if (result)
+                return result;
+        }
+        return 0;
+    }
+
+    size_t tsize()
+    {
+    return len * value.tsize();
+    }
+
+    void swap(void *p1, void *p2)
+    {   void* tmp;
+    size_t sz = value.tsize();
+    ubyte[16] buffer;
+    void* pbuffer;
+
+    if (sz < buffer.sizeof)
+        tmp = buffer.ptr;
+    else
+        tmp = pbuffer = (new void[sz]).ptr;
+
+    for (size_t u = 0; u < len; u += sz)
+    {   size_t o = u * sz;
+        memcpy(tmp, p1 + o, sz);
+        memcpy(p1 + o, p2 + o, sz);
+        memcpy(p2 + o, tmp, sz);
+    }
+    if (pbuffer)
+        delete pbuffer;
+    }
+
+    void[] init() { return value.init(); }
+    TypeInfo next() { return value; }
+    uint flags() { return value.flags(); }
+
+    TypeInfo value;
+    size_t len;
+}
+
+class TypeInfo_AssociativeArray : TypeInfo
+{
+    char[] toString()
+    {
+    return value.toString() ~ "[" ~ key.toString() ~ "]";
+    }
+
+    int opEquals(Object o)
+    {   TypeInfo_AssociativeArray c;
+
+    return this is o ||
+        ((c = cast(TypeInfo_AssociativeArray)o) !is null &&
+         this.key == c.key &&
+         this.value == c.value);
+    }
+
+    // BUG: need to add the rest of the functions
+
+    size_t tsize()
+    {
+    return (char[int]).sizeof;
+    }
+
+    TypeInfo next() { return value; }
+    uint flags() { return 1; }
+
+    TypeInfo value;
+    TypeInfo key;
+}
+
+class TypeInfo_Function : TypeInfo
+{
+    char[] toString()
+    {
+    return next.toString() ~ "()";
+    }
+
+    int opEquals(Object o)
+    {   TypeInfo_Function c;
+
+    return this is o ||
+        ((c = cast(TypeInfo_Function)o) !is null &&
+         this.next == c.next);
+    }
+
+    // BUG: need to add the rest of the functions
+
+    size_t tsize()
+    {
+    return 0;   // no size for functions
+    }
+
+    TypeInfo next;
+}
+
+class TypeInfo_Delegate : TypeInfo
+{
+    char[] toString()
+    {
+    return next.toString() ~ " delegate()";
+    }
+
+    int opEquals(Object o)
+    {   TypeInfo_Delegate c;
+
+    return this is o ||
+        ((c = cast(TypeInfo_Delegate)o) !is null &&
+         this.next == c.next);
+    }
+
+    // BUG: need to add the rest of the functions
+
+    size_t tsize()
+    {   alias int delegate() dg;
+    return dg.sizeof;
+    }
+
+    uint flags() { return 1; }
+
+    TypeInfo next;
+}
+
+class TypeInfo_Class : TypeInfo
+{
+    char[] toString() { return info.name; }
+
+    int opEquals(Object o)
+    {   TypeInfo_Class c;
+
+    return this is o ||
+        ((c = cast(TypeInfo_Class)o) !is null &&
+         this.info.name == c.classinfo.name);
+    }
+
+    hash_t getHash(void *p)
+    {
+    Object o = *cast(Object*)p;
+    assert(o);
+    return o.toHash();
+    }
+
+    int equals(void *p1, void *p2)
+    {
+    Object o1 = *cast(Object*)p1;
+    Object o2 = *cast(Object*)p2;
+
+    return (o1 is o2) || (o1 && o1.opEquals(o2));
+    }
+
+    int compare(void *p1, void *p2)
+    {
+    Object o1 = *cast(Object*)p1;
+    Object o2 = *cast(Object*)p2;
+    int c = 0;
+
+    // Regard null references as always being "less than"
+    if (o1 !is o2)
+    {
+        if (o1)
+        {   if (!o2)
+            c = 1;
+        else
+            c = o1.opCmp(o2);
+        }
+        else
+        c = -1;
+    }
+    return c;
+    }
+
+    size_t tsize()
+    {
+    return Object.sizeof;
+    }
+
+    uint flags() { return 1; }
+
+    OffsetTypeInfo[] offTi()
+    {
+    return (info.flags & 4) ? info.offTi : null;
+    }
+
+    ClassInfo info;
+}
+
+class TypeInfo_Interface : TypeInfo
+{
+    char[] toString() { return info.name; }
+
+    int opEquals(Object o)
+    {   TypeInfo_Interface c;
+
+    return this is o ||
+        ((c = cast(TypeInfo_Interface)o) !is null &&
+         this.info.name == c.classinfo.name);
+    }
+
+    hash_t getHash(void *p)
+    {
+    Interface* pi = **cast(Interface ***)*cast(void**)p;
+    Object o = cast(Object)(*cast(void**)p - pi.offset);
+    assert(o);
+    return o.toHash();
+    }
+
+    int equals(void *p1, void *p2)
+    {
+    Interface* pi = **cast(Interface ***)*cast(void**)p1;
+    Object o1 = cast(Object)(*cast(void**)p1 - pi.offset);
+    pi = **cast(Interface ***)*cast(void**)p2;
+    Object o2 = cast(Object)(*cast(void**)p2 - pi.offset);
+
+    return o1 == o2 || (o1 && o1.opCmp(o2) == 0);
+    }
+
+    int compare(void *p1, void *p2)
+    {
+    Interface* pi = **cast(Interface ***)*cast(void**)p1;
+    Object o1 = cast(Object)(*cast(void**)p1 - pi.offset);
+    pi = **cast(Interface ***)*cast(void**)p2;
+    Object o2 = cast(Object)(*cast(void**)p2 - pi.offset);
+    int c = 0;
+
+    // Regard null references as always being "less than"
+    if (o1 != o2)
+    {
+        if (o1)
+        {   if (!o2)
+            c = 1;
+        else
+            c = o1.opCmp(o2);
+        }
+        else
+        c = -1;
+    }
+    return c;
+    }
+
+    size_t tsize()
+    {
+    return Object.sizeof;
+    }
+
+    uint flags() { return 1; }
+
+    ClassInfo info;
+}
+
+class TypeInfo_Struct : TypeInfo
+{
+    char[] toString() { return name; }
+
+    int opEquals(Object o)
+    {   TypeInfo_Struct s;
+
+    return this is o ||
+        ((s = cast(TypeInfo_Struct)o) !is null &&
+         this.name == s.name &&
+         this.init.length == s.init.length);
+    }
+
+    hash_t getHash(void *p)
+    {   hash_t h;
+
+    assert(p);
+    if (xtoHash)
+    {   //printf("getHash() using xtoHash\n");
+        h = (*xtoHash)(p);
+    }
+    else
+    {
+        //printf("getHash() using default hash\n");
+        // A sorry hash algorithm.
+        // Should use the one for strings.
+        // BUG: relies on the GC not moving objects
+        for (size_t i = 0; i < init.length; i++)
+        {   h = h * 9 + *cast(ubyte*)p;
+        p++;
+        }
+    }
+    return h;
+    }
+
+    int equals(void *p2, void *p1)
+    {   int c;
+
+    if (p1 == p2)
+        c = 1;
+    else if (!p1 || !p2)
+        c = 0;
+    else if (xopEquals)
+        c = (*xopEquals)(p1, p2);
+    else
+        // BUG: relies on the GC not moving objects
+        c = (memcmp(p1, p2, init.length) == 0);
+    return c;
+    }
+
+    int compare(void *p2, void *p1)
+    {
+    int c = 0;
+
+    // Regard null references as always being "less than"
+    if (p1 != p2)
+    {
+        if (p1)
+        {   if (!p2)
+            c = 1;
+        else if (xopCmp)
+            c = (*xopCmp)(p1, p2);
+        else
+            // BUG: relies on the GC not moving objects
+            c = memcmp(p1, p2, init.length);
+        }
+        else
+        c = -1;
+    }
+    return c;
+    }
+
+    size_t tsize()
+    {
+    return init.length;
+    }
+
+    void[] init() { return m_init; }
+
+    uint flags() { return m_flags; }
+
+    char[] name;
+    void[] m_init;  // initializer; init.ptr == null if 0 initialize
+
+    hash_t function(void*) xtoHash;
+    int function(void*,void*) xopEquals;
+    int function(void*,void*) xopCmp;
+    char[] function(void*) xtoString;
+
+    uint m_flags;
+}
+
+class TypeInfo_Tuple : TypeInfo
+{
+    TypeInfo[] elements;
+
+    char[] toString()
+    {
+    char[] s;
+    s = "(";
+    foreach (i, element; elements)
+    {
+        if (i)
+        s ~= ',';
+        s ~= element.toString();
+    }
+    s ~= ")";
+        return s;
+    }
+
+    int opEquals(Object o)
+    {
+    if (this is o)
+        return 1;
+
+    auto t = cast(TypeInfo_Tuple)o;
+    if (t && elements.length == t.elements.length)
+    {
+        for (size_t i = 0; i < elements.length; i++)
+        {
+        if (elements[i] != t.elements[i])
+            return 0;
+        }
+        return 1;
+    }
+    return 0;
+    }
+
+    hash_t getHash(void *p)
+    {
+        assert(0);
+    }
+
+    int equals(void *p1, void *p2)
+    {
+        assert(0);
+    }
+
+    int compare(void *p1, void *p2)
+    {
+        assert(0);
+    }
+
+    size_t tsize()
+    {
+        assert(0);
+    }
+
+    void swap(void *p1, void *p2)
+    {
+        assert(0);
+    }
+}
+
+/**
+ * All recoverable exceptions should be derived from class Exception.
+ */
+class Exception : Object
+{
+    char[] msg;
+
+    /**
+     * Constructor; msg is a descriptive message for the exception.
+     */
+    this(char[] msg)
+    {
+    this.msg = msg;
+    }
+
+    void print()
+    {
+    printf("%.*s\n", toString());
+    }
+
+    char[] toString() { return msg; }
+}
+
+/**
+ * All irrecoverable exceptions should be derived from class Error.
+ */
+class Error : Exception
+{
+    Error next;
+
+    /**
+     * Constructor; msg is a descriptive message for the exception.
+     */
+    this(char[] msg)
+    {
+    super(msg);
+    }
+
+    this(char[] msg, Error next)
+    {
+    super(msg);
+    this.next = next;
+    }
+}
+
+//extern (C) int nullext = 0;
+
++/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/llvm/intrinsic.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,150 @@
+module llvm.intrinsic;
+
+// variable argument handling intrinsics
+pragma(LLVM_internal, "intrinsic", "llvm.va_start")
+    void llvm_va_start(void* args);
+
+pragma(LLVM_internal, "intrinsic", "llvm.va_end")
+    void llvm_va_end(void* args);
+
+pragma(LLVM_internal, "intrinsic", "llvm.va_copy")
+    void llvm_va_copy(void* dst, void* src);
+
+// code generator intrinsics
+/*
+pragma(LLVM_internal, "intrinsic", "llvm.returnaddress")
+    void* llvm_returnaddress(uint level);
+
+pragma(LLVM_internal, "intrinsic", "llvm.frameaddress")
+    void* llvm_frameaddress(uint level);
+
+pragma(LLVM_internal, "intrinsic", "llvm.stacksave")
+    void* llvm_stacksave();
+
+pragma(LLVM_internal, "intrinsic", "llvm.stackrestore")
+    void llvm_stackrestore(void* ptr);
+
+pragma(LLVM_internal, "intrinsic", "llvm.pcmarker")
+    void llvm_pcmarker(uint id);
+
+pragma(LLVM_internal, "intrinsic", "llvm.prefetch")
+    void llvm_prefetch(void* ptr, uint rw, uint locality);
+
+pragma(LLVM_internal, "intrinsic", "llvm.readcyclecounter")
+    ulong llvm_readcyclecounter();
+*/
+
+// standard C intrinsics
+pragma(LLVM_internal, "intrinsic", "llvm.memcpy.i32")
+    void llvm_memcpy_i32(void* dst, void* src, uint len, uint alignment);
+
+pragma(LLVM_internal, "intrinsic", "llvm.memcpy.i64")
+    void llvm_memcpy_i64(void* dst, void* src, ulong len, uint alignment);
+
+pragma(LLVM_internal, "intrinsic", "llvm.memmove.i32")
+    void llvm_memmove_i32(void* dst, void* src, uint len, uint alignment);
+
+pragma(LLVM_internal, "intrinsic", "llvm.memmove.i64")
+    void llvm_memmove_i64(void* dst, void* src, ulong len, int alignment);
+
+pragma(LLVM_internal, "intrinsic", "llvm.memset.i32")
+    void llvm_memset_i32(void* dst, ubyte val, uint len, uint alignment);
+
+pragma(LLVM_internal, "intrinsic", "llvm.memset.i64")
+    void llvm_memset_i64(void* dst, ubyte val, ulong len, uint alignment);
+
+pragma(LLVM_internal, "intrinsic", "llvm.sqrt.f32")
+    float llvm_sqrt(float val);
+
+pragma(LLVM_internal, "intrinsic", "llvm.sqrt.f64")
+{
+    double llvm_sqrt(double val);
+    real llvm_sqrt(real val);
+}
+
+pragma(LLVM_internal, "intrinsic", "llvm.powi.f32")
+    float llvm_powi(float val, int power);
+
+pragma(LLVM_internal, "intrinsic", "llvm.powi.f64")
+{
+    double llvm_powi(double val, int power);
+    real llvm_powi(real val, int power);
+}
+
+// bit manipulation intrinsics
+pragma(LLVM_internal, "intrinsic", "llvm.bswap.i16.i16")
+    ushort llvm_bswap(ushort val);
+
+pragma(LLVM_internal, "intrinsic", "llvm.bswap.i32.i32")
+    uint llvm_bswap(uint val);
+
+pragma(LLVM_internal, "intrinsic", "llvm.bswap.i64.i64")
+    ulong llvm_bswap(ulong val);
+
+/*
+pragma(LLVM_internal, "intrinsic", "llvm.ctpop.i8")
+    uint llvm_ctpop_i8(ubyte src);
+
+pragma(LLVM_internal, "intrinsic", "llvm.ctpop.i16")
+    uint llvm_ctpop_i16(ushort src);
+
+pragma(LLVM_internal, "intrinsic", "llvm.ctpop.i32")
+    uint llvm_ctpop_i32(uint src);
+
+pragma(LLVM_internal, "intrinsic", "llvm.ctpop.i64")
+    uint llvm_ctpop_i64(ulong src);
+
+pragma(LLVM_internal, "intrinsic", "llvm.ctlz.i8")
+    uint llvm_ctlz_i8(ubyte src);
+
+pragma(LLVM_internal, "intrinsic", "llvm.ctlz.i16")
+    uint llvm_ctlz_i16(ushort src);
+
+pragma(LLVM_internal, "intrinsic", "llvm.ctlz.i32")
+    uint llvm_ctlz_i32(uint src);
+
+pragma(LLVM_internal, "intrinsic", "llvm.ctlz.i64")
+    uint llvm_ctlz_i64(ulong src);
+
+pragma(LLVM_internal, "intrinsic", "llvm.cttz.i8")
+    uint llvm_cttz_i8(ubyte src);
+
+pragma(LLVM_internal, "intrinsic", "llvm.cttz.i16")
+    uint llvm_cttz_i16(ushort src);
+
+pragma(LLVM_internal, "intrinsic", "llvm.cttz.i32")
+    uint llvm_cttz_i32(uint src);
+
+pragma(LLVM_internal, "intrinsic", "llvm.cttz.i64")
+    uint llvm_cttz_i64(ulong src);
+*/
+
+// atomic operations and synchronization intrinsics
+// TODO
+/*
+
+//declare i8 @llvm.atomic.lcs.i8.i8p.i8.i8( i8* <ptr>, i8 <cmp>, i8 <val> )
+pragma(LLVM_internal, "intrinsic", "llvm.atomic.lcs.i8.i8p.i8.i8")
+    ubyte llvm_atomic_lcs_i8(void* ptr, ubyte cmp, ubyte val);
+
+declare i16 @llvm.atomic.lcs.i16.i16p.i16.i16( i16* <ptr>, i16 <cmp>, i16 <val> )
+declare i32 @llvm.atomic.lcs.i32.i32p.i32.i32( i32* <ptr>, i32 <cmp>, i32 <val> )
+declare i64 @llvm.atomic.lcs.i64.i64p.i64.i64( i64* <ptr>, i64 <cmp>, i64 <val> )
+
+declare i8 @llvm.atomic.ls.i8.i8p.i8( i8* <ptr>, i8 <val> )
+declare i16 @llvm.atomic.ls.i16.i16p.i16( i16* <ptr>, i16 <val> )
+declare i32 @llvm.atomic.ls.i32.i32p.i32( i32* <ptr>, i32 <val> )
+declare i64 @llvm.atomic.ls.i64.i64p.i64( i64* <ptr>, i64 <val> )
+
+declare i8 @llvm.atomic.las.i8.i8p.i8( i8* <ptr>, i8 <delta> )
+declare i16 @llvm.atomic.las.i16.i16p.i16( i16* <ptr>, i16 <delta> )
+declare i32 @llvm.atomic.las.i32.i32p.i32( i32* <ptr>, i32 <delta> )
+declare i64 @llvm.atomic.las.i64.i64p.i64( i64* <ptr>, i64 <delta> )
+
+declare i8 @llvm.atomic.lss.i8.i8.i8( i8* <ptr>, i8 <delta> )
+declare i16 @llvm.atomic.lss.i16.i16.i16( i16* <ptr>, i16 <delta> )
+declare i32 @llvm.atomic.lss.i32.i32.i32( i32* <ptr>, i32 <delta> )
+declare i64 @llvm.atomic.lss.i64.i64.i64( i64* <ptr>, i64 <delta> )
+
+declare void @llvm.memory.barrier( i1 <ll>, i1 <ls>, i1 <sl>, i1 <ss> )
+*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/object.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,164 @@
+
+// Implementation is in internal\object.d
+
+module object;
+
+//alias bit bool;
+alias bool bit;
+
+alias typeof(int.sizeof) size_t;
+alias typeof(cast(void*)0 - cast(void*)0) ptrdiff_t;
+alias size_t hash_t;
+
+extern (C)
+{   int printf(char *, ...);
+}
+
+class Object
+{
+    void print();
+    char[] toString();
+    hash_t toHash();
+    int opCmp(Object o);
+    int opEquals(Object o);
+
+    final void notifyRegister(void delegate(Object) dg);
+    final void notifyUnRegister(void delegate(Object) dg);
+}
+
+struct Interface
+{
+    ClassInfo classinfo;
+    void *[] vtbl;
+    ptrdiff_t offset;		// offset to Interface 'this' from Object 'this'
+}
+
+class ClassInfo : Object
+{
+    byte[] init;		// class static initializer
+    char[] name;		// class name
+    void *[] vtbl;		// virtual function pointer table
+    Interface[] interfaces;
+    ClassInfo base;
+    void *destructor;
+    void (*classInvariant)(Object);
+    uint flags;
+    //	1:			// IUnknown
+    //	2:			// has no possible pointers into GC memory
+    //	4:			// has offTi[] member
+    void *deallocator;
+    OffsetTypeInfo[] offTi;
+}
+
+struct OffsetTypeInfo
+{
+    size_t offset;
+    TypeInfo ti;
+}
+
+class TypeInfo
+{
+    hash_t getHash(void *p);
+    int equals(void *p1, void *p2);
+    int compare(void *p1, void *p2);
+    size_t tsize();
+    void swap(void *p1, void *p2);
+    TypeInfo next();
+    void[] init();
+    uint flags();
+    // 1:			// has possible pointers into GC memory
+    OffsetTypeInfo[] offTi();
+}
+
+class TypeInfo_Typedef : TypeInfo
+{
+    TypeInfo base;
+    char[] name;
+    void[] m_init;
+}
+
+class TypeInfo_Enum : TypeInfo_Typedef
+{
+}
+
+class TypeInfo_Pointer : TypeInfo
+{
+    TypeInfo m_next;
+}
+
+class TypeInfo_Array : TypeInfo
+{
+    TypeInfo value;
+}
+
+class TypeInfo_StaticArray : TypeInfo
+{
+    TypeInfo value;
+    size_t len;
+}
+
+class TypeInfo_AssociativeArray : TypeInfo
+{
+    TypeInfo value;
+    TypeInfo key;
+}
+
+class TypeInfo_Function : TypeInfo
+{
+    TypeInfo next;
+}
+
+class TypeInfo_Delegate : TypeInfo
+{
+    TypeInfo next;
+}
+
+class TypeInfo_Class : TypeInfo
+{
+    ClassInfo info;
+}
+
+class TypeInfo_Interface : TypeInfo
+{
+    ClassInfo info;
+}
+
+class TypeInfo_Struct : TypeInfo
+{
+    char[] name;
+    void[] m_init;
+
+    uint function(void*) xtoHash;
+    int function(void*,void*) xopEquals;
+    int function(void*,void*) xopCmp;
+    char[] function(void*) xtoString;
+
+    uint m_flags;
+}
+
+class TypeInfo_Tuple : TypeInfo
+{
+    TypeInfo[] elements;
+}
+
+// Recoverable errors
+
+class Exception : Object
+{
+    char[] msg;
+
+    this(char[] msg);
+    void print();
+    char[] toString();
+}
+
+// Non-recoverable errors
+
+class Error : Exception
+{
+    Error next;
+
+    this(char[] msg);
+    this(char[] msg, Error next);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/c/fenv.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,112 @@
+
+/**
+ * C's &lt;fenv.h&gt;
+ * Authors: Walter Bright, Digital Mars, www.digitalmars.com
+ * License: Public Domain
+ * Macros:
+ *	WIKI=Phobos/StdCFenv
+ */
+
+module std.c.fenv;
+
+extern (C):
+
+/// Entire floating point environment
+
+struct fenv_t
+{
+    version (Windows)
+    {
+	ushort status;
+	ushort control;
+	ushort round;
+	ushort reserved[2];
+    }
+    else version (linux)
+    {
+	ushort __control_word;
+	ushort __unused1;
+	ushort __status_word;
+	ushort __unused2;
+	ushort __tags;
+	ushort __unused3;
+	uint __eip;
+	ushort __cs_selector;
+	ushort __opcode;
+	uint __data_offset;
+	ushort __data_selector;
+	ushort __unused5;
+    }
+    else
+    {
+	static assert(0);
+    }
+}
+
+alias int fexcept_t;	/// Floating point status flags
+
+/// The various floating point exceptions
+enum
+{
+    FE_INVALID		= 1,		///
+    FE_DENORMAL		= 2,		///
+    FE_DIVBYZERO	= 4,		///
+    FE_OVERFLOW		= 8,		///
+    FE_UNDERFLOW	= 0x10,		///
+    FE_INEXACT		= 0x20,		///
+    FE_ALL_EXCEPT	= 0x3F,		/// Mask of all the exceptions
+}
+
+/// Rounding modes
+enum
+{
+    FE_TONEAREST	= 0,		///
+    FE_UPWARD		= 0x800,	///
+    FE_DOWNWARD		= 0x400,	///
+    FE_TOWARDZERO	= 0xC00,	///
+}
+
+version (Windows)
+{
+    extern fenv_t _FE_DFL_ENV;
+
+    /// Default floating point environment
+    fenv_t* FE_DFL_ENV = &_FE_DFL_ENV;
+}
+else version (linux)
+{
+    /// Default floating point environment
+    fenv_t* FE_DFL_ENV = cast(fenv_t*)(-1);
+}
+else
+{
+    static assert(0);
+}
+
+/// Floating point precision
+enum
+{
+    FE_FLTPREC	= 0,			///
+    FE_DBLPREC	= 0x200,		///
+    FE_LDBLPREC	= 0x300,		///
+}
+
+int fetestexcept(int excepts);		///
+int feraiseexcept(int excepts);		///
+int feclearexcept(int excepts);		///
+//int fegetexcept(fexcept_t *flagp,int excepts);	///
+//int fesetexcept(fexcept_t *flagp,int excepts);	///
+int fegetround();			///
+int fesetround(int round);		///
+int fegetprec();			///
+int fesetprec(int prec);		///
+int fegetenv(fenv_t *envp);		///
+int fesetenv(fenv_t *envp);		///
+//void feprocentry(fenv_t *envp);	///
+//void feprocexit(const fenv_t *envp);	///
+
+int fegetexceptflag(fexcept_t *flagp,int excepts);	///
+int fesetexceptflag(fexcept_t *flagp,int excepts);	///
+int feholdexcept(fenv_t *envp);		///
+int feupdateenv(fenv_t *envp);		///
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/c/linux/linux.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,478 @@
+
+/* Written by Walter Bright, Christopher E. Miller, and many others.
+ * www.digitalmars.com
+ * Placed into public domain.
+ * Linux(R) is the registered trademark of Linus Torvalds in the U.S. and other
+ * countries.
+ */
+
+module std.c.linux.linux;
+
+public import std.c.linux.linuxextern;
+public import std.c.linux.pthread;
+
+private import std.c.stdio;
+
+alias int pid_t;
+alias int off_t;
+alias uint mode_t;
+
+alias uint uid_t;
+alias uint gid_t;
+
+static if (size_t.sizeof == 4)
+    alias int ssize_t;
+else
+    alias long ssize_t;
+
+enum : int
+{
+	SIGHUP = 1,
+	SIGINT = 2,
+	SIGQUIT = 3,
+	SIGILL = 4,
+	SIGTRAP = 5,
+	SIGABRT = 6,
+	SIGIOT = 6,
+	SIGBUS = 7,
+	SIGFPE = 8,
+	SIGKILL = 9,
+	SIGUSR1 = 10,
+	SIGSEGV = 11,
+	SIGUSR2 = 12,
+	SIGPIPE = 13,
+	SIGALRM = 14,
+	SIGTERM = 15,
+	SIGSTKFLT = 16,
+	SIGCHLD = 17,
+	SIGCONT = 18,
+	SIGSTOP = 19,
+	SIGTSTP = 20,
+	SIGTTIN = 21,
+	SIGTTOU = 22,
+	SIGURG = 23,
+	SIGXCPU = 24,
+	SIGXFSZ = 25,
+	SIGVTALRM = 26,
+	SIGPROF = 27,
+	SIGWINCH = 28,
+	SIGPOLL = 29,
+	SIGIO = 29,
+	SIGPWR = 30,
+	SIGSYS = 31,
+	SIGUNUSED = 31,
+}
+
+enum
+{
+    O_RDONLY = 0,
+    O_WRONLY = 1,
+    O_RDWR = 2,
+    O_CREAT = 0100,
+    O_EXCL = 0200,
+    O_TRUNC = 01000,
+    O_APPEND = 02000,
+}
+
+struct struct_stat	// distinguish it from the stat() function
+{
+    ulong st_dev;	/// device
+    ushort __pad1;
+    uint st_ino;	/// file serial number
+    uint st_mode;	/// file mode
+    uint st_nlink;	/// link count
+    uint st_uid;	/// user ID of file's owner
+    uint st_gid;	/// user ID of group's owner
+    ulong st_rdev;	/// if device then device number
+    ushort __pad2;
+    int st_size;	/// file size in bytes
+    int st_blksize;	/// optimal I/O block size
+    int st_blocks;	/// number of allocated 512 byte blocks
+    int st_atime;
+    uint st_atimensec;
+    int st_mtime;
+    uint st_mtimensec;
+    int st_ctime;
+    uint st_ctimensec;
+
+    uint __unused4;
+    uint __unused5;
+}
+
+static assert(struct_stat.sizeof == 88);
+
+enum : int
+{
+    S_IFIFO  = 0010000,
+    S_IFCHR  = 0020000,
+    S_IFDIR  = 0040000,
+    S_IFBLK  = 0060000,
+    S_IFREG  = 0100000,
+    S_IFLNK  = 0120000,
+    S_IFSOCK = 0140000,
+
+    S_IFMT   = 0170000,
+
+    S_IREAD  = 0000400,
+    S_IWRITE = 0000200,
+    S_IEXEC  = 0000100,
+}
+
+extern (C)
+{
+    int access(char*, int);
+    int open(char*, int, ...);
+    int read(int, void*, int);
+    int write(int, void*, int);
+    int close(int);
+    int lseek(int, int, int);
+    int fstat(int, struct_stat*);
+    int lstat(char*, struct_stat*);
+    int stat(char*, struct_stat*);
+    int chdir(char*);
+    int mkdir(char*, int);
+    int rmdir(char*);
+    char* getcwd(char*, int);
+    int chmod(char*, mode_t);
+    int fork();
+    int dup(int);
+    int dup2(int, int);
+    int pipe(int[2]);
+    pid_t wait(int*);
+    int waitpid(pid_t, int*, int);
+
+    uint alarm(uint);
+    char* basename(char*);
+    //wint_t btowc(int);
+    int chown(char*, uid_t, gid_t);
+    int chroot(char*);
+    size_t confstr(int, char*, size_t);
+    int creat(char*, mode_t);
+    char* ctermid(char*);
+    int dirfd(DIR*);
+    char* dirname(char*);
+    int fattach(int, char*);
+    int fchmod(int, mode_t);
+    int fdatasync(int);
+    int ffs(int);
+    int fmtmsg(int, char*, int, char*, char*, char*);
+    int fpathconf(int, int);
+    int fseeko(FILE*, off_t, int);
+    off_t ftello(FILE*);
+
+    extern char** environ;
+}
+
+struct timeval
+{
+    int tv_sec;
+    int tv_usec;
+}
+
+struct struct_timezone
+{
+    int tz_minuteswest;
+    int tz_dstime;
+}
+
+struct tm
+{
+    int tm_sec;
+    int tm_min;
+    int tm_hour;
+    int tm_mday;
+    int tm_mon;
+    int tm_year;
+    int tm_wday;
+    int tm_yday;
+    int tm_isdst;
+    int tm_gmtoff;
+    int tm_zone;
+}
+
+extern (C)
+{
+    int gettimeofday(timeval*, struct_timezone*);
+    __time_t time(__time_t*);
+    char* asctime(tm*);
+    char* ctime(__time_t*);
+    tm* gmtime(__time_t*);
+    tm* localtime(__time_t*);
+    __time_t mktime(tm*);
+    char* asctime_r(tm* t, char* buf);
+    char* ctime_r(__time_t* timep, char* buf);
+    tm* gmtime_r(__time_t* timep, tm* result);
+    tm* localtime_r(__time_t* timep, tm* result);
+}
+
+/**************************************************************/
+// Memory mapping from <sys/mman.h> and <bits/mman.h>
+
+enum
+{
+	PROT_NONE	= 0,
+	PROT_READ	= 1,
+	PROT_WRITE	= 2,
+	PROT_EXEC	= 4,
+}
+
+// Memory mapping sharing types
+
+enum
+{	MAP_SHARED	= 1,
+	MAP_PRIVATE	= 2,
+	MAP_TYPE	= 0x0F,
+	MAP_FIXED	= 0x10,
+	MAP_FILE	= 0,
+	MAP_ANONYMOUS	= 0x20,
+	MAP_ANON	= 0x20,
+	MAP_GROWSDOWN	= 0x100,
+	MAP_DENYWRITE	= 0x800,
+	MAP_EXECUTABLE	= 0x1000,
+	MAP_LOCKED	= 0x2000,
+	MAP_NORESERVE	= 0x4000,
+	MAP_POPULATE	= 0x8000,
+	MAP_NONBLOCK	= 0x10000,
+}
+
+// Values for msync()
+
+enum
+{	MS_ASYNC	= 1,
+	MS_INVALIDATE	= 2,
+	MS_SYNC		= 4,
+}
+
+// Values for mlockall()
+
+enum
+{
+	MCL_CURRENT	= 1,
+	MCL_FUTURE	= 2,
+}
+
+// Values for mremap()
+
+enum
+{
+	MREMAP_MAYMOVE	= 1,
+}
+
+// Values for madvise
+
+enum
+{	MADV_NORMAL	= 0,
+	MADV_RANDOM	= 1,
+	MADV_SEQUENTIAL	= 2,
+	MADV_WILLNEED	= 3,
+	MADV_DONTNEED	= 4,
+}
+
+extern (C)
+{
+void* mmap(void*, size_t, int, int, int, off_t);
+const void* MAP_FAILED = cast(void*)-1;
+
+int munmap(void*, size_t);
+int mprotect(void*, size_t, int);
+int msync(void*, size_t, int);
+int madvise(void*, size_t, int);
+int mlock(void*, size_t);
+int munlock(void*, size_t);
+int mlockall(int);
+int munlockall();
+void* mremap(void*, size_t, size_t, int);
+int mincore(void*, size_t, ubyte*);
+int remap_file_pages(void*, size_t, int, size_t, int);
+int shm_open(char*, int, int);
+int shm_unlink(char*);
+}
+
+extern(C)
+{
+
+    enum
+    {
+	DT_UNKNOWN = 0,
+	DT_FIFO = 1,
+	DT_CHR = 2,
+	DT_DIR = 4,
+	DT_BLK = 6,
+	DT_REG = 8,
+	DT_LNK = 10,
+	DT_SOCK = 12,
+	DT_WHT = 14,
+    }
+
+    struct dirent
+    {
+	int d_ino;
+	off_t d_off;
+	ushort d_reclen;
+	ubyte d_type;
+	char[256] d_name;
+    }
+    
+    struct DIR
+    {
+	// Managed by OS.
+    }
+    
+    DIR* opendir(char* name);
+    int closedir(DIR* dir);
+    dirent* readdir(DIR* dir);
+    void rewinddir(DIR* dir);
+    off_t telldir(DIR* dir);
+    void seekdir(DIR* dir, off_t offset);
+}
+
+
+extern(C)
+{
+	private import std.intrinsic;
+	
+	
+	int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* errorfds, timeval* timeout);
+	int fcntl(int s, int f, ...);
+	
+	
+	enum
+	{
+		EINTR = 4,
+		EINPROGRESS = 115,
+	}
+	
+	
+	const uint FD_SETSIZE = 1024;
+	//const uint NFDBITS = 8 * int.sizeof; // DMD 0.110: 8 * (int).sizeof is not an expression
+	const int NFDBITS = 32;
+	
+	
+	struct fd_set
+	{
+		int[FD_SETSIZE / NFDBITS] fds_bits;
+		alias fds_bits __fds_bits;
+	}
+	
+	
+	int FDELT(int d)
+	{
+		return d / NFDBITS;
+	}
+	
+	
+	int FDMASK(int d)
+	{
+		return 1 << (d % NFDBITS);
+	}
+	
+	
+	// Removes.
+	void FD_CLR(int fd, fd_set* set)
+	{
+		btr(cast(uint*)&set.fds_bits.ptr[FDELT(fd)], cast(uint)(fd % NFDBITS));
+	}
+	
+	
+	// Tests.
+	int FD_ISSET(int fd, fd_set* set)
+	{
+		return bt(cast(uint*)&set.fds_bits.ptr[FDELT(fd)], cast(uint)(fd % NFDBITS));
+	}
+	
+	
+	// Adds.
+	void FD_SET(int fd, fd_set* set)
+	{
+		bts(cast(uint*)&set.fds_bits.ptr[FDELT(fd)], cast(uint)(fd % NFDBITS));
+	}
+	
+	
+	// Resets to zero.
+	void FD_ZERO(fd_set* set)
+	{
+		set.fds_bits[] = 0;
+	}
+}
+
+extern (C)
+{
+    /* From <dlfcn.h>
+     * See http://www.opengroup.org/onlinepubs/007908799/xsh/dlsym.html
+     */
+
+    const int RTLD_NOW = 0x00002;	// Correct for Red Hat 8
+
+    void* dlopen(char* file, int mode);
+    int   dlclose(void* handle);
+    void* dlsym(void* handle, char* name);
+    char* dlerror();
+}
+
+extern (C)
+{
+    /* from <pwd.h>
+     */
+
+    struct passwd
+    {
+	char *pw_name;
+	char *pw_passwd;
+	uid_t pw_uid;
+	gid_t pw_gid;
+	char *pw_gecos;
+	char *pw_dir;
+	char *pw_shell;
+    }
+
+    const size_t _SIGSET_NWORDS = 1024 / (8 * uint.sizeof);
+    struct sigset_t
+    {
+	uint[_SIGSET_NWORDS] __val;
+    }
+
+    int getpwnam_r(char*, passwd*, void*, size_t, passwd**);
+    passwd* getpwnam(char*);
+    passwd* getpwuid(uid_t);
+    int getpwuid_r(uid_t, passwd*, char*, size_t, passwd**);
+    int kill(pid_t, int);
+    int sem_close(sem_t*);
+    int sigemptyset(sigset_t*);
+    int sigfillset(sigset_t*);
+    int sigismember(sigset_t*, int);
+    int sigsuspend(sigset_t*);
+}
+
+extern (C)
+{
+    /* from semaphore.h
+     */
+
+    struct sem_t
+    {
+        _pthread_fastlock __sem_lock;
+        int __sem_value;
+        void* __sem_waiting;
+    }
+
+    int sem_init(sem_t*, int, uint);
+    int sem_wait(sem_t*);
+    int sem_trywait(sem_t*);
+    int sem_post(sem_t*);
+    int sem_getvalue(sem_t*, int*);
+    int sem_destroy(sem_t*);
+}
+
+extern (C)
+{
+    /* from utime.h
+     */
+
+    struct utimbuf
+    {
+	__time_t actime;
+	__time_t modtime;
+    }
+
+    int utime(char* filename, utimbuf* buf);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/c/linux/linuxextern.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,25 @@
+
+/* Written by Walter Bright.
+ * www.digitalmars.com
+ * Placed into public domain.
+ * Linux(R) is the registered trademark of Linus Torvalds in the U.S. and other
+ * countries.
+ */
+
+/* These are all the globals defined by the linux C runtime library.
+ * Put them separate so they'll be externed - do not link in linuxextern.o
+ */
+
+module std.c.linux.linuxextern;
+
+extern (C)
+{
+    void* __libc_stack_end;
+    int __data_start;
+    int _end;
+    int timezone;
+
+    void *_deh_beg;
+    void *_deh_end;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/c/linux/pthread.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,257 @@
+/* Written by Walter Bright, Christopher E. Miller, and many others.
+ * www.digitalmars.com
+ * Placed into public domain.
+ */
+
+module std.c.linux.pthread;
+
+extern (C)
+{
+    /*  pthread declarations taken from pthread headers and
+        http://svn.dsource.org/projects/bindings/trunk/pthreads.d
+    */
+
+    /* from bits/types.h
+    */
+
+    typedef int __time_t;
+
+    /* from time.h
+    */
+
+    struct timespec
+    {
+        __time_t tv_sec;    /* seconds   */
+        int tv_nsec;        /* nanosecs. */
+    }
+
+    /* from bits/pthreadtypes.h
+    */
+
+    alias uint pthread_t;
+    alias uint pthread_key_t;
+    alias int pthread_once_t;
+    alias int clockid_t;
+    alias int pthread_spinlock_t;	// volatile
+
+    struct _pthread_descr_struct
+    {
+    /*  Not defined in the headers ???
+        Just needed here to typedef
+        the _pthread_descr pointer
+    */
+    }
+
+    typedef _pthread_descr_struct* _pthread_descr;
+
+    struct _pthread_fastlock
+    {
+        int __status;
+        int __spinlock;
+    }
+
+    typedef long __pthread_cond_align_t;
+
+    struct pthread_cond_t 
+    {
+        _pthread_fastlock __c_lock;
+        _pthread_descr    __c_waiting;
+        char[48
+            - _pthread_fastlock.sizeof
+            - _pthread_descr.sizeof
+            - __pthread_cond_align_t.sizeof
+            ] __padding;
+        __pthread_cond_align_t __align;
+    }
+
+    struct pthread_condattr_t
+    {
+        int __dummy;
+    }
+
+    struct pthread_mutex_t
+    {
+        int         __m_reserved;
+        int         __m_count;
+        _pthread_descr  __m_owner;
+        int         __m_kind;
+        _pthread_fastlock __m_lock;
+    }
+
+    struct pthread_mutexattr_t
+    {
+        int __mutexkind;
+    }
+
+    /* from pthread.h
+    */
+
+    struct _pthread_cleanup_buffer
+    {
+	void function(void*) __routine;
+	void* __arg;
+	int __canceltype;
+	_pthread_cleanup_buffer* __prev;
+    }
+
+    struct __sched_param		// bits/sched.h
+    {
+	int __sched_priority;
+    }
+
+    struct pthread_attr_t
+    {
+	int __detachstate;
+	int __schedpolicy;
+	__sched_param schedparam;
+	int __inheritshed;
+	int __scope;
+	size_t __guardsize;
+	int __stackaddr_set;
+	void* __stackaddr;
+	size_t __stacksize;
+    }
+
+    struct pthread_barrier_t
+    {
+	_pthread_fastlock __ba_lock;
+	int __ba_required;
+	int __ba_present;
+	_pthread_descr __ba_waiting;
+    }
+
+    struct pthread_barrierattr_t
+    {
+	int __pshared;
+    }
+
+    struct pthread_rwlockattr_t
+    {
+	int __lockkind;
+	int __pshared;
+    }
+
+    struct pthread_rwlock_t
+    {
+	_pthread_fastlock __rw_lock;
+	int __rw_readers;
+	_pthread_descr __rw_writer;
+	_pthread_descr __rw_read_waiting;
+	_pthread_descr __rw_write_waiting;
+	int __rw_kind;
+	int __rw_pshared;
+    }
+
+    int pthread_mutex_init(pthread_mutex_t*, pthread_mutexattr_t*);
+    int pthread_mutex_destroy(pthread_mutex_t*);
+    int pthread_mutex_trylock(pthread_mutex_t*);
+    int pthread_mutex_lock(pthread_mutex_t*);
+    int pthread_mutex_unlock(pthread_mutex_t*);
+
+    int pthread_mutexattr_init(pthread_mutexattr_t*);
+    int pthread_mutexattr_destroy(pthread_mutexattr_t*);
+
+    int pthread_cond_init(pthread_cond_t*, pthread_condattr_t*);
+    int pthread_cond_destroy(pthread_cond_t*);
+    int pthread_cond_signal(pthread_cond_t*);
+    int pthread_cond_wait(pthread_cond_t*, pthread_mutex_t*);
+    int pthread_cond_timedwait(pthread_cond_t*, pthread_mutex_t*, timespec*);
+
+    int pthread_attr_init(pthread_attr_t*);
+    int pthread_attr_destroy(pthread_attr_t*);
+    int pthread_attr_setdetachstate(pthread_attr_t*, int);
+    int pthread_attr_getdetachstate(pthread_attr_t*, int*);
+    int pthread_attr_setinheritsched(pthread_attr_t*, int);
+    int pthread_attr_getinheritsched(pthread_attr_t*, int*);
+    int pthread_attr_setschedparam(pthread_attr_t*, __sched_param*);
+    int pthread_attr_getschedparam(pthread_attr_t*, __sched_param*);
+    int pthread_attr_setschedpolicy(pthread_attr_t*, int);
+    int pthread_attr_getschedpolicy(pthread_attr_t*, int*);
+    int pthread_attr_setscope(pthread_attr_t*, int);
+    int pthread_attr_getscope(pthread_attr_t*, int*);
+    int pthread_attr_setguardsize(pthread_attr_t*, size_t);
+    int pthread_attr_getguardsize(pthread_attr_t*, size_t*);
+    int pthread_attr_setstack(pthread_attr_t*, void*, size_t);
+    int pthread_attr_getstack(pthread_attr_t*, void**, size_t*);
+    int pthread_attr_setstackaddr(pthread_attr_t*, void*);
+    int pthread_attr_getstackaddr(pthread_attr_t*, void**);
+    int pthread_attr_setstacksize(pthread_attr_t*, size_t);
+    int pthread_attr_getstacksize(pthread_attr_t*, size_t*);
+
+    int pthread_barrierattr_init(pthread_barrierattr_t*);
+    int pthread_barrierattr_getpshared(pthread_barrierattr_t*, int*);
+    int pthread_barrierattr_destroy(pthread_barrierattr_t*);
+    int pthread_barrierattr_setpshared(pthread_barrierattr_t*, int);
+
+    int pthread_barrier_init(pthread_barrier_t*, pthread_barrierattr_t*, uint);
+    int pthread_barrier_destroy(pthread_barrier_t*);
+    int pthread_barrier_wait(pthread_barrier_t*);
+
+    int pthread_condattr_init(pthread_condattr_t*);
+    int pthread_condattr_destroy(pthread_condattr_t*);
+    int pthread_condattr_getpshared(pthread_condattr_t*, int*);
+    int pthread_condattr_setpshared(pthread_condattr_t*, int);
+
+    int pthread_detach(pthread_t);
+    void pthread_exit(void*);
+    int pthread_getattr_np(pthread_t, pthread_attr_t*);
+    int pthread_getconcurrency();
+    int pthread_getcpuclockid(pthread_t, clockid_t*);
+
+    int pthread_mutexattr_getpshared(pthread_mutexattr_t*, int*);
+    int pthread_mutexattr_setpshared(pthread_mutexattr_t*, int);
+    int pthread_mutexattr_settype(pthread_mutexattr_t*, int);
+    int pthread_mutexattr_gettype(pthread_mutexattr_t*, int*);
+    int pthread_mutex_timedlock(pthread_mutex_t*, timespec*);
+    int pthread_yield();
+
+    int pthread_rwlock_init(pthread_rwlock_t*, pthread_rwlockattr_t*);
+    int pthread_rwlock_destroy(pthread_rwlock_t*);
+    int pthread_rwlock_rdlock(pthread_rwlock_t*);
+    int pthread_rwlock_tryrdlock(pthread_rwlock_t*);
+    int pthread_rwlock_timedrdlock(pthread_rwlock_t*, timespec*);
+    int pthread_rwlock_wrlock(pthread_rwlock_t*);
+    int pthread_rwlock_trywrlock(pthread_rwlock_t*);
+    int pthread_rwlock_timedwrlock(pthread_rwlock_t*, timespec*);
+    int pthread_rwlock_unlock(pthread_rwlock_t*);
+
+    int pthread_rwlockattr_init(pthread_rwlockattr_t*);
+    int pthread_rwlockattr_destroy(pthread_rwlockattr_t*);
+    int pthread_rwlockattr_getpshared(pthread_rwlockattr_t*, int*);
+    int pthread_rwlockattr_setpshared(pthread_rwlockattr_t*, int);
+    int pthread_rwlockattr_getkind_np(pthread_rwlockattr_t*, int*);
+    int pthread_rwlockattr_setkind_np(pthread_rwlockattr_t*, int);
+
+    int pthread_spin_init(pthread_spinlock_t*, int);
+    int pthread_spin_destroy(pthread_spinlock_t*);
+    int pthread_spin_lock(pthread_spinlock_t*);
+    int pthread_spin_trylock(pthread_spinlock_t*);
+    int pthread_spin_unlock(pthread_spinlock_t*);
+
+    int pthread_cancel(pthread_t);
+    void pthread_testcancel();
+    int pthread_once(pthread_once_t*, void function());
+
+    int pthread_join(pthread_t, void**);
+    int pthread_create(pthread_t*, pthread_attr_t*, void*function(void*), void*);
+    pthread_t pthread_self();
+    int pthread_equal(pthread_t, pthread_t);
+    int pthread_atfork(void function(), void function(), void function());
+    void pthread_kill_other_threads_np();
+    int pthread_setschedparam(pthread_t, int, __sched_param*);
+    int pthread_getschedparam(pthread_t, int*, __sched_param*);
+    int pthread_cond_broadcast(pthread_cond_t*);
+    int pthread_key_create(pthread_key_t*, void function(void*));
+    int pthread_key_delete(pthread_key_t);
+    int pthread_setconcurrency(int);
+    int pthread_setspecific(pthread_key_t, void*);
+    void* pthread_getspecific(pthread_key_t);
+    int pthread_setcanceltype(int, int*);
+    int pthread_setcancelstate(int, int*);
+
+    void _pthread_cleanup_push(_pthread_cleanup_buffer*, void function(void*), void*);
+    void _pthread_cleanup_push_defer(_pthread_cleanup_buffer*, void function(void*), void*);
+    void _pthread_cleanup_pop(_pthread_cleanup_buffer*, int);
+    void _pthread_cleanup_pop_restore(_pthread_cleanup_buffer*, int);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/c/linux/socket.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,396 @@
+/*
+	Written by Christopher E. Miller
+	Placed into public domain.
+*/
+
+
+module std.c.linux.socket;
+
+private import std.stdint;
+
+
+extern(C):
+
+alias int socklen_t;
+
+const int F_GETFL =       3;
+const int F_SETFL =       4;
+const int O_NONBLOCK =    0x800;
+
+
+int socket(int af, int type, int protocol);
+int bind(int s, sockaddr* name, int namelen);
+int connect(int s, sockaddr* name, int namelen);
+int listen(int s, int backlog);
+int accept(int s, sockaddr* addr, int* addrlen);
+int shutdown(int s, int how);
+int getpeername(int s, sockaddr* name, int* namelen);
+int getsockname(int s, sockaddr* name, int* namelen);
+int send(int s, void* buf, int len, int flags);
+int sendto(int s, void* buf, int len, int flags, sockaddr* to, int tolen);
+int recv(int s, void* buf, int len, int flags);
+int recvfrom(int s, void* buf, int len, int flags, sockaddr* from, int* fromlen);
+int getsockopt(int s, int level, int optname, void* optval, int* optlen);
+int setsockopt(int s, int level, int optname, void* optval, int optlen);
+uint inet_addr(char* cp);
+char* inet_ntoa(in_addr ina);
+hostent* gethostbyname(char* name);
+int gethostbyname_r(char* name, hostent* ret, void* buf, size_t buflen, hostent** result, int* h_errnop);
+int gethostbyname2_r(char* name, int af, hostent* ret, void* buf, size_t buflen, hostent** result, int* h_errnop);
+hostent* gethostbyaddr(void* addr, int len, int type);
+protoent* getprotobyname(char* name);
+protoent* getprotobynumber(int number);
+servent* getservbyname(char* name, char* proto);
+servent* getservbyport(int port, char* proto);
+int gethostname(char* name, int namelen);
+int getaddrinfo(char* nodename, char* servname, addrinfo* hints, addrinfo** res);
+void freeaddrinfo(addrinfo* ai);
+int getnameinfo(sockaddr* sa, socklen_t salen, char* node, socklen_t nodelen, char* service, socklen_t servicelen, int flags);
+
+
+
+enum: int
+{
+	AF_UNSPEC =     0,
+	AF_UNIX =       1,
+	AF_INET =       2,
+	AF_IPX =        4,
+	AF_APPLETALK =  5,
+	AF_INET6 =      10,
+	// ...
+	
+	PF_UNSPEC =     AF_UNSPEC,
+	PF_UNIX =       AF_UNIX,
+	PF_INET =       AF_INET,
+	PF_IPX =        AF_IPX,
+	PF_APPLETALK =  AF_APPLETALK,
+	PF_INET6 =      AF_INET6,
+}
+
+
+version(X86)
+    version=SOL_SOCKET_IS_1;
+else version(X86_64)
+    version=SOL_SOCKET_IS_1;
+else version(PPC)
+    version=SOL_SOCKET_IS_1;
+else version(PPC64)
+    version=SOL_SOCKET_IS_1;
+else
+    static assert(0, "Unsupported architecture");
+
+version(SOL_SOCKET_IS_1)
+{
+	enum: int
+	{
+		SOL_SOCKET =  1,
+	}
+}
+else
+{
+	// Different values on other platforms.
+	static assert(0);
+}
+
+
+enum: int
+{
+	SO_DEBUG =       1,
+	SO_BROADCAST =   6,
+	SO_REUSEADDR =   2,
+	SO_LINGER =      13,
+	SO_DONTLINGER =  ~SO_LINGER,
+	SO_OOBINLINE =   10,
+	SO_SNDBUF =      7,
+	SO_RCVBUF =      8,
+	SO_ACCEPTCONN =  30,
+	SO_DONTROUTE =   5,
+	SO_TYPE =        3,
+	
+	TCP_NODELAY =    1,
+	
+	IP_MULTICAST_LOOP =  34,
+	IP_ADD_MEMBERSHIP =  35,
+	IP_DROP_MEMBERSHIP = 36,
+	
+	// ...
+	
+	IPV6_ADDRFORM =        1,
+	IPV6_PKTINFO =         2,
+	IPV6_HOPOPTS =         3,
+	IPV6_DSTOPTS =         4,
+	IPV6_RTHDR =           5,
+	IPV6_PKTOPTIONS =      6,
+	IPV6_CHECKSUM =        7,
+	IPV6_HOPLIMIT =        8,
+	IPV6_NEXTHOP =         9,
+	IPV6_AUTHHDR =         10,
+	IPV6_UNICAST_HOPS =    16,
+	IPV6_MULTICAST_IF =    17,
+	IPV6_MULTICAST_HOPS =  18,
+	IPV6_MULTICAST_LOOP =  19,
+	IPV6_JOIN_GROUP =      20,
+	IPV6_LEAVE_GROUP =     21,
+	IPV6_ROUTER_ALERT =    22,
+	IPV6_MTU_DISCOVER =    23,
+	IPV6_MTU =             24,
+	IPV6_RECVERR =         25,
+	IPV6_V6ONLY =          26,
+	IPV6_JOIN_ANYCAST =    27,
+	IPV6_LEAVE_ANYCAST =   28,
+	IPV6_IPSEC_POLICY =    34,
+	IPV6_XFRM_POLICY =     35,
+}
+
+
+struct linger
+{
+	int32_t l_onoff;
+	int32_t l_linger;
+}
+
+
+struct protoent
+{
+	char* p_name;
+	char** p_aliases;
+	int32_t p_proto;
+}
+
+
+struct servent
+{
+	char* s_name;
+	char** s_aliases;
+	int32_t s_port;
+	char* s_proto;
+}
+
+
+version(BigEndian)
+{
+	uint16_t htons(uint16_t x)
+	{
+		return x;
+	}
+	
+	
+	uint32_t htonl(uint32_t x)
+	{
+		return x;
+	}
+}
+else version(LittleEndian)
+{
+	private import std.intrinsic;
+	
+	
+	uint16_t htons(uint16_t x)
+	{
+		return cast(uint16_t)((x >> 8) | (x << 8));
+	}
+
+
+	uint32_t htonl(uint32_t x)
+	{
+		return bswap(x);
+	}
+}
+else
+{
+	static assert(0);
+}
+
+
+uint16_t ntohs(uint16_t x)
+{
+	return htons(x);
+}
+
+
+uint32_t ntohl(uint32_t x)
+{
+	return htonl(x);
+}
+
+
+enum: int
+{
+	SOCK_STREAM =     1,
+	SOCK_DGRAM =      2,
+	SOCK_RAW =        3,
+	SOCK_RDM =        4,
+	SOCK_SEQPACKET =  5,
+}
+
+
+enum: int
+{
+	IPPROTO_IP =    0,
+	IPPROTO_ICMP =  1,
+	IPPROTO_IGMP =  2,
+	IPPROTO_GGP =   3,
+	IPPROTO_TCP =   6,
+	IPPROTO_PUP =   12,
+	IPPROTO_UDP =   17,
+	IPPROTO_IDP =   22,
+	IPPROTO_IPV6 =  41,
+	IPPROTO_ND =    77,
+	IPPROTO_RAW =   255,
+	
+	IPPROTO_MAX =   256,
+}
+
+
+enum: int
+{
+	MSG_OOB =        0x1,
+	MSG_PEEK =       0x2,
+	MSG_DONTROUTE =  0x4,
+}
+
+
+enum: int
+{
+	SD_RECEIVE =  0,
+	SD_SEND =     1,
+	SD_BOTH =     2,
+}
+
+
+enum: uint
+{
+	INADDR_ANY =        0,
+	INADDR_LOOPBACK =   0x7F000001,
+	INADDR_BROADCAST =  0xFFFFFFFF,
+	INADDR_NONE =       0xFFFFFFFF,
+	ADDR_ANY =          INADDR_ANY,
+}
+
+
+enum: int
+{
+	AI_PASSIVE = 0x1,
+	AI_CANONNAME = 0x2,
+	AI_NUMERICHOST = 0x4,
+}
+
+
+union in_addr
+{
+	private union _S_un_t
+	{
+		private struct _S_un_b_t
+		{
+			uint8_t s_b1, s_b2, s_b3, s_b4;
+		}
+		_S_un_b_t S_un_b;
+		
+		private struct _S_un_w_t
+		{
+			uint16_t s_w1, s_w2;
+		}
+		_S_un_w_t S_un_w;
+		
+		uint32_t S_addr;
+	}
+	_S_un_t S_un;
+	
+	uint32_t s_addr;
+	
+	struct
+	{
+		uint8_t s_net, s_host;
+		
+		union
+		{
+			uint16_t s_imp;
+			
+			struct
+			{
+				uint8_t s_lh, s_impno;
+			}
+		}
+	}
+}
+
+
+union in6_addr
+{
+	private union _in6_u_t
+	{
+		uint8_t[16] u6_addr8;
+		uint16_t[8] u6_addr16;
+		uint32_t[4] u6_addr32;
+	}
+	_in6_u_t in6_u;
+	
+	uint8_t[16] s6_addr8;
+	uint16_t[8] s6_addr16;
+	uint32_t[4] s6_addr32;
+}
+
+
+const in6_addr IN6ADDR_ANY = { s6_addr8: [0] };
+const in6_addr IN6ADDR_LOOPBACK = { s6_addr8: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1] };
+//alias IN6ADDR_ANY IN6ADDR_ANY_INIT;
+//alias IN6ADDR_LOOPBACK IN6ADDR_LOOPBACK_INIT;
+	
+const uint INET_ADDRSTRLEN = 16;
+const uint INET6_ADDRSTRLEN = 46;
+
+
+struct sockaddr
+{
+	int16_t sa_family;               
+	ubyte[14] sa_data;             
+}
+
+
+struct sockaddr_in
+{
+	int16_t sin_family = AF_INET;
+	uint16_t sin_port;
+	in_addr sin_addr;
+	ubyte[8] sin_zero;
+}
+
+
+struct sockaddr_in6
+{
+	int16_t sin6_family = AF_INET6;
+	uint16_t sin6_port;
+	uint32_t sin6_flowinfo;
+	in6_addr sin6_addr;
+	uint32_t sin6_scope_id;
+}
+
+
+struct addrinfo
+{
+	int32_t ai_flags; 
+	int32_t ai_family;
+	int32_t ai_socktype;
+	int32_t ai_protocol;
+	size_t ai_addrlen;
+	sockaddr* ai_addr;
+	char* ai_canonname;
+	addrinfo* ai_next;
+}
+
+
+struct hostent
+{
+	char* h_name;
+	char** h_aliases;
+	int32_t h_addrtype;
+	int32_t h_length;
+	char** h_addr_list;
+	
+	
+	char* h_addr()
+	{
+		return h_addr_list[0];
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/c/locale.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,151 @@
+/**
+ * C's &lt;locale.h&gt;
+ * License: Public Domain
+ * Standards:
+ *	ISO/IEC 9899:1999 7.11 
+ * Macros:
+ *	WIKI=Phobos/StdCLocale
+ */
+module std.c.locale;
+
+extern(C):
+
+/// Structure giving information about numeric and monetary notation.
+struct lconv{
+	/// The decimal-point character used to format nonmonetary quantities.
+	char* decimal_point;
+
+	/** The character used to separate groups of digits before the
+	 * decimal-point character in formatted nonmonetary quantities.
+	 **/
+	char* thousands_sep;
+
+	/** A string whose elements indicate the size of each group of digits
+	 * in formatted nonmonetary quantities.
+	 **/
+	char* grouping;
+
+	/** The international currency symbol applicable to the current locale.
+	 * The first three characters contain the alphabetic international
+	 * currency symbol in accordance with those specified in ISO 4217.
+	 * The fourth character	(immediately preceding the null character)
+	 * is the character used to separate the international currency symbol
+	 * from the monetary quantity.
+	 **/
+	char* int_curr_symbol;
+
+	/// The local currency symbol applicable to the current locale.
+	char* currency_symbol;
+
+	/// The decimal-point used to format monetary quantities.
+	char* mon_decimal_point;
+
+	/** The separator for groups of digits before the decimal-point in
+	 * formatted monetary quantities.
+	 **/
+	char* mon_thousands_sep;
+
+	/** A string whose elements indicate the size of each group of digits
+	 * in formatted monetary quantities.
+	 **/
+	char* mon_grouping;
+
+	/** The string used to indicate a nonnegative-valued formatted
+	 * monetary quantity.
+	 **/
+	char* positive_sign;
+
+	/** The string used to indicate a negative-valued formatted monetary
+	 * quantity.
+	 **/
+	char* negative_sign;
+
+	/** The number of fractional digits (those after the decimal-point) to
+	 * be displayed in an internationally formatted monetary quantity.
+	 **/
+	char int_frac_digits;
+
+	/** The number of fractional digits (those after the decimal-point) to
+	 * be displayed in a locally formatted monetary quantity.
+	 **/
+	char frac_digits;
+
+	/// 1 if currency_symbol precedes a positive value, 0 if succeeds.
+	char p_cs_precedes;
+	
+	/// 1 if a space separates currency_symbol from a positive value.
+	char p_sep_by_space;
+	
+	/// 1 if currency_symbol precedes a negative value, 0 if succeeds.
+	char n_cs_precedes;
+
+	/// 1 if a space separates currency_symbol from a negative value.
+	char n_sep_by_space;
+
+  /* Positive and negative sign positions:
+     0 Parentheses surround the quantity and currency_symbol.
+     1 The sign string precedes the quantity and currency_symbol.
+     2 The sign string follows the quantity and currency_symbol.
+     3 The sign string immediately precedes the currency_symbol.
+     4 The sign string immediately follows the currency_symbol.  */
+  char p_sign_posn;
+  char n_sign_posn;
+  
+	/// 1 if int_curr_symbol precedes a positive value, 0 if succeeds.
+	char int_p_cs_precedes;
+	
+	/// 1 iff a space separates int_curr_symbol from a positive value.
+	char int_p_sep_by_space;
+	
+	/// 1 if int_curr_symbol precedes a negative value, 0 if succeeds.
+	char int_n_cs_precedes;
+	
+	/// 1 iff a space separates int_curr_symbol from a negative value.
+	char int_n_sep_by_space;
+
+  /* Positive and negative sign positions:
+     0 Parentheses surround the quantity and int_curr_symbol.
+     1 The sign string precedes the quantity and int_curr_symbol.
+     2 The sign string follows the quantity and int_curr_symbol.
+     3 The sign string immediately precedes the int_curr_symbol.
+     4 The sign string immediately follows the int_curr_symbol.  */
+  char int_p_sign_posn;
+  char int_n_sign_posn;
+}
+
+/** Affects the behavior of C's character handling functions and C's multibyte
+ * and wide character functions.
+ **/
+const LC_CTYPE = 0; 
+
+/** Affects the decimal-point character for C's formatted input/output functions
+ * and C's string conversion functions, as well as C's nonmonetary formatting
+ * information returned by the localeconv function.
+ **/
+const LC_NUMERIC = 1;
+
+/// Affects the behavior of the strftime and wcsftime functions.
+const LC_TIME = 2;
+
+/// Affects the behavior of the strcoll and strxfrm functions.
+const LC_COLLATE = 3;
+
+/** Affects the monetary formatting information returned by the localeconv
+ * function.
+ **/
+const LC_MONETARY = 4;
+
+/// The program's entire locale.
+const LC_ALL = 6;
+
+/** The setlocale function selects the appropriate portion of the program's
+ * locale as specified by the category and locale arguments.
+ **/
+char* setlocale(int category, char* locale);
+
+/** The localeconv function sets the components of an object with type
+ * lconv with values appropriate for the formatting of numeric quantities
+ * (monetary and otherwise) according to the rules of the current locale.
+ **/
+lconv* localeconv();
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/c/math.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,291 @@
+
+/**
+ * C's &lt;math.h&gt;
+ * Authors: Walter Bright, Digital Mars, www.digitalmars.com
+ * License: Public Domain
+ * Macros:
+ *	WIKI=Phobos/StdCMath
+ */
+
+module std.c.math;
+
+extern (C):
+
+alias float float_t;	///
+alias double double_t;	///
+
+const double HUGE_VAL  = double.infinity;	///
+const float HUGE_VALF = float.infinity;	/// ditto
+const real HUGE_VALL = real.infinity;	/// ditto
+
+const float INFINITY = float.infinity;	///
+const float NAN = float.nan;	///
+
+enum
+{
+    FP_NANS,	// extension
+    FP_NANQ,	// extension
+    FP_INFINITE,	///
+    FP_NAN = FP_NANQ,	///
+    FP_NORMAL = 3,	///
+    FP_SUBNORMAL = 4,	///
+    FP_ZERO = 5,	///
+    FP_EMPTY = 6,	// extension
+    FP_UNSUPPORTED = 7, // extension
+}
+
+enum
+{
+    FP_FAST_FMA  = 0,	///
+    FP_FAST_FMAF = 0,	///
+    FP_FAST_FMAL = 0,	///
+}
+
+const int FP_ILOGB0   = int.min;	///
+const int FP_ILOGBNAN = int.min;	///
+
+const int MATH_ERRNO     = 1;	///
+const int MATH_ERREXCEPT = 2;	///
+const int math_errhandling   = MATH_ERRNO | MATH_ERREXCEPT;	///
+
+double acos(double x);	///
+float  acosf(float x);	/// ditto
+real   acosl(real x);	/// ditto
+
+double asin(double x);	///
+float  asinf(float x);	/// ditto
+real   asinl(real x);	/// ditto
+
+double atan(double x);	///
+float  atanf(float x);	/// ditto
+real   atanl(real x);	/// ditto
+
+double atan2(double y, double x);	///
+float  atan2f(float y, float x);	/// ditto
+real   atan2l(real y, real x);		/// ditto
+
+double cos(double x);	///
+float  cosf(float x);	/// ditto
+real   cosl(real x);	/// ditto
+
+double sin(double x);	///
+float  sinf(float x);	/// ditto
+real   sinl(real x);	/// ditto
+
+double tan(double x);	///
+float  tanf(float x);	/// ditto
+real   tanl(real x);	/// ditto
+
+double acosh(double x);	///
+float  acoshf(float x);	/// ditto
+real   acoshl(real x);	/// ditto
+
+double asinh(double x);	///
+float  asinhf(float x);	/// ditto
+real   asinhl(real x);	/// ditto
+
+double atanh(double x);	///
+float  atanhf(float x);	/// ditto
+real   atanhl(real x);	/// ditto
+
+double cosh(double x);	///
+float  coshf(float x);	/// ditto
+real   coshl(real x);	/// ditto
+
+double sinh(double x);	///
+float  sinhf(float x);	/// ditto
+real   sinhl(real x);	/// ditto
+
+double tanh(double x);	///
+float  tanhf(float x);	/// ditto
+real   tanhl(real x);	/// ditto
+
+double exp(double x);	///
+float  expf(float x);	/// ditto
+real   expl(real x);	/// ditto
+
+double exp2(double x);	///
+float  exp2f(float x);	/// ditto
+real   exp2l(real x);	/// ditto
+
+double expm1(double x);	///
+float  expm1f(float x);	/// ditto
+real   expm1l(real x);	/// ditto
+
+double frexp(double value, int *exp);	///
+float  frexpf(float value, int *exp);	/// ditto
+real   frexpl(real value, int *exp);	/// ditto
+
+int    ilogb(double x);	///
+int    ilogbf(float x);	/// ditto
+int    ilogbl(real x);	/// ditto
+
+double ldexp(double x, int exp);	///
+float  ldexpf(float x, int exp);	/// ditto
+real   ldexpl(real x, int exp);		/// ditto
+
+double log(double x);	///
+float  logf(float x);	/// ditto
+real   logl(real x);	/// ditto
+
+double log10(double x);	///
+float  log10f(float x);	/// ditto
+real   log10l(real x);	/// ditto
+
+double log1p(double x);	///
+float  log1pf(float x);	/// ditto
+real   log1pl(real x);	/// ditto
+
+double log2(double x);	///
+float  log2f(float x);	/// ditto
+real   log2l(real x);	/// ditto
+
+double logb(double x);	///
+float  logbf(float x);	/// ditto
+real   logbl(real x);	/// ditto
+
+double modf(double value, double *iptr);	///
+float  modff(float value, float *iptr);		/// ditto
+real   modfl(real value, real *iptr);		/// ditto
+
+double scalbn(double x, int n);	///
+float  scalbnf(float x, int n);	/// ditto
+real   scalbnl(real x, int n);	/// ditto
+
+double scalbln(double x, int n);	///
+float  scalblnf(float x, int n);	/// ditto
+real   scalblnl(real x, int n);		/// ditto
+
+double cbrt(double x);	///
+float  cbrtf(float x);	/// ditto
+real   cbrtl(real x);	/// ditto
+
+double fabs(double x);	///
+float  fabsf(float x);	/// ditto
+real   fabsl(real x);	/// ditto
+
+double hypot(double x, double y);	///
+float  hypotf(float x, float y);	/// ditto
+real   hypotl(real x, real y);		/// ditto
+
+double pow(double x, double y);	///
+float  powf(float x, float y);	/// ditto
+real   powl(real x, real y);	/// ditto
+
+double sqrt(double x);	///
+float  sqrtf(float x);	/// ditto
+real   sqrtl(real x);	/// ditto
+
+double erf(double x);	///
+float  erff(float x);	/// ditto
+real   erfl(real x);	/// ditto
+
+double erfc(double x);	///
+float  erfcf(float x);	/// ditto
+real   erfcl(real x);	/// ditto
+
+double lgamma(double x);	///
+float  lgammaf(float x);	/// ditto
+real   lgammal(real x);		/// ditto
+
+double tgamma(double x);	///
+float  tgammaf(float x);	/// ditto
+real   tgammal(real x);		/// ditto
+
+double ceil(double x);	///
+float  ceilf(float x);	/// ditto
+real   ceill(real x);	/// ditto
+
+double floor(double x);	///
+float  floorf(float x);	/// ditto
+real   floorl(real x);	/// ditto
+
+double nearbyint(double x);	///
+float  nearbyintf(float x);	/// ditto
+real   nearbyintl(real x);	/// ditto
+
+double rint(double x);	///
+float  rintf(float x);	/// ditto
+real   rintl(real x);	/// ditto
+
+int    lrint(double x);	///
+int    lrintf(float x);	/// ditto
+int    lrintl(real x);	/// ditto
+
+long   llrint(double x);	///
+long   llrintf(float x);	/// ditto
+long   llrintl(real x);		/// ditto
+
+double round(double x);	///
+float  roundf(float x);	/// ditto
+real   roundl(real x);	/// ditto
+
+int    lround(double x);	///
+int    lroundf(float x);	/// ditto
+int    lroundl(real x);		/// ditto
+
+long   llround(double x);	///
+long   llroundf(float x);	/// ditto
+long   llroundl(real x);	/// ditto
+
+double trunc(double x);	///
+float  truncf(float x);	/// ditto
+real   truncl(real x);	/// ditto
+
+double fmod(double x, double y);	///
+float  fmodf(float x, float y);		/// ditto
+real   fmodl(real x, real y);		/// ditto
+
+double remainder(double x, double y);	///
+float  remainderf(float x, float y);	/// ditto
+real   remainderl(real x, real y);	/// ditto
+
+double remquo(double x, double y, int *quo);	///
+float  remquof(float x, float y, int *quo);	/// ditto
+real   remquol(real x, real y, int *quo);	/// ditto
+
+double copysign(double x, double y);	///
+float  copysignf(float x, float y);	/// ditto
+real   copysignl(real x, real y);	/// ditto
+
+double nan(char *tagp);		///
+float  nanf(char *tagp);	/// ditto
+real   nanl(char *tagp);	/// ditto
+
+double nextafter(double x, double y);	///
+float  nextafterf(float x, float y);	/// ditto
+real   nextafterl(real x, real y);	/// ditto
+
+double nexttoward(double x, real y);	///
+float  nexttowardf(float x, real y);	/// ditto
+real   nexttowardl(real x, real y);	/// ditto
+
+double fdim(double x, double y);	///
+float  fdimf(float x, float y);		/// ditto
+real   fdiml(real x, real y);		/// ditto
+
+double fmax(double x, double y);	///
+float  fmaxf(float x, float y);		/// ditto
+real   fmaxl(real x, real y);		/// ditto
+
+double fmin(double x, double y);	///
+float  fminf(float x, float y);		/// ditto
+real   fminl(real x, real y);		/// ditto
+
+double fma(double x, double y, double z);	///
+float  fmaf(float x, float y, float z);		/// ditto
+real   fmal(real x, real y, real z);		/// ditto
+
+///
+int isgreater(real x, real y)		{ return !(x !>  y); }
+///
+int isgreaterequal(real x, real y)	{ return !(x !>= y); }
+///
+int isless(real x, real y)		{ return !(x !<  y); }
+///
+int islessequal(real x, real y)		{ return !(x !<= y); }
+///
+int islessgreater(real x, real y)	{ return !(x !<> y); }
+///
+int isunordered(real x, real y)		{ return (x !<>= y); }
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/c/process.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,86 @@
+
+/**
+ * C's &lt;process.h&gt;
+ * Authors: Walter Bright, Digital Mars, www.digitalmars.com
+ * License: Public Domain
+ * Macros:
+ *	WIKI=Phobos/StdCProcess
+ */
+
+module std.c.process;
+
+private import std.c.stddef;
+
+extern (C):
+
+void exit(int);
+void _c_exit();
+void _cexit();
+void _exit(int);
+void abort();
+void _dodtors();
+int getpid();
+
+int system(char *);
+
+enum { _P_WAIT, _P_NOWAIT, _P_OVERLAY };
+
+int execl(char *, char *,...);
+int execle(char *, char *,...);
+int execlp(char *, char *,...);
+int execlpe(char *, char *,...);
+int execv(char *, char **);
+int execve(char *, char **, char **);
+int execvp(char *, char **);
+int execvpe(char *, char **, char **);
+
+
+enum { WAIT_CHILD, WAIT_GRANDCHILD }
+
+int cwait(int *,int,int);
+int wait(int *);
+
+version (Windows)
+{
+    uint _beginthread(void function(void *),uint,void *);
+
+    extern (Windows) alias uint (*stdfp)(void *);
+
+    uint _beginthreadex(void* security, uint stack_size,
+	    stdfp start_addr, void* arglist, uint initflag,
+	    uint* thrdaddr);
+
+    void _endthread();
+    void _endthreadex(uint);
+
+    int spawnl(int, char *, char *,...);
+    int spawnle(int, char *, char *,...);
+    int spawnlp(int, char *, char *,...);
+    int spawnlpe(int, char *, char *,...);
+    int spawnv(int, char *, char **);
+    int spawnve(int, char *, char **, char **);
+    int spawnvp(int, char *, char **);
+    int spawnvpe(int, char *, char **, char **);
+
+
+    int _wsystem(wchar_t *);
+    int _wspawnl(int, wchar_t *, wchar_t *, ...);
+    int _wspawnle(int, wchar_t *, wchar_t *, ...);
+    int _wspawnlp(int, wchar_t *, wchar_t *, ...);
+    int _wspawnlpe(int, wchar_t *, wchar_t *, ...);
+    int _wspawnv(int, wchar_t *, wchar_t **);
+    int _wspawnve(int, wchar_t *, wchar_t **, wchar_t **);
+    int _wspawnvp(int, wchar_t *, wchar_t **);
+    int _wspawnvpe(int, wchar_t *, wchar_t **, wchar_t **);
+
+    int _wexecl(wchar_t *, wchar_t *, ...);
+    int _wexecle(wchar_t *, wchar_t *, ...);
+    int _wexeclp(wchar_t *, wchar_t *, ...);
+    int _wexeclpe(wchar_t *, wchar_t *, ...);
+    int _wexecv(wchar_t *, wchar_t **);
+    int _wexecve(wchar_t *, wchar_t **, wchar_t **);
+    int _wexecvp(wchar_t *, wchar_t **);
+    int _wexecvpe(wchar_t *, wchar_t **, wchar_t **);
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/c/stdarg.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,42 @@
+
+/**
+ * C's &lt;stdarg.h&gt;
+ * Authors: Hauke Duden and Walter Bright, Digital Mars, www.digitalmars.com
+ * License: Public Domain
+ * Macros:
+ *	WIKI=Phobos/StdCStdarg
+ */
+
+/* This is for use with extern(C) variable argument lists. */
+
+module std.c.stdarg;
+
+alias void* va_list;
+
+template va_start(T)
+{
+    void va_start(out va_list ap, inout T parmn)
+    {
+	ap = cast(va_list)(cast(void*)&parmn + ((T.sizeof + int.sizeof - 1) & ~(int.sizeof - 1)));
+    }
+}
+
+template va_arg(T)
+{
+    T va_arg(inout va_list ap)
+    {
+	T arg = *cast(T*)ap;
+	ap = cast(va_list)(cast(void*)ap + ((T.sizeof + int.sizeof - 1) & ~(int.sizeof - 1)));
+	return arg;
+    }
+}
+
+void va_end(va_list ap)
+{
+
+}
+
+void va_copy(out va_list dest, va_list src)
+{
+    dest = src;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/c/stddef.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,23 @@
+
+/**
+ * C's &lt;stddef.h&gt;
+ * Authors: Walter Bright, Digital Mars, www.digitalmars.com
+ * License: Public Domain
+ * Macros:
+ *	WIKI=Phobos/StdCStddef
+ */
+
+module std.c.stddef;
+
+version (Win32)
+{
+    alias wchar wchar_t;
+}
+else version (linux)
+{
+    alias dchar wchar_t;
+}
+else
+{
+    static assert(0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/c/stdio.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,300 @@
+
+/**
+ * C's &lt;stdio.h&gt;
+ * Authors: Walter Bright, Digital Mars, www.digitalmars.com
+ * License: Public Domain
+ * Macros:
+ *	WIKI=Phobos/StdCStdio
+ */
+
+
+
+module std.c.stdio;
+
+import std.c.stddef;
+private import std.c.stdarg;
+
+extern (C):
+
+version (Win32)
+{
+    const int _NFILE = 60;	///
+    const int BUFSIZ = 0x4000;	///
+    const int EOF = -1;		///
+    const int FOPEN_MAX = 20;	///
+    const int FILENAME_MAX = 256;  /// 255 plus NULL
+    const int TMP_MAX = 32767;	///
+    const int _SYS_OPEN = 20;	///
+    const int SYS_OPEN = _SYS_OPEN;	///
+    const wchar WEOF = 0xFFFF;		///
+}
+
+version (linux)
+{
+    const int EOF = -1;
+    const int FOPEN_MAX = 16;
+    const int FILENAME_MAX = 4095;
+    const int TMP_MAX = 238328;
+    const int L_tmpnam = 20;
+}
+
+enum { SEEK_SET, SEEK_CUR, SEEK_END }
+
+struct _iobuf
+{
+    align (1):
+    version (Win32)
+    {
+	char	*_ptr;
+	int	_cnt;
+	char	*_base;
+	int	_flag;
+	int	_file;
+	int	_charbuf;
+	int	_bufsiz;
+	int	__tmpnum;
+    }
+    version (linux)
+    {
+	char*	_read_ptr;
+	char*	_read_end;
+	char*	_read_base;
+	char*	_write_base;
+	char*	_write_ptr;
+	char*	_write_end;
+	char*	_buf_base;
+	char*	_buf_end;
+	char*	_save_base;
+	char*	_backup_base;
+	char*	_save_end;
+	void*	_markers;
+	_iobuf*	_chain;
+	int	_fileno;
+	int	_blksize;
+	int	_old_offset;
+	ushort	_cur_column;
+	byte	_vtable_offset;
+	char[1]	_shortbuf;
+	void*	_lock;
+    }
+}
+
+alias _iobuf FILE;	///
+
+enum
+{
+    _F_RDWR = 0x0003,
+    _F_READ = 0x0001,
+    _F_WRIT = 0x0002,
+    _F_BUF  = 0x0004,
+    _F_LBUF = 0x0008,
+    _F_ERR  = 0x0010,
+    _F_EOF  = 0x0020,
+    _F_BIN  = 0x0040,
+    _F_IN   = 0x0080,
+    _F_OUT  = 0x0100,
+    _F_TERM = 0x0200,
+}
+
+version (Win32)
+{
+    extern FILE _iob[_NFILE];
+    extern void function() _fcloseallp;
+    extern ubyte __fhnd_info[_NFILE];
+
+    enum
+    {
+	FHND_APPEND	= 0x04,
+	FHND_DEVICE	= 0x08,
+	FHND_TEXT	= 0x10,
+	FHND_BYTE	= 0x20,
+	FHND_WCHAR	= 0x40,
+    }
+}
+
+version (Win32)
+{
+    enum
+    {
+	    _IOREAD	= 1,
+	    _IOWRT	= 2,
+	    _IONBF	= 4,
+	    _IOMYBUF	= 8,
+	    _IOEOF	= 0x10,
+	    _IOERR	= 0x20,
+	    _IOLBF	= 0x40,
+	    _IOSTRG	= 0x40,
+	    _IORW	= 0x80,
+	    _IOFBF	= 0,
+	    _IOAPP	= 0x200,
+	    _IOTRAN	= 0x100,
+    }
+}
+
+version (linux)
+{
+    enum
+    {
+	    _IOFBF = 0,
+	    _IOLBF = 1,
+	    _IONBF = 2,
+    }
+}
+
+version (Win32)
+{
+    const FILE *stdin  = &_iob[0];	///
+    const FILE *stdout = &_iob[1];	///
+    const FILE *stderr = &_iob[2];	///
+    const FILE *stdaux = &_iob[3];	///
+    const FILE *stdprn = &_iob[4];	///
+}
+
+version (linux)
+{
+    extern FILE *stdin;
+    extern FILE *stdout;
+    extern FILE *stderr;
+}
+
+version (Win32)
+{
+    const char[] _P_tmpdir = "\\";
+    const wchar[] _wP_tmpdir = "\\";
+    const int L_tmpnam = _P_tmpdir.length + 12;
+}
+
+alias int fpos_t;	///
+
+char *	 tmpnam(char *);	///
+FILE *	 fopen(char *,char *);	///
+FILE *	 _fsopen(char *,char *,int );	///
+FILE *	 freopen(char *,char *,FILE *);	///
+int	 fseek(FILE *,int,int);	///
+int	 ftell(FILE *);	///
+char *	 fgets(char *,int,FILE *);	///
+int	 fgetc(FILE *);	///
+int	 _fgetchar();	///
+int	 fflush(FILE *);	///
+int	 fclose(FILE *);	///
+int	 fputs(char *,FILE *);	///
+char *	 gets(char *);	///
+int	 fputc(int,FILE *);	///
+int	 _fputchar(int);	///
+int	 puts(char *);	///
+int	 ungetc(int,FILE *);	///
+size_t	 fread(void *,size_t,size_t,FILE *);	///
+size_t	 fwrite(void *,size_t,size_t,FILE *);	///
+//int	 printf(char *,...);	///
+int	 fprintf(FILE *,char *,...);	///
+int	 vfprintf(FILE *,char *,va_list);	///
+int	 vprintf(char *,va_list);	///
+int	 sprintf(char *,char *,...);	///
+int	 vsprintf(char *,char *,va_list);	///
+int	 scanf(char *,...);	///
+int	 fscanf(FILE *,char *,...);	///
+int	 sscanf(char *,char *,...);	///
+void	 setbuf(FILE *,char *);	///
+int	 setvbuf(FILE *,char *,int,size_t);	///
+int	 remove(char *);	///
+int	 rename(char *,char *);	///
+void	 perror(char *);	///
+int	 fgetpos(FILE *,fpos_t *);	///
+int	 fsetpos(FILE *,fpos_t *);	///
+FILE *	 tmpfile();	///
+int	 _rmtmp();
+int      _fillbuf(FILE *);
+int      _flushbu(int, FILE *);
+
+int  getw(FILE *FHdl);	///
+int  putw(int Word, FILE *FilePtr);	///
+
+///
+int  getchar()		{ return getc(stdin);		}
+///
+int  putchar(int c)	{ return putc(c,stdout);	}
+///
+int  getc(FILE *fp)	{ return fgetc(fp);		}
+///
+int  putc(int c,FILE *fp) { return fputc(c,fp);		}
+
+version (Win32)
+{
+    ///
+    int  ferror(FILE *fp)	{ return fp._flag&_IOERR;	}
+    ///
+    int  feof(FILE *fp)	{ return fp._flag&_IOEOF;	}
+    ///
+    void clearerr(FILE *fp)	{ fp._flag &= ~(_IOERR|_IOEOF); }
+    ///
+    void rewind(FILE *fp)	{ fseek(fp,0L,SEEK_SET); fp._flag&=~_IOERR; }
+    int  _bufsize(FILE *fp)	{ return fp._bufsiz; }
+    ///
+    int  fileno(FILE *fp)	{ return fp._file; }
+    int  _snprintf(char *,size_t,char *,...);
+    int  _vsnprintf(char *,size_t,char *,va_list);
+}
+
+version (linux)
+{
+    int  ferror(FILE *fp);
+    int  feof(FILE *fp);
+    void clearerr(FILE *fp);
+    void rewind(FILE *fp);
+    int  _bufsize(FILE *fp);
+    int  fileno(FILE *fp);
+    int  snprintf(char *,size_t,char *,...);
+    int  vsnprintf(char *,size_t,char *,va_list);
+}
+
+int      unlink(char *);	///
+FILE *	 fdopen(int, char *);	///
+int	 fgetchar();	///
+int	 fputchar(int);	///
+int	 fcloseall();	///
+int	 filesize(char *);	///
+int	 flushall();	///
+int	 getch();	///
+int	 getche();	///
+int      kbhit();	///
+char *   tempnam (char *dir, char *pfx);	///
+
+wchar_t *  _wtmpnam(wchar_t *);	///
+FILE *  _wfopen(wchar_t *, wchar_t *);
+FILE *  _wfsopen(wchar_t *, wchar_t *, int);
+FILE *  _wfreopen(wchar_t *, wchar_t *, FILE *);
+wchar_t *  fgetws(wchar_t *, int, FILE *);	///
+int  fputws(wchar_t *, FILE *);	///
+wchar_t *  _getws(wchar_t *);
+int  _putws(wchar_t *);
+int  wprintf(wchar_t *, ...);	///
+int  fwprintf(FILE *, wchar_t *, ...);	///
+int  vwprintf(wchar_t *, va_list);	///
+int  vfwprintf(FILE *, wchar_t *, va_list);	///
+int  swprintf(wchar_t *, wchar_t *, ...);	///
+int  vswprintf(wchar_t *, wchar_t *, va_list);	///
+int  _snwprintf(wchar_t *, size_t, wchar_t *, ...);
+int  _vsnwprintf(wchar_t *, size_t, wchar_t *, va_list);
+int  wscanf(wchar_t *, ...);	///
+int  fwscanf(FILE *, wchar_t *, ...);	///
+int  swscanf(wchar_t *, wchar_t *, ...);	///
+int  _wremove(wchar_t *);
+void  _wperror(wchar_t *);
+FILE *  _wfdopen(int, wchar_t *);
+wchar_t *  _wtempnam(wchar_t *, wchar_t *);
+wchar_t  fgetwc(FILE *);	///
+wchar_t  _fgetwchar_t();
+wchar_t  fputwc(wchar_t, FILE *);	///
+wchar_t  _fputwchar_t(wchar_t);
+wchar_t  ungetwc(wchar_t, FILE *);	///
+
+///
+wchar_t	 getwchar_t()		{ return fgetwc(stdin); }
+///
+wchar_t	 putwchar_t(wchar_t c)	{ return fputwc(c,stdout); }
+///
+wchar_t	 getwc(FILE *fp)	{ return fgetwc(fp); }
+///
+wchar_t	 putwc(wchar_t c, FILE *fp)	{ return fputwc(c, fp); }
+
+int fwide(FILE* fp, int mode);	///
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/c/stdlib.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,90 @@
+/**
+ * C's &lt;stdlib.h&gt;
+ * Authors: Walter Bright, Digital Mars, www.digitalmars.com
+ * License: Public Domain
+ * Macros:
+ *	WIKI=Phobos/StdCStdlib
+ */
+
+
+module std.c.stdlib;
+
+private import std.c.stddef;
+
+extern (C):
+
+enum
+{
+    _MAX_PATH   = 260,
+    _MAX_DRIVE  = 3,
+    _MAX_DIR    = 256,
+    _MAX_FNAME  = 256,
+    _MAX_EXT    = 256,
+}
+
+///
+struct div_t { int  quot,rem; }
+///
+struct ldiv_t { int quot,rem; }
+///
+struct lldiv_t { long quot,rem; }
+
+    div_t div(int,int);	///
+    ldiv_t ldiv(int,int); /// ditto
+    lldiv_t lldiv(long, long); /// ditto
+
+    const int EXIT_SUCCESS = 0;	///
+    const int EXIT_FAILURE = 1;	/// ditto
+
+    int    atexit(void (*)());	///
+    void   exit(int);	/// ditto
+    void   _exit(int);	/// ditto
+
+    int system(char *);
+
+    void *alloca(uint);	///
+
+    void *calloc(size_t, size_t);	///
+    void *malloc(size_t);	/// ditto
+    void *realloc(void *, size_t);	/// ditto
+    void free(void *);	/// ditto
+
+    void *bsearch(void *,void *,size_t,size_t,
+       int function(void *,void *));	///
+    void qsort(void *base, size_t nelems, size_t elemsize,
+	int (*compare)(void *elem1, void *elem2));	/// ditto
+
+    char* getenv(char*);	///
+    int   setenv(char*, char*, int); /// extension to ISO C standard, not available on all platforms
+    void  unsetenv(char*); /// extension to ISO C standard, not available on all platforms
+
+    int    rand();	///
+    void   srand(uint);	/// ditto
+    int    random(int num);	/// ditto
+    void   randomize();	/// ditto
+
+    int getErrno();	/// ditto
+    int setErrno(int);	/// ditto
+
+const int ERANGE = 34;	// on both Windows and linux
+
+double atof(char *);	///
+int    atoi(char *);	/// ditto
+int    atol(char *);	/// ditto
+float  strtof(char *,char **);	/// ditto
+double strtod(char *,char **);	/// ditto
+real   strtold(char *,char **);	/// ditto
+long   strtol(char *,char **,int);	/// ditto
+uint   strtoul(char *,char **,int);	/// ditto
+long   atoll(char *);	/// ditto
+long   strtoll(char *,char **,int);	/// ditto
+ulong  strtoull(char *,char **,int);	/// ditto
+
+char* itoa(int, char*, int);	///
+char* ultoa(uint, char*, int);	/// ditto
+
+int mblen(char *s, size_t n);	///
+int mbtowc(wchar_t *pwc, char *s, size_t n);	/// ditto
+int wctomb(char *s, wchar_t wc);	/// ditto
+size_t mbstowcs(wchar_t *pwcs, char *s, size_t n);	/// ditto
+size_t wcstombs(char *s, wchar_t *pwcs, size_t n);	/// ditto
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/c/string.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,40 @@
+
+/**
+ * C's &lt;string.h&gt;
+ * Authors: Walter Bright, Digital Mars, www.digitalmars.com
+ * License: Public Domain
+ * Macros:
+ *	WIKI=Phobos/StdCString
+ */
+
+module std.c.string;
+
+extern (C):
+
+void* memcpy(void* s1, void* s2, size_t n);	///
+void* memmove(void* s1, void* s2, size_t n);	///
+char* strcpy(char* s1, char* s2);		///
+char* strncpy(char* s1, char* s2, size_t n);	///
+char* strncat(char*  s1, char*  s2, size_t n);	///
+int strcoll(char* s1, char* s2);		///
+int strncmp(char* s1, char* s2, size_t n);	///
+size_t strxfrm(char*  s1, char*  s2, size_t n);	///
+void* memchr(void* s, int c, size_t n);		///
+char* strchr(char* s, int c);			///
+size_t strcspn(char* s1, char* s2);		///
+char* strpbrk(char* s1, char* s2);		///
+char* strrchr(char* s, int c);			///
+size_t strspn(char* s1, char* s2);		///
+char* strstr(char* s1, char* s2);		///
+char* strtok(char*  s1, char*  s2);		///
+void* memset(void* s, int c, size_t n);		///
+char* strerror(int errnum);			///
+size_t strlen(char* s);				///
+int strcmp(char* s1, char* s2);			///
+char* strcat(char* s1, char* s2);		///
+int memcmp(void* s1, void* s2, size_t n);	///
+
+version (Windows)
+{
+    int memicmp(char* s1, char* s2, size_t n);	///
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/c/time.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,94 @@
+
+/**
+ * C's &lt;time.h&gt;
+ * Authors: Walter Bright, Digital Mars, www.digitalmars.com
+ * License: Public Domain
+ * Macros:
+ *	WIKI=Phobos/StdCTime
+ */
+
+module std.c.time;
+
+private import std.c.stddef;
+
+extern (C):
+
+alias int clock_t;
+
+version (Windows)
+{   const clock_t CLOCKS_PER_SEC = 1000;
+}
+else version (linux)
+{   const clock_t CLOCKS_PER_SEC = 1000000;
+}
+else version (darwin)
+{
+    const clock_t CLOCKS_PER_SEC = 100;
+}
+else
+{
+    static assert(0);
+}
+
+version (Windows)
+{
+    const clock_t CLK_TCK        = 1000;
+}
+else version (linux)
+{
+    extern (C) int sysconf(int);
+    extern clock_t CLK_TCK;
+    /*static this()
+    {
+	CLK_TCK = cast(clock_t) sysconf(2);
+    }*/
+}
+else
+{
+    static assert(0);
+}
+
+const uint TIMEOFFSET     = 315558000;
+
+alias int time_t;
+
+extern int daylight;
+extern int timezone;
+extern int altzone;
+extern char *tzname[2];
+
+struct tm
+{      int     tm_sec,
+               tm_min,
+               tm_hour,
+               tm_mday,
+               tm_mon,
+               tm_year,
+               tm_wday,
+               tm_yday,
+               tm_isdst;
+}
+
+clock_t clock();
+time_t time(time_t *);
+time_t mktime(tm *);
+char *asctime(tm *);
+char *ctime(time_t *);
+tm *localtime(time_t *);
+tm *gmtime(time_t *);
+size_t strftime(char *, size_t, char *, tm *);
+char *_strdate(char *dstring);
+char *_strtime(char *timestr);
+double difftime(time_t t1, time_t t2);
+void _tzset();
+void tzset();
+
+void sleep(time_t);
+void usleep(uint);
+void msleep(uint);
+
+wchar_t *_wasctime(tm *);
+wchar_t *_wctime(time_t *);
+size_t wcsftime(wchar_t *, size_t, wchar_t *, tm *);
+wchar_t *_wstrdate(wchar_t *);
+wchar_t *_wstrtime(wchar_t *);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/intrinsic.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,265 @@
+
+
+// written by Walter Bright
+// www.digitalmars.com
+// Placed into the public domain
+
+/* NOTE: This file has been patched from the original DMD distribution to
+   work with the GDC compiler.
+   NOTE: This file has been patched from the original GDC distribution to
+   work with the LLVMDC compiler.
+
+   Modified by David Friedman, May 2006
+   Modified by Tomas Lindquist Olsen, August 2007
+*/
+
+/** These functions are built-in intrinsics to the compiler.
+ *
+	Intrinsic functions are functions built in to the compiler,
+	usually to take advantage of specific CPU features that
+	are inefficient to handle via external functions.
+	The compiler's optimizer and code generator are fully
+	integrated in with intrinsic functions, bringing to bear
+	their full power on them.
+	This can result in some surprising speedups.
+ * Macros:
+ *	WIKI=Phobos/StdIntrinsic
+ */
+
+module std.intrinsic;
+
+/**
+ * Scans the bits in v starting with bit 0, looking
+ * for the first set bit.
+ * Returns:
+ *	The bit number of the first bit set.
+ *	The return value is undefined if v is zero.
+ */
+version (LLVM)
+    int bsf(uint v)
+    {
+	uint m = 1;
+	uint i;
+	for (i = 0; i < 32; i++,m<<=1) {
+	    if (v&m)
+		return i;
+	}
+	return i; // supposed to be undefined
+    }
+else
+    int bsf(uint v);
+
+/**
+ * Scans the bits in v from the most significant bit
+ * to the least significant bit, looking
+ * for the first set bit.
+ * Returns:
+ *	The bit number of the first bit set.
+ *	The return value is undefined if v is zero.
+ * Example:
+ * ---
+ * import std.intrinsic;
+ *
+ * int main()
+ * {   
+ *     uint v;
+ *     int x;
+ *
+ *     v = 0x21;
+ *     x = bsf(v);
+ *     printf("bsf(x%x) = %d\n", v, x);
+ *     x = bsr(v);
+ *     printf("bsr(x%x) = %d\n", v, x);
+ *     return 0;
+ * } 
+ * ---
+ * Output:
+ *  bsf(x21) = 0<br>
+ *  bsr(x21) = 5
+ */
+version (LLVM)
+int bsr(uint v)
+{
+    uint m = 0x80000000;
+    uint i;
+    for (i = 32; i ; i--,m>>>=1) {
+	if (v&m)
+	    return i-1;
+    }
+    return i; // supposed to be undefined
+}
+else
+    int bsr(uint v);
+
+/**
+ * Tests the bit.
+ */
+version (LLVM)
+int bt(uint *p, uint bitnum)
+{
+    return (p[bitnum / (uint.sizeof*8)] & (1<<(bitnum & ((uint.sizeof*8)-1)))) ? -1 : 0 ;
+}
+else
+    int bt(uint *p, uint bitnum);
+
+/**
+ * Tests and complements the bit.
+ */
+version (LLVM)
+int btc(uint *p, uint bitnum)
+{
+    uint * q = p + (bitnum / (uint.sizeof*8));
+    uint mask = 1 << (bitnum & ((uint.sizeof*8) - 1));
+    int result = *q & mask;
+    *q ^= mask;
+    return result ? -1 : 0;
+}
+else
+int btc(uint *p, uint bitnum);
+
+/**
+ * Tests and resets (sets to 0) the bit.
+ */
+version (LLVM)
+int btr(uint *p, uint bitnum)
+{
+    uint * q = p + (bitnum / (uint.sizeof*8));
+    uint mask = 1 << (bitnum & ((uint.sizeof*8) - 1));
+    int result = *q & mask;
+    *q &= ~mask;
+    return result ? -1 : 0;
+}
+else
+    int btr(uint *p, uint bitnum);
+
+/**
+ * Tests and sets the bit.
+ * Params:
+ * p = a non-NULL pointer to an array of uints.
+ * index = a bit number, starting with bit 0 of p[0],
+ * and progressing. It addresses bits like the expression:
+---
+p[index / (uint.sizeof*8)] & (1 << (index & ((uint.sizeof*8) - 1)))
+---
+ * Returns:
+ * 	A non-zero value if the bit was set, and a zero
+ *	if it was clear.
+ *
+ * Example: 
+ * ---
+import std.intrinsic;
+
+int main()
+{   
+    uint array[2];
+
+    array[0] = 2;
+    array[1] = 0x100;
+
+    printf("btc(array, 35) = %d\n", <b>btc</b>(array, 35));
+    printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
+
+    printf("btc(array, 35) = %d\n", <b>btc</b>(array, 35));
+    printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
+
+    printf("bts(array, 35) = %d\n", <b>bts</b>(array, 35));
+    printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
+
+    printf("btr(array, 35) = %d\n", <b>btr</b>(array, 35));
+    printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
+
+    printf("bt(array, 1) = %d\n", <b>bt</b>(array, 1));
+    printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
+
+    return 0;
+} 
+ * ---
+ * Output:
+<pre>
+btc(array, 35) = 0
+array = [0]:x2, [1]:x108
+btc(array, 35) = -1
+array = [0]:x2, [1]:x100
+bts(array, 35) = 0
+array = [0]:x2, [1]:x108
+btr(array, 35) = -1
+array = [0]:x2, [1]:x100
+bt(array, 1) = -1
+array = [0]:x2, [1]:x100
+</pre>
+ */
+version (LLVM)
+int bts(uint *p, uint bitnum)
+{
+    uint * q = p + (bitnum / (uint.sizeof*8));
+    uint mask = 1 << (bitnum & ((uint.sizeof*8) - 1));
+    int result = *q & mask;
+    *q |= mask;
+    return result ? -1 : 0;
+}
+else
+    int bts(uint *p, uint bitnum);
+
+
+/**
+ * Swaps bytes in a 4 byte uint end-to-end, i.e. byte 0 becomes
+	byte 3, byte 1 becomes byte 2, byte 2 becomes byte 1, byte 3
+	becomes byte 0.
+ */
+version (LLVM)
+pragma(LLVM_internal, "intrinsic", "llvm.bswap.i32.i32")
+    uint bswap(uint val);
+else
+    uint bswap(uint v);
+
+
+/**
+ * Reads I/O port at port_address.
+ */
+version (LLVM)
+    ubyte  inp(uint p) { return 0; }
+else
+    ubyte  inp(uint port_address);
+
+/**
+ * ditto
+ */
+version (LLVM)
+    ushort inpw(uint p) { return 0; }
+else
+    ushort inpw(uint port_address);
+
+/**
+ * ditto
+ */
+version (LLVM)
+    uint   inpl(uint p) { return 0; }
+else
+    uint   inpl(uint port_address);
+
+
+/**
+ * Writes and returns value to I/O port at port_address.
+ */
+version (LLVM)
+    ubyte  outp(uint p, ubyte v) { return v; }
+else
+    ubyte  outp(uint port_address, ubyte value);
+
+/**
+ * ditto
+ */
+version (LLVM)
+    ushort outpw(uint p, ushort v) { return v; }
+else
+    ushort outpw(uint port_address, ushort value);
+
+/**
+ * ditto
+ */
+version (LLVM)
+    uint   outpl(uint p, uint v) { return v; }
+else
+    uint   outpl(uint port_address, uint value);
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/stdint.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,177 @@
+
+/**
+ *
+	D constrains integral types to specific sizes. But efficiency
+	of different sizes varies from machine to machine,
+	pointer sizes vary, and the maximum integer size varies.
+	<b>stdint</b> offers a portable way of trading off size
+	vs efficiency, in a manner compatible with the <tt>stdint.h</tt>
+	definitions in C.
+
+	The exact aliases are types of exactly the specified number of bits.
+	The at least aliases are at least the specified number of bits
+	large, and can be larger.
+	The fast aliases are the fastest integral type supported by the
+	processor that is at least as wide as the specified number of bits.
+
+	The aliases are:
+
+	<table border=1 cellspacing=0 cellpadding=5>
+	<th>Exact Alias
+	<th>Description
+	<th>At Least Alias
+	<th>Description
+	<th>Fast Alias
+	<th>Description
+	<tr>
+	<td>int8_t
+	<td>exactly 8 bits signed
+	<td>int_least8_t
+	<td>at least 8 bits signed
+	<td>int_fast8_t
+	<td>fast 8 bits signed
+	<tr>
+	<td>uint8_t
+	<td>exactly 8 bits unsigned
+	<td>uint_least8_t
+	<td>at least 8 bits unsigned
+	<td>uint_fast8_t
+	<td>fast 8 bits unsigned
+
+	<tr>
+	<td>int16_t
+	<td>exactly 16 bits signed
+	<td>int_least16_t
+	<td>at least 16 bits signed
+	<td>int_fast16_t
+	<td>fast 16 bits signed
+	<tr>
+	<td>uint16_t
+	<td>exactly 16 bits unsigned
+	<td>uint_least16_t
+	<td>at least 16 bits unsigned
+	<td>uint_fast16_t
+	<td>fast 16 bits unsigned
+
+	<tr>
+	<td>int32_t
+	<td>exactly 32 bits signed
+	<td>int_least32_t
+	<td>at least 32 bits signed
+	<td>int_fast32_t
+	<td>fast 32 bits signed
+	<tr>
+	<td>uint32_t
+	<td>exactly 32 bits unsigned
+	<td>uint_least32_t
+	<td>at least 32 bits unsigned
+	<td>uint_fast32_t
+	<td>fast 32 bits unsigned
+
+	<tr>
+	<td>int64_t
+	<td>exactly 64 bits signed
+	<td>int_least64_t
+	<td>at least 64 bits signed
+	<td>int_fast64_t
+	<td>fast 64 bits signed
+	<tr>
+	<td>uint64_t
+	<td>exactly 64 bits unsigned
+	<td>uint_least64_t
+	<td>at least 64 bits unsigned
+	<td>uint_fast64_t
+	<td>fast 64 bits unsigned
+	</table>
+
+	The ptr aliases are integral types guaranteed to be large enough
+	to hold a pointer without losing bits:
+
+	<table border=1 cellspacing=0 cellpadding=5>
+	<th>Alias
+	<th>Description
+	<tr>
+	<td>intptr_t
+	<td>signed integral type large enough to hold a pointer
+	<tr>
+	<td>uintptr_t
+	<td>unsigned integral type large enough to hold a pointer
+	</table>
+
+	The max aliases are the largest integral types:
+
+	<table border=1 cellspacing=0 cellpadding=5>
+	<th>Alias
+	<th>Description
+	<tr>
+	<td>intmax_t
+	<td>the largest signed integral type
+	<tr>
+	<td>uintmax_t
+	<td>the largest unsigned integral type
+	</table>
+
+ * Authors: Walter Bright, www.digitalmars.com
+ * License: Public Domain
+ * Macros:
+ *	WIKI=Phobos/StdStdint
+ */
+
+/*
+    NOTE: This file has been patched from the original DMD distribution to
+    work with the LLVMDC compiler.
+
+    Modified by Tomas Lindquist Olsen, August 2007
+*/
+
+module std.stdint;
+
+/* Exact sizes */
+
+alias  byte   int8_t;
+alias ubyte  uint8_t;
+alias  short  int16_t;
+alias ushort uint16_t;
+alias  int    int32_t;
+alias uint   uint32_t;
+alias  long   int64_t;
+alias ulong  uint64_t;
+
+/* At least sizes */
+
+alias  byte   int_least8_t;
+alias ubyte  uint_least8_t;
+alias  short  int_least16_t;
+alias ushort uint_least16_t;
+alias  int    int_least32_t;
+alias uint   uint_least32_t;
+alias  long   int_least64_t;
+alias ulong  uint_least64_t;
+
+/* Fastest minimum width sizes */
+
+alias  byte  int_fast8_t;
+alias ubyte uint_fast8_t;
+alias  int   int_fast16_t;
+alias uint  uint_fast16_t;
+alias  int   int_fast32_t;
+alias uint  uint_fast32_t;
+alias  long  int_fast64_t;
+alias ulong uint_fast64_t;
+
+/* Integer pointer holders */
+
+version(LLVM64) {
+    alias long   intptr_t;
+    alias ulong uintptr_t;
+}
+else {
+    alias int   intptr_t;
+    alias uint uintptr_t;
+}
+
+/* Greatest width integer types */
+
+alias  long  intmax_t;
+alias ulong uintmax_t;
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfo/ti_Aint.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,111 @@
+
+module std.typeinfo.ti_Aint;
+
+private import std.c.string;
+
+// int[]
+
+class TypeInfo_Ai : TypeInfo
+{
+    char[] toString() { return "int[]"; }
+
+    hash_t getHash(void *p)
+    {	int[] s = *cast(int[]*)p;
+	auto len = s.length;
+	auto str = s.ptr;
+	hash_t hash = 0;
+
+	while (len)
+	{
+	    hash *= 9;
+	    hash += *cast(uint *)str;
+	    str++;
+	    len--;
+	}
+
+	return hash;
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	int[] s1 = *cast(int[]*)p1;
+	int[] s2 = *cast(int[]*)p2;
+
+	return s1.length == s2.length &&
+	       memcmp(cast(void *)s1, cast(void *)s2, s1.length * int.sizeof) == 0;
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	int[] s1 = *cast(int[]*)p1;
+	int[] s2 = *cast(int[]*)p2;
+	size_t len = s1.length;
+
+	if (s2.length < len)
+	    len = s2.length;
+	for (size_t u = 0; u < len; u++)
+	{
+	    int result = s1[u] - s2[u];
+	    if (result)
+		return result;
+	}
+	return cast(int)s1.length - cast(int)s2.length;
+    }
+
+    size_t tsize()
+    {
+	return (int[]).sizeof;
+    }
+
+    uint flags()
+    {
+	return 1;
+    }
+
+    TypeInfo next()
+    {
+	return typeid(int);
+    }
+}
+
+// uint[]
+
+class TypeInfo_Ak : TypeInfo_Ai
+{
+    char[] toString() { return "uint[]"; }
+
+    int compare(void *p1, void *p2)
+    {
+	uint[] s1 = *cast(uint[]*)p1;
+	uint[] s2 = *cast(uint[]*)p2;
+	size_t len = s1.length;
+
+	if (s2.length < len)
+	    len = s2.length;
+	for (size_t u = 0; u < len; u++)
+	{
+	    int result = s1[u] - s2[u];
+	    if (result)
+		return result;
+	}
+	return cast(int)s1.length - cast(int)s2.length;
+    }
+
+    TypeInfo next()
+    {
+	return typeid(uint);
+    }
+}
+
+// dchar[]
+
+class TypeInfo_Aw : TypeInfo_Ak
+{
+    char[] toString() { return "dchar[]"; }
+
+    TypeInfo next()
+    {
+	return typeid(dchar);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfo/ti_byte.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,39 @@
+
+// byte
+
+module std.typeinfo.ti_byte;
+
+class TypeInfo_g : TypeInfo
+{
+    char[] toString() { return "byte"; }
+
+    hash_t getHash(void *p)
+    {
+	return *cast(byte *)p;
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	return *cast(byte *)p1 == *cast(byte *)p2;
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	return *cast(byte *)p1 - *cast(byte *)p2;
+    }
+
+    size_t tsize()
+    {
+	return byte.sizeof;
+    }
+
+    void swap(void *p1, void *p2)
+    {
+	byte t;
+
+	t = *cast(byte *)p1;
+	*cast(byte *)p1 = *cast(byte *)p2;
+	*cast(byte *)p2 = t;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfo/ti_char.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,43 @@
+
+module std.typeinfo.ti_char;
+
+class TypeInfo_a : TypeInfo
+{
+    char[] toString() { return "char"; }
+
+    hash_t getHash(void *p)
+    {
+	return *cast(char *)p;
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	return *cast(char *)p1 == *cast(char *)p2;
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	return *cast(char *)p1 - *cast(char *)p2;
+    }
+
+    size_t tsize()
+    {
+	return char.sizeof;
+    }
+
+    void swap(void *p1, void *p2)
+    {
+	char t;
+
+	t = *cast(char *)p1;
+	*cast(char *)p1 = *cast(char *)p2;
+	*cast(char *)p2 = t;
+    }
+
+    void[] init()
+    {	static char c;
+
+	return (cast(char *)&c)[0 .. 1];
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfo/ti_int.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,43 @@
+
+// int
+
+module std.typeinfo.ti_int;
+
+class TypeInfo_i : TypeInfo
+{
+    char[] toString() { return "int"; }
+
+    hash_t getHash(void *p)
+    {
+	return *cast(uint *)p;
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	return *cast(uint *)p1 == *cast(uint *)p2;
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	if (*cast(int*) p1 < *cast(int*) p2)
+	    return -1;
+	else if (*cast(int*) p1 > *cast(int*) p2)
+	    return 1;
+	return 0;
+    }
+
+    size_t tsize()
+    {
+	return int.sizeof;
+    }
+
+    void swap(void *p1, void *p2)
+    {
+	int t;
+
+	t = *cast(int *)p1;
+	*cast(int *)p1 = *cast(int *)p2;
+	*cast(int *)p2 = t;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfo/ti_ptr.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,42 @@
+
+// pointer
+
+module std.typeinfo.ti_ptr;
+
+class TypeInfo_P : TypeInfo
+{
+    hash_t getHash(void *p)
+    {
+	return cast(uint)*cast(void* *)p;
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	return *cast(void* *)p1 == *cast(void* *)p2;
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	return *cast(void* *)p1 - *cast(void* *)p2;
+    }
+
+    size_t tsize()
+    {
+	return (void*).sizeof;
+    }
+
+    void swap(void *p1, void *p2)
+    {
+	void* t;
+
+	t = *cast(void* *)p1;
+	*cast(void* *)p1 = *cast(void* *)p2;
+	*cast(void* *)p2 = t;
+    }
+
+    uint flags()
+    {
+	return 1;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfo/ti_short.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,39 @@
+
+// short
+
+module std.typeinfo.ti_short;
+
+class TypeInfo_s : TypeInfo
+{
+    char[] toString() { return "short"; }
+
+    hash_t getHash(void *p)
+    {
+	return *cast(short *)p;
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	return *cast(short *)p1 == *cast(short *)p2;
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	return *cast(short *)p1 - *cast(short *)p2;
+    }
+
+    size_t tsize()
+    {
+	return short.sizeof;
+    }
+
+    void swap(void *p1, void *p2)
+    {
+	short t;
+
+	t = *cast(short *)p1;
+	*cast(short *)p1 = *cast(short *)p2;
+	*cast(short *)p2 = t;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfo/ti_ubyte.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,43 @@
+
+// ubyte
+
+module std.typeinfo.ti_ubyte;
+
+class TypeInfo_h : TypeInfo
+{
+    char[] toString() { return "ubyte"; }
+
+    hash_t getHash(void *p)
+    {
+	return *cast(ubyte *)p;
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	return *cast(ubyte *)p1 == *cast(ubyte *)p2;
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	return *cast(ubyte *)p1 - *cast(ubyte *)p2;
+    }
+
+    size_t tsize()
+    {
+	return ubyte.sizeof;
+    }
+
+    void swap(void *p1, void *p2)
+    {
+	ubyte t;
+
+	t = *cast(ubyte *)p1;
+	*cast(ubyte *)p1 = *cast(ubyte *)p2;
+	*cast(ubyte *)p2 = t;
+    }
+}
+
+class TypeInfo_b : TypeInfo_h
+{
+    char[] toString() { return "bool"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfo/ti_uint.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,43 @@
+
+// uint
+
+module std.typeinfo.ti_uint;
+
+class TypeInfo_k : TypeInfo
+{
+    char[] toString() { return "uint"; }
+
+    hash_t getHash(void *p)
+    {
+	return *cast(uint *)p;
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	return *cast(uint *)p1 == *cast(uint *)p2;
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	if (*cast(uint*) p1 < *cast(uint*) p2)
+	    return -1;
+	else if (*cast(uint*) p1 > *cast(uint*) p2)
+	    return 1;
+	return 0;
+    }
+
+    size_t tsize()
+    {
+	return uint.sizeof;
+    }
+
+    void swap(void *p1, void *p2)
+    {
+	int t;
+
+	t = *cast(uint *)p1;
+	*cast(uint *)p1 = *cast(uint *)p2;
+	*cast(uint *)p2 = t;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfo/ti_ushort.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,39 @@
+
+// ushort
+
+module std.typeinfo.ti_ushort;
+
+class TypeInfo_t : TypeInfo
+{
+    char[] toString() { return "ushort"; }
+
+    hash_t getHash(void *p)
+    {
+	return *cast(ushort *)p;
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	return *cast(ushort *)p1 == *cast(ushort *)p2;
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	return *cast(ushort *)p1 - *cast(ushort *)p2;
+    }
+
+    size_t tsize()
+    {
+	return ushort.sizeof;
+    }
+
+    void swap(void *p1, void *p2)
+    {
+	ushort t;
+
+	t = *cast(ushort *)p1;
+	*cast(ushort *)p1 = *cast(ushort *)p2;
+	*cast(ushort *)p2 = t;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfounsupported/ti_AC.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,92 @@
+module std.typeinfo.ti_AC;
+
+// Object[]
+
+class TypeInfo_AC : TypeInfo
+{
+    hash_t getHash(void *p)
+    {	Object[] s = *cast(Object[]*)p;
+	hash_t hash = 0;
+
+	foreach (Object o; s)
+	{
+	    if (o)
+		hash += o.toHash();
+	}
+	return hash;
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	Object[] s1 = *cast(Object[]*)p1;
+	Object[] s2 = *cast(Object[]*)p2;
+
+	if (s1.length == s2.length)
+	{
+	    for (size_t u = 0; u < s1.length; u++)
+	    {	Object o1 = s1[u];
+		Object o2 = s2[u];
+
+		// Do not pass null's to Object.opEquals()
+		if (o1 is o2 ||
+		    (!(o1 is null) && !(o2 is null) && o1.opEquals(o2)))
+		    continue;
+		return 0;
+	    }
+	    return 1;
+	}
+	return 0;
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	Object[] s1 = *cast(Object[]*)p1;
+	Object[] s2 = *cast(Object[]*)p2;
+	int c;
+
+	c = cast(int)s1.length - cast(int)s2.length;
+	if (c == 0)
+	{
+	    for (size_t u = 0; u < s1.length; u++)
+	    {	Object o1 = s1[u];
+		Object o2 = s2[u];
+
+		if (o1 is o2)
+		    continue;
+
+		// Regard null references as always being "less than"
+		if (o1)
+		{
+		    if (!o2)
+		    {	c = 1;
+			break;
+		    }
+		    c = o1.opCmp(o2);
+		    if (c)
+			break;
+		}
+		else
+		{   c = -1;
+		    break;
+		}
+	    }
+	}
+	return c;
+    }
+
+    size_t tsize()
+    {
+	return (Object[]).sizeof;
+    }
+
+    uint flags()
+    {
+	return 1;
+    }
+
+    TypeInfo next()
+    {
+	return typeid(Object);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfounsupported/ti_Acdouble.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,103 @@
+/*
+ *  Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+module std.typeinfo.ti_Acdouble;
+
+private import std.typeinfo.ti_cdouble;
+
+// cdouble[]
+
+class TypeInfo_Ar : TypeInfo
+{
+    char[] toString() { return "cdouble[]"; }
+
+    hash_t getHash(void *p)
+    {	cdouble[] s = *cast(cdouble[]*)p;
+	size_t len = s.length;
+	cdouble *str = s.ptr;
+	hash_t hash = 0;
+
+	while (len)
+	{
+	    hash *= 9;
+	    hash += (cast(uint *)str)[0];
+	    hash += (cast(uint *)str)[1];
+	    hash += (cast(uint *)str)[2];
+	    hash += (cast(uint *)str)[3];
+	    str++;
+	    len--;
+	}
+
+	return hash;
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	cdouble[] s1 = *cast(cdouble[]*)p1;
+	cdouble[] s2 = *cast(cdouble[]*)p2;
+	size_t len = s1.length;
+
+	if (len != s2.length)
+	    return 0;
+	for (size_t u = 0; u < len; u++)
+	{
+	    int c = TypeInfo_r._equals(s1[u], s2[u]);
+	    if (c == 0)
+		return 0;
+	}
+	return 1;
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	cdouble[] s1 = *cast(cdouble[]*)p1;
+	cdouble[] s2 = *cast(cdouble[]*)p2;
+	size_t len = s1.length;
+
+	if (s2.length < len)
+	    len = s2.length;
+	for (size_t u = 0; u < len; u++)
+	{
+	    int c = TypeInfo_r._compare(s1[u], s2[u]);
+	    if (c)
+		return c;
+	}
+	return cast(int)s1.length - cast(int)s2.length;
+    }
+
+    size_t tsize()
+    {
+	return (cdouble[]).sizeof;
+    }
+
+    uint flags()
+    {
+	return 1;
+    }
+
+    TypeInfo next()
+    {
+	return typeid(cdouble);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfounsupported/ti_Acfloat.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,101 @@
+/*
+ *  Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+module std.typeinfo.ti_Acfloat;
+
+private import std.typeinfo.ti_cfloat;
+
+// cfloat[]
+
+class TypeInfo_Aq : TypeInfo
+{
+    char[] toString() { return "cfloat[]"; }
+
+    hash_t getHash(void *p)
+    {	cfloat[] s = *cast(cfloat[]*)p;
+	size_t len = s.length;
+	cfloat *str = s.ptr;
+	hash_t hash = 0;
+
+	while (len)
+	{
+	    hash *= 9;
+	    hash += (cast(uint *)str)[0];
+	    hash += (cast(uint *)str)[1];
+	    str++;
+	    len--;
+	}
+
+	return hash;
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	cfloat[] s1 = *cast(cfloat[]*)p1;
+	cfloat[] s2 = *cast(cfloat[]*)p2;
+	size_t len = s1.length;
+
+	if (len != s2.length)
+	    return 0;
+	for (size_t u = 0; u < len; u++)
+	{
+	    int c = TypeInfo_q._equals(s1[u], s2[u]);
+	    if (c == 0)
+		return 0;
+	}
+	return 1;
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	cfloat[] s1 = *cast(cfloat[]*)p1;
+	cfloat[] s2 = *cast(cfloat[]*)p2;
+	size_t len = s1.length;
+
+	if (s2.length < len)
+	    len = s2.length;
+	for (size_t u = 0; u < len; u++)
+	{
+	    int c = TypeInfo_q._compare(s1[u], s2[u]);
+	    if (c)
+		return c;
+	}
+	return cast(int)s1.length - cast(int)s2.length;
+    }
+
+    size_t tsize()
+    {
+	return (cfloat[]).sizeof;
+    }
+
+    uint flags()
+    {
+	return 1;
+    }
+
+    TypeInfo next()
+    {
+	return typeid(cfloat);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfounsupported/ti_Acreal.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,104 @@
+/*
+ *  Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+module std.typeinfo.ti_Acreal;
+
+private import std.typeinfo.ti_creal;
+
+// creal[]
+
+class TypeInfo_Ac : TypeInfo
+{
+    char[] toString() { return "creal[]"; }
+
+    hash_t getHash(void *p)
+    {	creal[] s = *cast(creal[]*)p;
+	size_t len = s.length;
+	creal *str = s.ptr;
+	hash_t hash = 0;
+
+	while (len)
+	{
+	    hash *= 9;
+	    hash += (cast(uint *)str)[0];
+	    hash += (cast(uint *)str)[1];
+	    hash += (cast(uint *)str)[2];
+	    hash += (cast(uint *)str)[3];
+	    hash += (cast(uint *)str)[4];
+	    str++;
+	    len--;
+	}
+
+	return hash;
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	creal[] s1 = *cast(creal[]*)p1;
+	creal[] s2 = *cast(creal[]*)p2;
+	size_t len = s1.length;
+
+	if (len != s2.length)
+	    return 0;
+	for (size_t u = 0; u < len; u++)
+	{
+	    int c = TypeInfo_c._equals(s1[u], s2[u]);
+	    if (c == 0)
+		return 0;
+	}
+	return 1;
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	creal[] s1 = *cast(creal[]*)p1;
+	creal[] s2 = *cast(creal[]*)p2;
+	size_t len = s1.length;
+
+	if (s2.length < len)
+	    len = s2.length;
+	for (size_t u = 0; u < len; u++)
+	{
+	    int c = TypeInfo_c._compare(s1[u], s2[u]);
+	    if (c)
+		return c;
+	}
+	return cast(int)s1.length - cast(int)s2.length;
+    }
+
+    size_t tsize()
+    {
+	return (creal[]).sizeof;
+    }
+
+    uint flags()
+    {
+	return 1;
+    }
+
+    TypeInfo next()
+    {
+	return typeid(creal);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfounsupported/ti_Adouble.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,112 @@
+/*
+ *  Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+module std.typeinfo.ti_Adouble;
+
+private import std.typeinfo.ti_double;
+
+// double[]
+
+class TypeInfo_Ad : TypeInfo
+{
+    char[] toString() { return "double[]"; }
+
+    hash_t getHash(void *p)
+    {	double[] s = *cast(double[]*)p;
+	size_t len = s.length;
+	auto str = s.ptr;
+	hash_t hash = 0;
+
+	while (len)
+	{
+	    hash *= 9;
+	    hash += (cast(uint *)str)[0];
+	    hash += (cast(uint *)str)[1];
+	    str++;
+	    len--;
+	}
+
+	return hash;
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	double[] s1 = *cast(double[]*)p1;
+	double[] s2 = *cast(double[]*)p2;
+	size_t len = s1.length;
+
+	if (len != s2.length)
+	    return 0;
+	for (size_t u = 0; u < len; u++)
+	{
+	    int c = TypeInfo_d._equals(s1[u], s2[u]);
+	    if (c == 0)
+		return 0;
+	}
+	return 1;
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	double[] s1 = *cast(double[]*)p1;
+	double[] s2 = *cast(double[]*)p2;
+	size_t len = s1.length;
+
+	if (s2.length < len)
+	    len = s2.length;
+	for (size_t u = 0; u < len; u++)
+	{
+	    int c = TypeInfo_d._compare(s1[u], s2[u]);
+	    if (c)
+		return c;
+	}
+	return cast(int)s1.length - cast(int)s2.length;
+    }
+
+    size_t tsize()
+    {
+	return (double[]).sizeof;
+    }
+
+    uint flags()
+    {
+	return 1;
+    }
+
+    TypeInfo next()
+    {
+	return typeid(double);
+    }
+}
+
+// idouble[]
+
+class TypeInfo_Ap : TypeInfo_Ad
+{
+    char[] toString() { return "idouble[]"; }
+
+    TypeInfo next()
+    {
+	return typeid(idouble);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfounsupported/ti_Afloat.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,111 @@
+/*
+ *  Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+module std.typeinfo.ti_Afloat;
+
+private import std.typeinfo.ti_float;
+
+// float[]
+
+class TypeInfo_Af : TypeInfo
+{
+    char[] toString() { return "float[]"; }
+
+    hash_t getHash(void *p)
+    {	float[] s = *cast(float[]*)p;
+	size_t len = s.length;
+	auto str = s.ptr;
+	hash_t hash = 0;
+
+	while (len)
+	{
+	    hash *= 9;
+	    hash += *cast(uint *)str;
+	    str++;
+	    len--;
+	}
+
+	return hash;
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	float[] s1 = *cast(float[]*)p1;
+	float[] s2 = *cast(float[]*)p2;
+	size_t len = s1.length;
+
+	if (len != s2.length)
+	    return 0;
+	for (size_t u = 0; u < len; u++)
+	{
+	    int c = TypeInfo_f._equals(s1[u], s2[u]);
+	    if (c == 0)
+		return 0;
+	}
+	return 1;
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	float[] s1 = *cast(float[]*)p1;
+	float[] s2 = *cast(float[]*)p2;
+	size_t len = s1.length;
+
+	if (s2.length < len)
+	    len = s2.length;
+	for (size_t u = 0; u < len; u++)
+	{
+	    int c = TypeInfo_f._compare(s1[u], s2[u]);
+	    if (c)
+		return c;
+	}
+	return cast(int)s1.length - cast(int)s2.length;
+    }
+
+    size_t tsize()
+    {
+	return (float[]).sizeof;
+    }
+
+    uint flags()
+    {
+	return 1;
+    }
+
+    TypeInfo next()
+    {
+	return typeid(float);
+    }
+}
+
+// ifloat[]
+
+class TypeInfo_Ao : TypeInfo_Af
+{
+    char[] toString() { return "ifloat[]"; }
+
+    TypeInfo next()
+    {
+	return typeid(ifloat);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfounsupported/ti_Ag.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,202 @@
+
+module std.typeinfo.ti_Ag;
+
+private import std.string;
+private import std.c.string;
+
+// byte[]
+
+class TypeInfo_Ag : TypeInfo
+{
+    char[] toString() { return "byte[]"; }
+
+    hash_t getHash(void *p)
+    {	byte[] s = *cast(byte[]*)p;
+	size_t len = s.length;
+	byte *str = s.ptr;
+	hash_t hash = 0;
+
+	while (1)
+	{
+	    switch (len)
+	    {
+		case 0:
+		    return hash;
+
+		case 1:
+		    hash *= 9;
+		    hash += *cast(ubyte *)str;
+		    return hash;
+
+		case 2:
+		    hash *= 9;
+		    hash += *cast(ushort *)str;
+		    return hash;
+
+		case 3:
+		    hash *= 9;
+		    hash += (*cast(ushort *)str << 8) +
+			    (cast(ubyte *)str)[2];
+		    return hash;
+
+		default:
+		    hash *= 9;
+		    hash += *cast(uint *)str;
+		    str += 4;
+		    len -= 4;
+		    break;
+	    }
+	}
+
+	return hash;
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	byte[] s1 = *cast(byte[]*)p1;
+	byte[] s2 = *cast(byte[]*)p2;
+
+	return s1.length == s2.length &&
+	       memcmp(cast(byte *)s1, cast(byte *)s2, s1.length) == 0;
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	byte[] s1 = *cast(byte[]*)p1;
+	byte[] s2 = *cast(byte[]*)p2;
+	size_t len = s1.length;
+
+	if (s2.length < len)
+	    len = s2.length;
+	for (size_t u = 0; u < len; u++)
+	{
+	    int result = s1[u] - s2[u];
+	    if (result)
+		return result;
+	}
+	return cast(int)s1.length - cast(int)s2.length;
+    }
+
+    size_t tsize()
+    {
+	return (byte[]).sizeof;
+    }
+
+    uint flags()
+    {
+	return 1;
+    }
+
+    TypeInfo next()
+    {
+	return typeid(byte);
+    }
+}
+
+
+// ubyte[]
+
+class TypeInfo_Ah : TypeInfo_Ag
+{
+    char[] toString() { return "ubyte[]"; }
+
+    int compare(void *p1, void *p2)
+    {
+	char[] s1 = *cast(char[]*)p1;
+	char[] s2 = *cast(char[]*)p2;
+
+	return std.string.cmp(s1, s2);
+    }
+
+    TypeInfo next()
+    {
+	return typeid(ubyte);
+    }
+}
+
+// void[]
+
+class TypeInfo_Av : TypeInfo_Ah
+{
+    char[] toString() { return "void[]"; }
+
+    TypeInfo next()
+    {
+	return typeid(void);
+    }
+}
+
+// bool[]
+
+class TypeInfo_Ab : TypeInfo_Ah
+{
+    char[] toString() { return "bool[]"; }
+
+    TypeInfo next()
+    {
+	return typeid(bool);
+    }
+}
+
+// char[]
+
+class TypeInfo_Aa : TypeInfo_Ag
+{
+    char[] toString() { return "char[]"; }
+
+    hash_t getHash(void *p)
+    {	char[] s = *cast(char[]*)p;
+	hash_t hash = 0;
+
+version (all)
+{
+	foreach (char c; s)
+	    hash = hash * 11 + c;
+}
+else
+{
+	size_t len = s.length;
+	char *str = s;
+
+	while (1)
+	{
+	    switch (len)
+	    {
+		case 0:
+		    return hash;
+
+		case 1:
+		    hash *= 9;
+		    hash += *cast(ubyte *)str;
+		    return hash;
+
+		case 2:
+		    hash *= 9;
+		    hash += *cast(ushort *)str;
+		    return hash;
+
+		case 3:
+		    hash *= 9;
+		    hash += (*cast(ushort *)str << 8) +
+			    (cast(ubyte *)str)[2];
+		    return hash;
+
+		default:
+		    hash *= 9;
+		    hash += *cast(uint *)str;
+		    str += 4;
+		    len -= 4;
+		    break;
+	    }
+	}
+}
+	return hash;
+    }
+
+    TypeInfo next()
+    {
+	return typeid(char);
+    }
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfounsupported/ti_Aint.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,111 @@
+
+module std.typeinfo.ti_Aint;
+
+private import std.c.string;
+
+// int[]
+
+class TypeInfo_Ai : TypeInfo
+{
+    char[] toString() { return "int[]"; }
+
+    hash_t getHash(void *p)
+    {	int[] s = *cast(int[]*)p;
+	auto len = s.length;
+	auto str = s.ptr;
+	hash_t hash = 0;
+
+	while (len)
+	{
+	    hash *= 9;
+	    hash += *cast(uint *)str;
+	    str++;
+	    len--;
+	}
+
+	return hash;
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	int[] s1 = *cast(int[]*)p1;
+	int[] s2 = *cast(int[]*)p2;
+
+	return s1.length == s2.length &&
+	       memcmp(cast(void *)s1, cast(void *)s2, s1.length * int.sizeof) == 0;
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	int[] s1 = *cast(int[]*)p1;
+	int[] s2 = *cast(int[]*)p2;
+	size_t len = s1.length;
+
+	if (s2.length < len)
+	    len = s2.length;
+	for (size_t u = 0; u < len; u++)
+	{
+	    int result = s1[u] - s2[u];
+	    if (result)
+		return result;
+	}
+	return cast(int)s1.length - cast(int)s2.length;
+    }
+
+    size_t tsize()
+    {
+	return (int[]).sizeof;
+    }
+
+    uint flags()
+    {
+	return 1;
+    }
+
+    TypeInfo next()
+    {
+	return typeid(int);
+    }
+}
+
+// uint[]
+
+class TypeInfo_Ak : TypeInfo_Ai
+{
+    char[] toString() { return "uint[]"; }
+
+    int compare(void *p1, void *p2)
+    {
+	uint[] s1 = *cast(uint[]*)p1;
+	uint[] s2 = *cast(uint[]*)p2;
+	size_t len = s1.length;
+
+	if (s2.length < len)
+	    len = s2.length;
+	for (size_t u = 0; u < len; u++)
+	{
+	    int result = s1[u] - s2[u];
+	    if (result)
+		return result;
+	}
+	return cast(int)s1.length - cast(int)s2.length;
+    }
+
+    TypeInfo next()
+    {
+	return typeid(uint);
+    }
+}
+
+// dchar[]
+
+class TypeInfo_Aw : TypeInfo_Ak
+{
+    char[] toString() { return "dchar[]"; }
+
+    TypeInfo next()
+    {
+	return typeid(dchar);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfounsupported/ti_Along.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,103 @@
+
+module std.typeinfo.ti_Along;
+
+private import std.c.string;
+
+// long[]
+
+class TypeInfo_Al : TypeInfo
+{
+    char[] toString() { return "long[]"; }
+
+    hash_t getHash(void *p)
+    {	long[] s = *cast(long[]*)p;
+	size_t len = s.length;
+	auto str = s.ptr;
+	hash_t hash = 0;
+
+	while (len)
+	{
+	    hash *= 9;
+	    hash += *cast(uint *)str + *(cast(uint *)str + 1);
+	    str++;
+	    len--;
+	}
+
+	return hash;
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	long[] s1 = *cast(long[]*)p1;
+	long[] s2 = *cast(long[]*)p2;
+
+	return s1.length == s2.length &&
+	       memcmp(cast(void *)s1, cast(void *)s2, s1.length * long.sizeof) == 0;
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	long[] s1 = *cast(long[]*)p1;
+	long[] s2 = *cast(long[]*)p2;
+	size_t len = s1.length;
+
+	if (s2.length < len)
+	    len = s2.length;
+	for (size_t u = 0; u < len; u++)
+	{
+	    if (s1[u] < s2[u])
+		return -1;
+	    else if (s1[u] > s2[u])
+		return 1;
+	}
+	return cast(int)s1.length - cast(int)s2.length;
+    }
+
+    size_t tsize()
+    {
+	return (long[]).sizeof;
+    }
+
+    uint flags()
+    {
+	return 1;
+    }
+
+    TypeInfo next()
+    {
+	return typeid(long);
+    }
+}
+
+
+// ulong[]
+
+class TypeInfo_Am : TypeInfo_Al
+{
+    char[] toString() { return "ulong[]"; }
+
+    int compare(void *p1, void *p2)
+    {
+	ulong[] s1 = *cast(ulong[]*)p1;
+	ulong[] s2 = *cast(ulong[]*)p2;
+	size_t len = s1.length;
+
+	if (s2.length < len)
+	    len = s2.length;
+	for (size_t u = 0; u < len; u++)
+	{
+	    if (s1[u] < s2[u])
+		return -1;
+	    else if (s1[u] > s2[u])
+		return 1;
+	}
+	return cast(int)s1.length - cast(int)s2.length;
+    }
+
+    TypeInfo next()
+    {
+	return typeid(ulong);
+    }
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfounsupported/ti_Areal.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,113 @@
+/*
+ *  Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+module std.typeinfo.ti_Areal;
+
+private import std.typeinfo.ti_real;
+
+// real[]
+
+class TypeInfo_Ae : TypeInfo
+{
+    char[] toString() { return "real[]"; }
+
+    hash_t getHash(void *p)
+    {	real[] s = *cast(real[]*)p;
+	size_t len = s.length;
+	auto str = s.ptr;
+	hash_t hash = 0;
+
+	while (len)
+	{
+	    hash *= 9;
+	    hash += (cast(uint *)str)[0];
+	    hash += (cast(uint *)str)[1];
+	    hash += (cast(ushort *)str)[4];
+	    str++;
+	    len--;
+	}
+
+	return hash;
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	real[] s1 = *cast(real[]*)p1;
+	real[] s2 = *cast(real[]*)p2;
+	size_t len = s1.length;
+
+	if (len != s2.length)
+	    return 0;
+	for (size_t u = 0; u < len; u++)
+	{
+	    int c = TypeInfo_e._equals(s1[u], s2[u]);
+	    if (c == 0)
+		return 0;
+	}
+	return 1;
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	real[] s1 = *cast(real[]*)p1;
+	real[] s2 = *cast(real[]*)p2;
+	size_t len = s1.length;
+
+	if (s2.length < len)
+	    len = s2.length;
+	for (size_t u = 0; u < len; u++)
+	{
+	    int c = TypeInfo_e._compare(s1[u], s2[u]);
+	    if (c)
+		return c;
+	}
+	return cast(int)s1.length - cast(int)s2.length;
+    }
+
+    size_t tsize()
+    {
+	return (real[]).sizeof;
+    }
+
+    uint flags()
+    {
+	return 1;
+    }
+
+    TypeInfo next()
+    {
+	return typeid(real);
+    }
+}
+
+// ireal[]
+
+class TypeInfo_Aj : TypeInfo_Ae
+{
+    char[] toString() { return "ireal[]"; }
+
+    TypeInfo next()
+    {
+	return typeid(ireal);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfounsupported/ti_Ashort.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,126 @@
+
+module std.typeinfo.ti_Ashort;
+
+private import std.c.string;
+
+// short[]
+
+class TypeInfo_As : TypeInfo
+{
+    char[] toString() { return "short[]"; }
+
+    hash_t getHash(void *p)
+    {	short[] s = *cast(short[]*)p;
+	size_t len = s.length;
+	short *str = s.ptr;
+	hash_t hash = 0;
+
+	while (1)
+	{
+	    switch (len)
+	    {
+		case 0:
+		    return hash;
+
+		case 1:
+		    hash *= 9;
+		    hash += *cast(ushort *)str;
+		    return hash;
+
+		default:
+		    hash *= 9;
+		    hash += *cast(uint *)str;
+		    str += 2;
+		    len -= 2;
+		    break;
+	    }
+	}
+
+	return hash;
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	short[] s1 = *cast(short[]*)p1;
+	short[] s2 = *cast(short[]*)p2;
+
+	return s1.length == s2.length &&
+	       memcmp(cast(void *)s1, cast(void *)s2, s1.length * short.sizeof) == 0;
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	short[] s1 = *cast(short[]*)p1;
+	short[] s2 = *cast(short[]*)p2;
+	size_t len = s1.length;
+
+	if (s2.length < len)
+	    len = s2.length;
+	for (size_t u = 0; u < len; u++)
+	{
+	    int result = s1[u] - s2[u];
+	    if (result)
+		return result;
+	}
+	return cast(int)s1.length - cast(int)s2.length;
+    }
+
+    size_t tsize()
+    {
+	return (short[]).sizeof;
+    }
+
+    uint flags()
+    {
+	return 1;
+    }
+
+    TypeInfo next()
+    {
+	return typeid(short);
+    }
+}
+
+
+// ushort[]
+
+class TypeInfo_At : TypeInfo_As
+{
+    char[] toString() { return "ushort[]"; }
+
+    int compare(void *p1, void *p2)
+    {
+	ushort[] s1 = *cast(ushort[]*)p1;
+	ushort[] s2 = *cast(ushort[]*)p2;
+	size_t len = s1.length;
+
+	if (s2.length < len)
+	    len = s2.length;
+	for (size_t u = 0; u < len; u++)
+	{
+	    int result = s1[u] - s2[u];
+	    if (result)
+		return result;
+	}
+	return cast(int)s1.length - cast(int)s2.length;
+    }
+
+    TypeInfo next()
+    {
+	return typeid(ushort);
+    }
+}
+
+// wchar[]
+
+class TypeInfo_Au : TypeInfo_At
+{
+    char[] toString() { return "wchar[]"; }
+
+    TypeInfo next()
+    {
+	return typeid(wchar);
+    }
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfounsupported/ti_C.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,76 @@
+/*
+ *  Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+module std.typeinfo.ti_C;
+
+// Object
+
+class TypeInfo_C : TypeInfo
+{
+    hash_t getHash(void *p)
+    {
+	Object o = *cast(Object*)p;
+	assert(o);
+	return o.toHash();
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	Object o1 = *cast(Object*)p1;
+	Object o2 = *cast(Object*)p2;
+
+	return o1 == o2;
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	Object o1 = *cast(Object*)p1;
+	Object o2 = *cast(Object*)p2;
+	int c = 0;
+
+	// Regard null references as always being "less than"
+	if (!(o1 is o2))
+	{
+	    if (o1)
+	    {	if (!o2)
+		    c = 1;
+		else
+		    c = o1.opCmp(o2);
+	    }
+	    else
+		c = -1;
+	}
+	return c;
+    }
+
+    size_t tsize()
+    {
+	return Object.sizeof;
+    }
+
+    uint flags()
+    {
+	return 1;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfounsupported/ti_byte.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,39 @@
+
+// byte
+
+module std.typeinfo.ti_byte;
+
+class TypeInfo_g : TypeInfo
+{
+    char[] toString() { return "byte"; }
+
+    hash_t getHash(void *p)
+    {
+	return *cast(byte *)p;
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	return *cast(byte *)p1 == *cast(byte *)p2;
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	return *cast(byte *)p1 - *cast(byte *)p2;
+    }
+
+    size_t tsize()
+    {
+	return byte.sizeof;
+    }
+
+    void swap(void *p1, void *p2)
+    {
+	byte t;
+
+	t = *cast(byte *)p1;
+	*cast(byte *)p1 = *cast(byte *)p2;
+	*cast(byte *)p2 = t;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfounsupported/ti_cdouble.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,67 @@
+
+// cdouble
+
+module std.typeinfo.ti_cdouble;
+
+class TypeInfo_r : TypeInfo
+{
+    char[] toString() { return "cdouble"; }
+
+    hash_t getHash(void *p)
+    {
+	return (cast(uint *)p)[0] + (cast(uint *)p)[1] +
+	       (cast(uint *)p)[2] + (cast(uint *)p)[3];
+    }
+
+    static int _equals(cdouble f1, cdouble f2)
+    {
+	return f1 == f2;
+    }
+
+    static int _compare(cdouble f1, cdouble f2)
+    {   int result;
+
+	if (f1.re < f2.re)
+	    result = -1;
+	else if (f1.re > f2.re)
+	    result = 1;
+	else if (f1.im < f2.im)
+	    result = -1;
+	else if (f1.im > f2.im)
+	    result = 1;
+	else
+	    result = 0;
+        return result;
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	return _equals(*cast(cdouble *)p1, *cast(cdouble *)p2);
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	return _compare(*cast(cdouble *)p1, *cast(cdouble *)p2);
+    }
+
+    size_t tsize()
+    {
+	return cdouble.sizeof;
+    }
+
+    void swap(void *p1, void *p2)
+    {
+	cdouble t;
+
+	t = *cast(cdouble *)p1;
+	*cast(cdouble *)p1 = *cast(cdouble *)p2;
+	*cast(cdouble *)p2 = t;
+    }
+
+    void[] init()
+    {	static cdouble r;
+
+	return (cast(cdouble *)&r)[0 .. 1];
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfounsupported/ti_cfloat.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,66 @@
+
+// cfloat
+
+module std.typeinfo.ti_cfloat;
+
+class TypeInfo_q : TypeInfo
+{
+    char[] toString() { return "cfloat"; }
+
+    hash_t getHash(void *p)
+    {
+	return (cast(uint *)p)[0] + (cast(uint *)p)[1];
+    }
+
+    static int _equals(cfloat f1, cfloat f2)
+    {
+	return f1 == f2;
+    }
+
+    static int _compare(cfloat f1, cfloat f2)
+    {   int result;
+
+	if (f1.re < f2.re)
+	    result = -1;
+	else if (f1.re > f2.re)
+	    result = 1;
+	else if (f1.im < f2.im)
+	    result = -1;
+	else if (f1.im > f2.im)
+	    result = 1;
+	else
+	    result = 0;
+        return result;
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	return _equals(*cast(cfloat *)p1, *cast(cfloat *)p2);
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	return _compare(*cast(cfloat *)p1, *cast(cfloat *)p2);
+    }
+
+    size_t tsize()
+    {
+	return cfloat.sizeof;
+    }
+
+    void swap(void *p1, void *p2)
+    {
+	cfloat t;
+
+	t = *cast(cfloat *)p1;
+	*cast(cfloat *)p1 = *cast(cfloat *)p2;
+	*cast(cfloat *)p2 = t;
+    }
+
+    void[] init()
+    {	static cfloat r;
+
+	return (cast(cfloat *)&r)[0 .. 1];
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfounsupported/ti_char.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,43 @@
+
+module std.typeinfo.ti_char;
+
+class TypeInfo_a : TypeInfo
+{
+    char[] toString() { return "char"; }
+
+    hash_t getHash(void *p)
+    {
+	return *cast(char *)p;
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	return *cast(char *)p1 == *cast(char *)p2;
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	return *cast(char *)p1 - *cast(char *)p2;
+    }
+
+    size_t tsize()
+    {
+	return char.sizeof;
+    }
+
+    void swap(void *p1, void *p2)
+    {
+	char t;
+
+	t = *cast(char *)p1;
+	*cast(char *)p1 = *cast(char *)p2;
+	*cast(char *)p2 = t;
+    }
+
+    void[] init()
+    {	static char c;
+
+	return (cast(char *)&c)[0 .. 1];
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfounsupported/ti_creal.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,68 @@
+
+// creal
+
+module std.typeinfo.ti_creal;
+
+class TypeInfo_c : TypeInfo
+{
+    char[] toString() { return "creal"; }
+
+    hash_t getHash(void *p)
+    {
+	return (cast(uint *)p)[0] + (cast(uint *)p)[1] +
+	       (cast(uint *)p)[2] + (cast(uint *)p)[3] +
+	       (cast(uint *)p)[4];
+    }
+
+    static int _equals(creal f1, creal f2)
+    {
+	return f1 == f2;
+    }
+
+    static int _compare(creal f1, creal f2)
+    {   int result;
+
+	if (f1.re < f2.re)
+	    result = -1;
+	else if (f1.re > f2.re)
+	    result = 1;
+	else if (f1.im < f2.im)
+	    result = -1;
+	else if (f1.im > f2.im)
+	    result = 1;
+	else
+	    result = 0;
+        return result;
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	return _equals(*cast(creal *)p1, *cast(creal *)p2);
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	return _compare(*cast(creal *)p1, *cast(creal *)p2);
+    }
+
+    size_t tsize()
+    {
+	return creal.sizeof;
+    }
+
+    void swap(void *p1, void *p2)
+    {
+	creal t;
+
+	t = *cast(creal *)p1;
+	*cast(creal *)p1 = *cast(creal *)p2;
+	*cast(creal *)p2 = t;
+    }
+
+    void[] init()
+    {	static creal r;
+
+	return (cast(creal *)&r)[0 .. 1];
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfounsupported/ti_dchar.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,45 @@
+
+// dchar
+
+module std.typeinfo.ti_dchar;
+
+class TypeInfo_w : TypeInfo
+{
+    char[] toString() { return "dchar"; }
+
+    hash_t getHash(void *p)
+    {
+	return *cast(dchar *)p;
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	return *cast(dchar *)p1 == *cast(dchar *)p2;
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	return *cast(dchar *)p1 - *cast(dchar *)p2;
+    }
+
+    size_t tsize()
+    {
+	return dchar.sizeof;
+    }
+
+    void swap(void *p1, void *p2)
+    {
+	dchar t;
+
+	t = *cast(dchar *)p1;
+	*cast(dchar *)p1 = *cast(dchar *)p2;
+	*cast(dchar *)p2 = t;
+    }
+
+    void[] init()
+    {	static dchar c;
+
+	return (cast(dchar *)&c)[0 .. 1];
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfounsupported/ti_delegate.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,40 @@
+
+// delegate
+
+module std.typeinfo.ti_delegate;
+
+alias void delegate(int) dg;
+
+class TypeInfo_D : TypeInfo
+{
+    hash_t getHash(void *p)
+    {	long l = *cast(long *)p;
+
+	return cast(uint)(l + (l >> 32));
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	return *cast(dg *)p1 == *cast(dg *)p2;
+    }
+
+    size_t tsize()
+    {
+	return dg.sizeof;
+    }
+
+    void swap(void *p1, void *p2)
+    {
+	dg t;
+
+	t = *cast(dg *)p1;
+	*cast(dg *)p1 = *cast(dg *)p2;
+	*cast(dg *)p2 = t;
+    }
+
+    uint flags()
+    {
+	return 1;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfounsupported/ti_double.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,67 @@
+
+// double
+
+module std.typeinfo.ti_double;
+
+private import std.math;
+
+class TypeInfo_d : TypeInfo
+{
+    char[] toString() { return "double"; }
+
+    hash_t getHash(void *p)
+    {
+	return (cast(uint *)p)[0] + (cast(uint *)p)[1];
+    }
+
+    static int _equals(double f1, double f2)
+    {
+	return f1 == f2 ||
+		(isnan(f1) && isnan(f2));
+    }
+
+    static int _compare(double d1, double d2)
+    {
+	if (d1 !<>= d2)		// if either are NaN
+	{
+	    if (isnan(d1))
+	    {	if (isnan(d2))
+		    return 0;
+		return -1;
+	    }
+	    return 1;
+	}
+	return (d1 == d2) ? 0 : ((d1 < d2) ? -1 : 1);
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	return _equals(*cast(double *)p1, *cast(double *)p2);
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	return _compare(*cast(double *)p1, *cast(double *)p2);
+    }
+
+    size_t tsize()
+    {
+	return double.sizeof;
+    }
+
+    void swap(void *p1, void *p2)
+    {
+	double t;
+
+	t = *cast(double *)p1;
+	*cast(double *)p1 = *cast(double *)p2;
+	*cast(double *)p2 = t;
+    }
+
+    void[] init()
+    {	static double r;
+
+	return (cast(double *)&r)[0 .. 1];
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfounsupported/ti_float.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,67 @@
+
+// float
+
+module std.typeinfo.ti_float;
+
+private import std.math;
+
+class TypeInfo_f : TypeInfo
+{
+    char[] toString() { return "float"; }
+
+    hash_t getHash(void *p)
+    {
+	return *cast(uint *)p;
+    }
+
+    static int _equals(float f1, float f2)
+    {
+	return f1 == f2 ||
+		(isnan(f1) && isnan(f2));
+    }
+
+    static int _compare(float d1, float d2)
+    {
+	if (d1 !<>= d2)		// if either are NaN
+	{
+	    if (isnan(d1))
+	    {	if (isnan(d2))
+		    return 0;
+		return -1;
+	    }
+	    return 1;
+	}
+	return (d1 == d2) ? 0 : ((d1 < d2) ? -1 : 1);
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	return _equals(*cast(float *)p1, *cast(float *)p2);
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	return _compare(*cast(float *)p1, *cast(float *)p2);
+    }
+
+    size_t tsize()
+    {
+	return float.sizeof;
+    }
+
+    void swap(void *p1, void *p2)
+    {
+	float t;
+
+	t = *cast(float *)p1;
+	*cast(float *)p1 = *cast(float *)p2;
+	*cast(float *)p2 = t;
+    }
+
+    void[] init()
+    {	static float r;
+
+	return (cast(float *)&r)[0 .. 1];
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfounsupported/ti_idouble.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,12 @@
+
+// idouble
+
+module std.typeinfo.ti_idouble;
+
+private import std.typeinfo.ti_double;
+
+class TypeInfo_p : TypeInfo_d
+{
+    char[] toString() { return "idouble"; }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfounsupported/ti_ifloat.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,12 @@
+
+// ifloat
+
+module std.typeinfo.ti_ifloat;
+
+private import std.typeinfo.ti_float;
+
+class TypeInfo_o : TypeInfo_f
+{
+    char[] toString() { return "ifloat"; }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfounsupported/ti_int.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,43 @@
+
+// int
+
+module std.typeinfo.ti_int;
+
+class TypeInfo_i : TypeInfo
+{
+    char[] toString() { return "int"; }
+
+    hash_t getHash(void *p)
+    {
+	return *cast(uint *)p;
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	return *cast(uint *)p1 == *cast(uint *)p2;
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	if (*cast(int*) p1 < *cast(int*) p2)
+	    return -1;
+	else if (*cast(int*) p1 > *cast(int*) p2)
+	    return 1;
+	return 0;
+    }
+
+    size_t tsize()
+    {
+	return int.sizeof;
+    }
+
+    void swap(void *p1, void *p2)
+    {
+	int t;
+
+	t = *cast(int *)p1;
+	*cast(int *)p1 = *cast(int *)p2;
+	*cast(int *)p2 = t;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfounsupported/ti_ireal.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,12 @@
+
+// ireal
+
+module std.typeinfo.ti_ireal;
+
+private import std.typeinfo.ti_real;
+
+class TypeInfo_j : TypeInfo_e
+{
+    char[] toString() { return "ireal"; }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfounsupported/ti_long.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,43 @@
+
+// long
+
+module std.typeinfo.ti_long;
+
+class TypeInfo_l : TypeInfo
+{
+    char[] toString() { return "long"; }
+
+    hash_t getHash(void *p)
+    {
+	return *cast(uint *)p + (cast(uint *)p)[1];
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	return *cast(long *)p1 == *cast(long *)p2;
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	if (*cast(long *)p1 < *cast(long *)p2)
+	    return -1;
+	else if (*cast(long *)p1 > *cast(long *)p2)
+	    return 1;
+	return 0;
+    }
+
+    size_t tsize()
+    {
+	return long.sizeof;
+    }
+
+    void swap(void *p1, void *p2)
+    {
+	long t;
+
+	t = *cast(long *)p1;
+	*cast(long *)p1 = *cast(long *)p2;
+	*cast(long *)p2 = t;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfounsupported/ti_ptr.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,42 @@
+
+// pointer
+
+module std.typeinfo.ti_ptr;
+
+class TypeInfo_P : TypeInfo
+{
+    hash_t getHash(void *p)
+    {
+	return cast(uint)*cast(void* *)p;
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	return *cast(void* *)p1 == *cast(void* *)p2;
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	return *cast(void* *)p1 - *cast(void* *)p2;
+    }
+
+    size_t tsize()
+    {
+	return (void*).sizeof;
+    }
+
+    void swap(void *p1, void *p2)
+    {
+	void* t;
+
+	t = *cast(void* *)p1;
+	*cast(void* *)p1 = *cast(void* *)p2;
+	*cast(void* *)p2 = t;
+    }
+
+    uint flags()
+    {
+	return 1;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfounsupported/ti_real.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,67 @@
+
+// real
+
+module std.typeinfo.ti_real;
+
+private import std.math;
+
+class TypeInfo_e : TypeInfo
+{
+    char[] toString() { return "real"; }
+
+    hash_t getHash(void *p)
+    {
+	return (cast(uint *)p)[0] + (cast(uint *)p)[1] + (cast(ushort *)p)[4];
+    }
+
+    static int _equals(real f1, real f2)
+    {
+	return f1 == f2 ||
+		(isnan(f1) && isnan(f2));
+    }
+
+    static int _compare(real d1, real d2)
+    {
+	if (d1 !<>= d2)		// if either are NaN
+	{
+	    if (isnan(d1))
+	    {	if (isnan(d2))
+		    return 0;
+		return -1;
+	    }
+	    return 1;
+	}
+	return (d1 == d2) ? 0 : ((d1 < d2) ? -1 : 1);
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	return _equals(*cast(real *)p1, *cast(real *)p2);
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	return _compare(*cast(real *)p1, *cast(real *)p2);
+    }
+
+    size_t tsize()
+    {
+	return real.sizeof;
+    }
+
+    void swap(void *p1, void *p2)
+    {
+	real t;
+
+	t = *cast(real *)p1;
+	*cast(real *)p1 = *cast(real *)p2;
+	*cast(real *)p2 = t;
+    }
+
+    void[] init()
+    {	static real r;
+
+	return (cast(real *)&r)[0 .. 1];
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfounsupported/ti_short.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,39 @@
+
+// short
+
+module std.typeinfo.ti_short;
+
+class TypeInfo_s : TypeInfo
+{
+    char[] toString() { return "short"; }
+
+    hash_t getHash(void *p)
+    {
+	return *cast(short *)p;
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	return *cast(short *)p1 == *cast(short *)p2;
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	return *cast(short *)p1 - *cast(short *)p2;
+    }
+
+    size_t tsize()
+    {
+	return short.sizeof;
+    }
+
+    void swap(void *p1, void *p2)
+    {
+	short t;
+
+	t = *cast(short *)p1;
+	*cast(short *)p1 = *cast(short *)p2;
+	*cast(short *)p2 = t;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfounsupported/ti_ubyte.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,43 @@
+
+// ubyte
+
+module std.typeinfo.ti_ubyte;
+
+class TypeInfo_h : TypeInfo
+{
+    char[] toString() { return "ubyte"; }
+
+    hash_t getHash(void *p)
+    {
+	return *cast(ubyte *)p;
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	return *cast(ubyte *)p1 == *cast(ubyte *)p2;
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	return *cast(ubyte *)p1 - *cast(ubyte *)p2;
+    }
+
+    size_t tsize()
+    {
+	return ubyte.sizeof;
+    }
+
+    void swap(void *p1, void *p2)
+    {
+	ubyte t;
+
+	t = *cast(ubyte *)p1;
+	*cast(ubyte *)p1 = *cast(ubyte *)p2;
+	*cast(ubyte *)p2 = t;
+    }
+}
+
+class TypeInfo_b : TypeInfo_h
+{
+    char[] toString() { return "bool"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfounsupported/ti_uint.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,43 @@
+
+// uint
+
+module std.typeinfo.ti_uint;
+
+class TypeInfo_k : TypeInfo
+{
+    char[] toString() { return "uint"; }
+
+    hash_t getHash(void *p)
+    {
+	return *cast(uint *)p;
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	return *cast(uint *)p1 == *cast(uint *)p2;
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	if (*cast(uint*) p1 < *cast(uint*) p2)
+	    return -1;
+	else if (*cast(uint*) p1 > *cast(uint*) p2)
+	    return 1;
+	return 0;
+    }
+
+    size_t tsize()
+    {
+	return uint.sizeof;
+    }
+
+    void swap(void *p1, void *p2)
+    {
+	int t;
+
+	t = *cast(uint *)p1;
+	*cast(uint *)p1 = *cast(uint *)p2;
+	*cast(uint *)p2 = t;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfounsupported/ti_ulong.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,43 @@
+
+// ulong
+
+module std.typeinfo.ti_ulong;
+
+class TypeInfo_m : TypeInfo
+{
+    char[] toString() { return "ulong"; }
+
+    hash_t getHash(void *p)
+    {
+	return *cast(uint *)p + (cast(uint *)p)[1];
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	return *cast(ulong *)p1 == *cast(ulong *)p2;
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	if (*cast(ulong *)p1 < *cast(ulong *)p2)
+	    return -1;
+	else if (*cast(ulong *)p1 > *cast(ulong *)p2)
+	    return 1;
+	return 0;
+    }
+
+    size_t tsize()
+    {
+	return ulong.sizeof;
+    }
+
+    void swap(void *p1, void *p2)
+    {
+	ulong t;
+
+	t = *cast(ulong *)p1;
+	*cast(ulong *)p1 = *cast(ulong *)p2;
+	*cast(ulong *)p2 = t;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfounsupported/ti_ushort.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,39 @@
+
+// ushort
+
+module std.typeinfo.ti_ushort;
+
+class TypeInfo_t : TypeInfo
+{
+    char[] toString() { return "ushort"; }
+
+    hash_t getHash(void *p)
+    {
+	return *cast(ushort *)p;
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	return *cast(ushort *)p1 == *cast(ushort *)p2;
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	return *cast(ushort *)p1 - *cast(ushort *)p2;
+    }
+
+    size_t tsize()
+    {
+	return ushort.sizeof;
+    }
+
+    void swap(void *p1, void *p2)
+    {
+	ushort t;
+
+	t = *cast(ushort *)p1;
+	*cast(ushort *)p1 = *cast(ushort *)p2;
+	*cast(ushort *)p2 = t;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfounsupported/ti_void.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,44 @@
+
+// void
+
+module std.typeinfo.ti_void;
+
+class TypeInfo_v : TypeInfo
+{
+    char[] toString() { return "void"; }
+
+    hash_t getHash(void *p)
+    {
+	assert(0);
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	return *cast(byte *)p1 == *cast(byte *)p2;
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	return *cast(byte *)p1 - *cast(byte *)p2;
+    }
+
+    size_t tsize()
+    {
+	return void.sizeof;
+    }
+
+    void swap(void *p1, void *p2)
+    {
+	byte t;
+
+	t = *cast(byte *)p1;
+	*cast(byte *)p1 = *cast(byte *)p2;
+	*cast(byte *)p2 = t;
+    }
+
+    uint flags()
+    {
+	return 1;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/typeinfounsupported/ti_wchar.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,44 @@
+
+module std.typeinfo.ti_wchar;
+
+
+class TypeInfo_u : TypeInfo
+{
+    char[] toString() { return "wchar"; }
+
+    hash_t getHash(void *p)
+    {
+	return *cast(wchar *)p;
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	return *cast(wchar *)p1 == *cast(wchar *)p2;
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	return *cast(wchar *)p1 - *cast(wchar *)p2;
+    }
+
+    size_t tsize()
+    {
+	return wchar.sizeof;
+    }
+
+    void swap(void *p1, void *p2)
+    {
+	wchar t;
+
+	t = *cast(wchar *)p1;
+	*cast(wchar *)p1 = *cast(wchar *)p2;
+	*cast(wchar *)p2 = t;
+    }
+
+    void[] init()
+    {	static wchar c;
+
+	return (cast(wchar *)&c)[0 .. 1];
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/premake.lua	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,34 @@
+project.name = llvmdc
+project.bindir = "bin"
+
+package = newpackage()
+package.name = "idgen"
+package.kind = "exe"
+package.language = "c++"
+package.files = { "dmd/idgen.c" }
+package.buildoptions = { "-x c++" }
+package.postbuildcommands = { "bin/idgen", "mv -f id.c id.h dmd" }
+
+package = newpackage()
+package.name = "impcnvgen"
+package.kind = "exe"
+package.language = "c++"
+package.files = { "dmd/impcnvgen.c" }
+package.buildoptions = { "-x c++" }
+package.postbuildcommands = { "bin/impcnvgen", "mv -f impcnvtab.c dmd" }
+
+package = newpackage()
+package.name = "llvmdc"
+package.kind = "exe"
+package.language = "c++"
+package.files = { matchfiles("dmd/*.c"), matchfiles("gen/*.c") }
+package.excludes = { "dmd/idgen.c", "dmd/impcnvgen.c" }
+package.buildoptions = { "-x c++", "`llvm-config --cxxflags`" }
+package.linkoptions = { "`llvm-config --libs native bitwriter bitreader`", "`llvm-config --ldflags`" }
+package.defines = { "IN_LLVM", "_DH" }
+package.config.Release.defines = { "LLVMD_NO_LOGGER" }
+package.config.Debug.buildoptions = { "-g" }
+--package.targetprefix = "llvm"
+package.includepaths = { "dmd" }
+--package.postbuildcommands = { "cd runtime; ./build.sh; cd .." }
+package.links = { "gc" }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/a.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,21 @@
+module a;
+
+int i = 42;
+
+void main()
+{
+    int j;
+    j = i;
+    int* p;
+    p = &j;
+    int k = *p;
+    assert(k == 42);
+
+    byte b = -1;
+    int i = b;
+    assert(i == -1);
+
+    int* p2 = p;
+
+    printf("Done\n");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/alignment.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,21 @@
+module alignment;
+
+align(1) struct S
+{
+    ubyte b;
+    int i;
+    ubyte[2] b2;
+    long l;
+    real r;
+}
+
+void main()
+{
+    byte b;
+    short s;
+    int i;
+    long l;
+    float f;
+    double d;
+    real r;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/arrayinit.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,5 @@
+module arrayinit;
+float[4] ftable = [1,2,3,4];
+int[8] itable = [3:42,6:123];
+
+private uint[7] crc32_table = [0x00000000,0x77073096,0xee0e612c,0x990951ba,0x076dc419,0x706af48f,0xe963a535];
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/arrays.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,39 @@
+void integer()
+{
+    auto arr = new int[16];
+    arr[1] = 42;
+    arr[6] = 555;
+    print_int(arr);
+    delete arr;
+}
+
+void floating()
+{
+    auto arr = new float[6];
+    arr[1] = 3.14159265;
+    arr[3] = 1.61803399;
+    print_float(arr);
+    delete arr;
+}
+
+void print_int(int[] arr)
+{
+    printf("arr[%lu] = [", arr.length);
+    for (auto i=0; i<arr.length; i++)
+        printf("%d,", arr[i]);
+    printf("\b]\n");
+}
+
+void print_float(float[] arr)
+{
+    printf("arr[%lu] = [", arr.length);
+    for (auto i=0; i<arr.length; i++)
+        printf("%f,", arr[i]);
+    printf("\b]\n");
+}
+
+void main()
+{
+    integer();
+    floating();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/arrays2.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,19 @@
+char[] get()
+{
+    return "hello";
+}
+
+void param(char[] s)
+{
+}
+
+void refparam(ref char[] s)
+{
+}
+
+void main()
+{
+    char[] dstr = get();
+    param(dstr);
+    refparam(dstr);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/assign.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,23 @@
+module assign;
+
+// this is taken from std.intrinsic from gdc
+
+int mybtc(uint *p, uint bitnum)
+{
+    uint * q = p + (bitnum / (uint.sizeof*8));
+    uint mask = 1 << (bitnum & ((uint.sizeof*8) - 1));
+    int result = *q & mask;
+    *q ^= mask;
+    return result ? -1 : 0;
+}
+
+void main()
+{
+    uint i = 0xFFFF_FFFF;
+    int r = mybtc(&i, 31);
+    assert(r);
+    assert(i == 0x7FFF_FFFF);
+    r = mybtc(&i, 31);
+    assert(!r);
+    assert(i == 0xFFFF_FFFF);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/b.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,23 @@
+module b;
+
+struct S
+{
+    int i;
+    float[4] f;
+}
+
+void main()
+{
+    S s;
+    int i = s.i;
+    int* p = &s.i;
+    *p = 42;
+    printf("%d == %d\n", *p, s.i);
+
+    float* f = &s.f[0];
+    printf("%f == %f\n", *f, s.f[0]);
+    *f = 3.1415;
+    printf("%f == %f\n", *f, s.f[0]);
+    s.f[0] = 123.456;
+    printf("%f == %f\n", *f, s.f[0]);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/bitops.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,75 @@
+void main()
+{
+    printf("Bitwise operations test\n");
+    {   ushort a = 0xFFF0;
+        ushort b = 0x0FFF;
+        assert((a&b) == 0x0FF0);
+        assert((a|b) == 0xFFFF);
+        assert((a^b) == 0xF00F);
+    }
+    {   ubyte a = 0xFF;
+        ulong b = 0xFFFF_FFFF_FFFF_FFF0;
+        assert((a&b) == 0xF0);
+    }
+    {   ushort s = 0xFF;
+        assert((s<<1) == s*2);
+        assert((s>>>1) == s/2);
+    }
+    {   int s = -10;
+        assert((s>>1) == -5);
+        assert((s>>>1) != -5);
+    }
+    
+    {   ushort a = 0xFFF0;
+        ushort b = 0x0FFF;
+        auto t = a;
+        t &= b;
+        assert(t == 0x0FF0);
+        t = a;
+        t |= b;
+        assert(t == 0xFFFF);
+        t = a;
+        t ^= b;
+        assert(t == 0xF00F);
+    }
+    {   ubyte a = 0xFF;
+        ulong b = 0xFFFF_FFFF_FFFF_FFF0;
+        a &= b;
+        assert(a == 0xF0);
+    }
+    {   ushort s = 0xFF;
+        auto t = s;
+        t <<= 1;
+        assert(t == (s*2));
+        t = s;
+        t >>>= 1;
+        assert(t == s/2);
+    }
+    {   int s = -10;
+        auto t = s;
+        t >>= 1;
+        assert(t == -5);
+        t = s;
+        t >>>= 1;
+        assert(t != -5);
+    }
+    {   struct S
+        {
+            uint i;
+            ulong l;
+        };
+        S s = S(1,4);
+        auto a = s.i | s.l;
+        assert(a == 5);
+        s.i = 0xFFFF_00FF;
+        s.l = 0xFFFF_FFFF_0000_FF00;
+        s.l ^= s.i;
+        assert(s.l == ulong.max);
+        s.i = 0x__FFFF_FF00;
+        s.l = 0xFF00FF_FF00;
+        s.i &= s.l;
+        assert(s.i == 0x00FF_FF00);
+    }
+        
+    printf("  SUCCESS\n");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/c.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,10 @@
+module c;
+
+void main()
+{
+    ushort a = 0xFFF0;
+    ushort b = 0x0FFF;
+    auto t = a & b;
+    a &= b;
+    assert(t == a);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/classes.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,17 @@
+class C
+{
+    int i;
+    void p()
+    {
+        printf("%d\n", i);
+    }
+}
+
+void main()
+{
+    printf("should print 4\n");
+    C c = new C;
+    c.i = 4;
+    c.p();
+    //delete c;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/classes2.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,23 @@
+class A
+{
+    int i;
+    void f()
+    {
+        printf("A.f\n");
+    }
+}
+
+class B : A
+{
+    long l;
+    void f()
+    {
+        printf("B.f\n");
+    }
+}
+
+void main()
+{
+    A a = new B;
+    a.f();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/classes3.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,33 @@
+class C
+{
+    int c;
+    long f(long l)
+    {
+        return l;
+    }
+}
+
+class D : C
+{
+    int d;
+    override long f(long l)
+    {
+        return l*2;
+    }
+}
+
+void main()
+{
+    scope c = new C;
+    assert(c.f(25L) == 25);
+    scope d = new D;
+    assert(d.f(25L) == 50);
+    C cd = d;
+    assert(cd.f(25L) == 50);
+    assert(func(d,25L) == 50);
+}
+
+long func(C c, long l)
+{
+    return c.f(l);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/classes4.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,36 @@
+class A
+{
+    int i = 42;
+    double df = 3.1415;
+    this()
+    {
+    }
+    char[] toString()
+    {
+        return "A:Object";
+    }
+}
+
+class B : A
+{
+    ubyte b;
+    char[] toString()
+    {
+        return "B:A";
+    }
+}
+
+void main()
+{
+    scope a = new A;
+    char[] as = a.toString;
+    {printf("a.toString = '%.*s'\n", as.length, as.ptr);}
+
+    Object o = a;
+    char[] os = o.toString;
+    {printf("o.toString = '%.*s'\n", os.length, os.ptr);}
+
+    scope b = new B;
+    char[] bs = b.toString;
+    {printf("b.toString = '%.*s'\n", bs.length, bs.ptr);}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/comma.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,11 @@
+module comma;
+
+void main()
+{
+    int i=0,j=0;
+    for (; i<10; i++,j++)
+    {
+    }
+    assert(i == 10);
+    assert(j == 10);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/cond.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,43 @@
+version=AndAnd;
+version=OrOr;
+
+version(AndAnd)
+void andand1()
+{
+    int a,b;
+    a = 4;
+    b = 5;
+    assert(a == 4);
+    assert(b == 5);
+    assert(a+b == 9);
+    assert(a == 4 && b == 5);
+    assert(a != 3 && b == 5);
+    assert(a > 2);
+    assert(a < 54);
+    assert(a < b);
+    assert(a > b-2);
+    
+    int apb = a+b;
+    int amb = a*b;
+    assert(apb < amb && apb > a);
+}
+
+version(OrOr)
+void oror1()
+{
+    int a,b;
+    a = 10;
+    b = 1000;
+    assert(a);
+    assert(b);
+    assert(a || b);
+    assert(a > b || a < b);
+}
+
+void main()
+{
+    printf("Conditionals test\n");
+    version(AndAnd) andand1();
+    version(OrOr) oror1();
+    printf("  SUCCESS\n");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/condexp.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,14 @@
+module condexp;
+
+int f()
+{
+    return 42;
+}
+
+void main()
+{
+    int i = f() < 25 ? -1 : 1;
+    /*int j = f() > 25 ? 1 : -1;
+    assert(i);
+    assert(!j);*/
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/cyclic.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,16 @@
+void main()
+{
+    S t;
+}
+
+struct T
+{
+    int i;
+    S* s;
+}
+
+struct S
+{
+    long i;
+    T* t;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/d.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,48 @@
+module d;
+/*
+void main()
+{
+    int delegate() dg;
+    int i = dg();
+
+    struct S
+    {
+        int i;
+        long l;
+        float f;
+
+        int func()
+        {
+            return 42;
+        }
+    }
+
+    S s;
+    auto dg2 = &s.func;
+    i = dg2();
+
+    i = f(dg2, 1);
+}
+
+int f(int delegate() dg, int i)
+{
+    return dg() + i;
+}
+*/
+
+struct S
+{
+    int i;
+    float f;
+    int square()
+    {
+        return i*i;
+    }
+}
+
+S s;
+
+void main()
+{
+    auto dg = &s.square;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/dgs.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,84 @@
+struct S
+{
+    int i;
+    int square()
+    {
+        return i*i;
+    }
+    int plus(int a)
+    {
+        return i + a;
+    }
+    int minus(int a)
+    {
+        return i - a;
+    }
+    int delegate(int) get(char op)
+    {
+        int delegate(int) rval;
+        if (op == '+')
+            rval = &plus;
+        else if (op == '-')
+            rval = &minus;
+        return rval;
+    }
+}
+
+int calldg1(int delegate(int) dg, int i)
+{
+    return dg(i);
+}
+
+void delegate() retdg()
+{
+    void delegate() dg;
+    return dg;
+}
+
+void getretdg()
+{
+    void delegate() dg;
+    dg = retdg();
+}
+
+class C
+{
+    int i;
+    void m()
+    {
+        i = 42;
+    }
+}
+
+void getclassdg()
+{
+    scope c = new C;
+    void delegate() dg = &c.m;
+    assert(c.i != 42);
+    dg();
+    assert(c.i == 42);
+}
+
+void main()
+{
+    printf("Delegate test\n");
+    S s = S(4);
+    
+    auto dg = &s.square;
+    //assert(dg() == 16);
+    //dg();
+    
+    /*auto dg1 = &s.plus;
+    assert(dg1(6) == 10);
+    
+    auto dg2 = &s.minus;
+    assert(calldg1(dg2,30) == -26);
+    
+    auto dg3 = s.get('+');
+    assert(dg3(16) == 20);
+    
+    getretdg();
+    getclassdg();*/
+    
+    printf("  SUCCESS\n");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/dotproduct.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,34 @@
+struct vec3
+{
+    float x,y,z;
+
+    float dot(ref vec3 v)
+    {
+        return x*v.x + y*v.y + z*v.z;
+    }
+
+    void print(char* n)
+    {
+        printf("%s = vec3(%.4f, %.4f, %.4f)\n", n, x,y,z);
+    }
+}
+
+int main()
+{
+    printf("Dot Product test\n");
+
+    const float f = 0.7071067811865474617f;
+    vec3 v = vec3(f,f,0);
+    vec3 w = vec3(f,0,f);
+
+    v.print("v");
+    v.print("w");
+
+    auto dp = v.dot(w);
+    printf("v · w = %f\n", dp);
+    assert(dp > 0.4999 && dp < 0.5001);
+
+    printf("  SUCCESS\n");
+    return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/e.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,23 @@
+module e;
+
+struct C
+{
+    float x=0,y=0;
+
+    float dot(ref C b)
+    {
+        return x*b.x + y*b.y;
+    }
+}
+
+void main()
+{
+    C a,b;
+    a.x = 2;
+    a.y = 6;
+    b.x = 3;
+    b.y = 5;
+    float f = a.dot(b);
+    printf("%f\n", f);
+    assert(f == 36);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/f.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,11 @@
+module f;
+
+struct S
+{
+    long l;
+}
+
+void main()
+{
+    S s;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/floatcmp.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,160 @@
+module floatcmp;
+
+void eq()
+{
+    float _3 = 3;
+    assert(!(_3 == 4));
+    assert(!(_3 == 2));
+    assert(_3 == 3);
+    assert(!(_3 == float.nan));
+}
+
+void neq()
+{
+    float _3 = 3;
+    assert(_3 != 4);
+    assert(_3 != 2);
+    assert(!(_3 != 3));
+    assert(_3 != float.nan);
+}
+
+void gt()
+{
+    float _3 = 3;
+    assert(_3 > 2);
+    assert(!(_3 > 4));
+    assert(!(_3 > 3));
+    assert(!(_3 > float.nan));
+}
+
+void ge()
+{
+    float _3 = 3;
+    assert(_3 >= 2);
+    assert(!(_3 >= 4));
+    assert(_3 >= 3);
+    assert(!(_3 >= float.nan));
+}
+
+void lt()
+{
+    float _3 = 3;
+    assert(_3 < 4);
+    assert(!(_3 < 2));
+    assert(!(_3 < 3));
+    assert(!(_3 < float.nan));
+}
+
+void le()
+{
+    float _3 = 3;
+    assert(_3 <= 4);
+    assert(!(_3 <= 2));
+    assert(_3 <= 3);
+    assert(!(_3 <= float.nan));
+}
+
+void uno()
+{
+    float _3 = 3;
+    assert(!(_3 !<>= 2));
+    assert(!(_3 !<>= 3));
+    assert(!(_3 !<>= 4));
+    assert(_3 !<>= float.nan);
+}
+
+void lg()
+{
+    float _3 = 3;
+    assert(_3 <> 4);
+    assert(_3 <> 2);
+    assert(!(_3 <> 3));
+    assert(!(_3 <> float.nan));
+}
+
+void lge()
+{
+    float _3 = 3;
+    assert(_3 <>= 4);
+    assert(_3 <>= 2);
+    assert(_3 <>= 3);
+    assert(!(_3 <>= float.nan));
+}
+
+void ugt()
+{
+    float _3 = 3;
+    assert(_3 !<= 2);
+    assert(!(_3 !<= 4));
+    assert(!(_3 !<= 3));
+    assert(_3 !<= float.nan);
+}
+
+void uge()
+{
+    float _3 = 3;
+    assert(_3 !< 2);
+    assert(!(_3 !< 4));
+    assert(_3 !< 3);
+    assert(_3 !< float.nan);
+}
+
+void ult()
+{
+    float _3 = 3;
+    assert(_3 !>= 4);
+    assert(!(_3 !>= 2));
+    assert(!(_3 !>= 3));
+    assert(_3 !>= float.nan);
+}
+
+void ule()
+{
+    float _3 = 3;
+    assert(_3 !> 4);
+    assert(!(_3 !> 2));
+    assert(_3 !> 3);
+    assert(_3 !> float.nan);
+}
+
+void ueq()
+{
+    float _3 = 3;
+    assert(!(_3 !<> 2));
+    assert(!(_3 !<> 4));
+    assert(_3 !<> 3);
+    assert(_3 !<> float.nan);
+}
+
+void main()
+{
+    printf("floating point comparison test\n");
+    
+    eq();
+    neq();
+    gt();
+    ge();
+    lt();
+    le();
+    uno();
+    lg();
+    lge();
+    ugt();
+    uge();
+    ult();
+    ule();
+    ueq();
+    
+    printf("  SUCCESS\n");
+}
+
+/+
+void gt()
+{
+    float _3 = 3;
+    assert();
+    assert();
+    assert();
+    assert();
+}
++/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/forwdecl.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,11 @@
+struct S
+{
+    S* s;
+    S** ss;
+    S*[4] s4;
+}
+
+void main()
+{
+    S s;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/funcptr.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,66 @@
+int return_six()
+{
+    return 6;
+}
+
+int add_int(int a, int b)
+{
+    return a+b;
+}
+
+int sub_int(int a, int b)
+{
+    return a-b;
+}
+
+alias int function(int,int) binfn_t;
+
+int binop_int(binfn_t op, int a, int b)
+{
+    return op(a,b);
+}
+
+binfn_t get_binop_int(char op)
+{
+    binfn_t fn;
+    if (op == '+')
+        fn = &add_int;
+    else if (op == '-')
+        fn = &sub_int;
+    return fn;
+}
+
+extern(C) float mul_float(float a, float b)
+{
+    return a * b;
+}
+
+void function_pointers()
+{
+    int function() fn = &return_six;
+    assert(fn() == 6);
+
+    binfn_t binfn = &add_int;
+    assert(binfn(4,1045) == 1049);
+    
+    assert(binop_int(binfn, 10,656) == 666);
+    
+    binfn = get_binop_int('+');
+    assert(binop_int(binfn, 10,100) == 110);
+    binfn = get_binop_int('-');
+    assert(binop_int(binfn, 10,100) == -90);
+    
+    {
+    auto ffn = &mul_float;
+    float ftmp = mul_float(2.5,5);
+    assert(ftmp == 12.5);
+    assert(ftmp > 12.49 && ftmp < 12.51);
+    }
+}
+
+void main()
+{
+    printf("Function pointer test\n");
+    function_pointers();
+    printf("  SUCCESS\n");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/funcs.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,48 @@
+void main()
+{
+    printf("Testing functions\n");
+    int i = 5;
+    assert(a(i) == 110);
+    assert(i == 11);
+
+    S s;
+    s.i = 5;
+    d(s);
+    assert(s.i == 5);
+    e(s);
+    assert(s.i == 6);
+
+    printf("  SUCCESS\n");
+}
+
+int a(ref int i)
+{
+    i*=2;
+    return b(i);
+}
+
+int b(ref int i)
+{
+    i++;
+    return c(i);
+}
+
+int c(int i)
+{
+    return i*10;
+}
+
+struct S
+{
+    int i;
+}
+
+void d(S s)
+{
+    s.i++;
+}
+
+void e(ref S s)
+{
+    s.i++;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/imports_1of2.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,11 @@
+module imports_1of2;
+
+import imports_2of2;
+
+void main()
+{
+    assert(func() == 42);
+    S s;
+    s.l = 32;
+    assert(s.l == 32);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/imports_2of2.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,11 @@
+module imports_2of2;
+
+int func()
+{
+    return 42;
+}
+
+struct S
+{
+    long l;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/intrinsics.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,30 @@
+import llvm.intrinsic;
+
+extern(C) int scanf(char*,...);
+
+void main()
+{
+    {
+    float f;
+    printf("Enter float: ");
+    scanf("%f", &f);
+    float sf = llvm_sqrt(f);
+    printf("sqrt(%f) = %f\n", f, sf);
+    }
+    
+    {
+    double d;
+    printf("Enter double: ");
+    scanf("%lf", &d);
+    double sd = llvm_sqrt(d);
+    printf("sqrt(%lf) = %lf\n", d, sd);
+    }
+    
+    {
+    real d;
+    printf("Enter real: ");
+    scanf("%lf", &d);
+    real sd = llvm_sqrt(d);
+    printf("sqrt(%lf) = %lf\n", d, sd);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/pointers.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,22 @@
+module pointers;
+
+struct S
+{
+    long l;
+}
+
+void main()
+{
+    int j = 42;
+    int* p = &j;
+
+    auto t = *p;
+    *p ^= t;
+
+    *p = ~t;
+
+    S s;
+    S* sp = &s;
+    *sp = s;
+    s = *sp;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/pt.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,28 @@
+int main()
+{
+    char[16] s = void;
+    {
+    char[] sd = s;
+    {
+    s[0] = 'a';
+    s[1] = 'b';
+    s[2] = 'c';
+    }
+
+    printf("%p %p\n", s.ptr, sd.ptr);
+    printf("%c%c%c\n", s[0], s[1], s[2]);
+    }
+    
+
+    char[16] s1 = void;
+    char[16] s2 = void;
+    char[] d1 = s1;
+
+    {
+        printf("%p\n%p\n%p\n", s1.ptr, s2.ptr, d1.ptr);
+    }
+
+    int[16] arr;
+
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/ptrarith.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,33 @@
+void main()
+{
+    printf("Pointer arithmetic test\n");
+    int* p;
+    printf("0x%x\n", p);
+    assert(p++ is null);
+    assert(cast(size_t)p == 4);
+    printf("0x%x\n", p);
+    p--;
+    assert(p is null);
+    printf("0x%x\n", p);
+    int d = 4;
+    p+=d;
+    printf("0x%x\n", p);
+    assert(cast(size_t)p == 16);
+    d = 2;
+    p+=d;
+    printf("0x%x\n", p);
+    assert(cast(size_t)p == 0x18);
+    d = 6;
+    p-=d;
+    printf("0x%x\n", p);
+    assert(p is null);
+    printf("  SUCCESS\n");
+}
+
+void fill_byte_array(ubyte* a, size_t n, ubyte v)
+{
+    auto p = a;
+    auto end = a+n;
+    while (p !is end)
+        *p++ = v;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sieve.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,31 @@
+/* Eratosthenes Sieve prime number calculation. */
+
+bool flags[8191];
+
+int main()
+{   int     i, prime, k, count, iter;
+
+    printf("10 iterations\n");
+    for (iter = 1;
+    iter <= 10;
+    iter++)
+    {
+    count = 0;
+    flags[] = true;
+    for (i = 0; i < flags.length; i++)
+    {   if (flags[i])
+        {
+        prime = i + i + 3;
+        k = i + prime;
+        while (k < flags.length)
+        {
+            flags[k] = false;
+            k += prime;
+        }
+        count += 1;
+        }
+    }
+    }
+    printf("%d primes\n", count);
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/slices.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,34 @@
+module slices;
+
+void main()
+{
+    //char[] a = "hello world";
+    //char[5] b = a[0..5];
+
+    //char* cp = a.ptr;
+    //char[] c = cp[0..1];
+}
+
+char[] first5(char[] str)
+{
+    char* p = str.ptr;
+    return p[0..5];
+}
+
+int[] one()
+{
+    static int i;
+    return (&i)[0..1];
+}
+
+void[] init()
+{
+static char c;
+return (&c)[0 .. 1];
+}
+
+void[] init2()
+    {   static char c;
+
+    return (cast(char *)&c)[0 .. 1];
+    }
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/static_ctor.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,14 @@
+static this()
+{
+    printf("static this\n");
+}
+
+static ~this()
+{
+    printf("static ~this\n");
+}
+
+void main()
+{
+    printf("main\n");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/staticarrays.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,70 @@
+void numbers()
+{
+    bool[8] bools;
+    char[8] chars;
+    byte[8] bytes;
+    short[8] shorts;
+    int[8] ints;
+    long[8] longs;
+    float[8] floats;
+    double[8] doubles;
+    real[8] reals;
+    {
+        bools[7] = true;
+        floats[7] = 3.14159265;
+        {
+            printf("bools[0] = %d, bools[7] = %d\n", bools[0], bools[7]);
+            printf("floats[0] = %f, floats[7] = %f\n", floats[0], floats[7]);
+        }
+    }
+}
+
+struct S
+{
+    int i = 42;
+    void print()
+    {
+        printf("S.i = %d\n", i);
+    }
+}
+
+class C
+{
+    int i;
+    this()
+    {
+        i = 3;
+    }
+    void print()
+    {
+        printf("C.i = %d\n", i);
+    }
+}
+
+void refs()
+{
+    void*[5] voids;
+    S*[5] structs;
+    C[5] classes;
+    
+    {
+        voids[0] = cast(void*)0xA;
+        printf("void* = %p\n", voids[0]);
+    }
+    {
+        structs[0] = new S;
+        structs[0].print();
+        delete structs[0];
+    }
+    {
+        classes[0] = new C;
+        classes[0].print();
+        delete classes[0];
+    }
+}
+
+void main()
+{
+    numbers();
+    refs();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/structinit.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,24 @@
+module structinit;
+
+import structinit2;
+
+struct S
+{
+    uint ui;
+    float f;
+    long l;
+    real r;
+}
+
+S adef;
+
+S a = { 1, 2.0f };
+S b = { f:2.0f, l:42 };
+
+Imp imp;
+
+void main()
+{
+    //assert(a == S.init);
+    //assert(b == S(0,3.14f,0,real.init));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/structinit2.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,8 @@
+module structinit2;
+
+struct Imp
+{
+    int i;
+    long l;
+    float f;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/structs.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,13 @@
+struct S
+{
+    int func()
+    {
+        return 42;
+    }
+}
+
+void main()
+{
+    S s;
+    int i = s.func();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/structs2.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,13 @@
+module structs2;
+
+struct S
+{
+    int i;
+    char c;
+    S* s;
+    char[4] ca;
+}
+
+void main()
+{
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/terms.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,45 @@
+module terms;
+
+void f()
+{
+    int i = 42;
+    if (i > 25)
+        return;
+    if (i < 25) {
+        return;
+    }
+
+    if (i > 100)
+        return;
+    else
+        return;
+
+    if (i < 1000) {
+        return;
+    }
+    else {
+        return;
+    }
+}
+
+void main()
+{
+    int i = 42;
+    if (i > 25)
+        return;
+    if (i < 25) {
+        return;
+    }
+
+    if (i > 100)
+        return;
+    else
+        return;
+
+    if (i < 1000) {
+        return;
+    }
+    else {
+        return;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/typeinfo.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,9 @@
+module typeinfo;
+
+typedef int int_t;
+
+void main()
+{
+    int_t i;
+    i += 3;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/v2d.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,30 @@
+struct V2D(T)
+{
+    T x,y;
+
+    T dot(ref V2D v)
+    {
+        return x*v.x + y*v.y;
+    }
+
+    V2D opAdd(ref V2D v)
+    {
+        return V2D(x+v.x, y+v.y);
+    }
+}
+
+alias V2D!(float) V2Df;
+
+void main()
+{
+    printf("V2D test\n");
+    auto up = V2Df(0.0f, 1.0f);
+    auto right = V2Df(1.0f, 0.0f);
+    assert(up.dot(right) == 0.0f);
+    auto upright = up + right;
+    assert(upright.x == 1.0f && upright.y == 1.0f);
+    auto copy = upright;
+    copy.x++;
+    assert(copy.x > upright.x);
+    printf("  SUCCESS\n");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/virtcall.d	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,15 @@
+module virtcall;
+
+class C
+{
+    override char[] toString()
+    {
+        return "overridden";
+    }
+}
+
+void main()
+{
+    C c = new C;
+    auto s = c.toString();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tester.sh	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+if [ -z $1 ]; then
+    echo "you need to specify the test name"
+    exit 1
+fi
+
+if [ "$2" = "ll" ]; then
+    make &&
+    llvmdc $1 -Itest -odtest -c &&
+    llvm-dis -f $1.bc &&
+    cat $1.ll
+    exit $?
+elif [ "$2" = "run" ]; then
+    make &&
+    llvmdc $1 -Itest -odtest -of$1 &&
+    $1
+    exit $?
+elif [ "$2" = "c" ]; then
+    make &&
+    llvmdc $1 -Itest -odtest -c
+    exit $?
+elif [ "$2" = "gdb" ]; then
+    make &&
+    gdb --args llvmdc $1 -Itest -odtest '-c'
+    exit $?
+else
+    echo "bad command or filename"
+fi