# HG changeset patch # User lindquist # Date 1188675807 -7200 # Node ID c53b6e3fe49ae00b0c869366f25eb5f0cb2db5ba # Parent a9e71648e74d16b54521f57a8a6555b16997946e [svn r5] Initial commit. Most things are very rough. diff -r a9e71648e74d -r c53b6e3fe49a dmd/Doxyfile --- /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 , where is the value of +# the FILE_VERSION_FILTER tag, and 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 , where +# is the value of the INPUT_FILTER tag, and 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 diff -r a9e71648e74d -r c53b6e3fe49a dmd/access.c --- /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 +#include +#include + +#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); + } +} diff -r a9e71648e74d -r c53b6e3fe49a dmd/aggregate.h --- /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 */ diff -r a9e71648e74d -r c53b6e3fe49a dmd/array.c --- /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 +#include +#include +#include +#include + +#if _MSC_VER +#include +#endif + +#if IN_GCC +#include "gdc_alloca.h" +#endif + +#if _WIN32 +#include +#endif + +#ifndef _WIN32 +#include +#include +#include +#include +#include +#include +#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; +} + diff -r a9e71648e74d -r c53b6e3fe49a dmd/arraytypes.h --- /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 diff -r a9e71648e74d -r c53b6e3fe49a dmd/artistic.txt --- /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 diff -r a9e71648e74d -r c53b6e3fe49a dmd/attrib.c --- /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 +#include +#include + +#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(); +} diff -r a9e71648e74d -r c53b6e3fe49a dmd/attrib.h --- /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 */ diff -r a9e71648e74d -r c53b6e3fe49a dmd/cast.c --- /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 +#include + +#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 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; +} + diff -r a9e71648e74d -r c53b6e3fe49a dmd/class.c --- /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 +#include +#include + +#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"); +} diff -r a9e71648e74d -r c53b6e3fe49a dmd/complex_t.h --- /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 diff -r a9e71648e74d -r c53b6e3fe49a dmd/cond.c --- /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 +#include + +#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, ¶meters, &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(')'); +} + + diff -r a9e71648e74d -r c53b6e3fe49a dmd/cond.h --- /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 diff -r a9e71648e74d -r c53b6e3fe49a dmd/constfold.c --- /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 +#include +#include +#include + +#if __DMC__ +#include +#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; +} + diff -r a9e71648e74d -r c53b6e3fe49a dmd/dchar.c --- /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 +#include +#include +#include + +#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 + +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 diff -r a9e71648e74d -r c53b6e3fe49a dmd/dchar.h --- /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 +#include + +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 +#include + +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 + +#ifndef GCC_SAFE_DMD +#include +#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 + diff -r a9e71648e74d -r c53b6e3fe49a dmd/declaration.c --- /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 +#include + +#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; +} + + diff -r a9e71648e74d -r c53b6e3fe49a dmd/declaration.h --- /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 */ diff -r a9e71648e74d -r c53b6e3fe49a dmd/delegatize.c --- /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 +#include + +#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); +} + + + diff -r a9e71648e74d -r c53b6e3fe49a dmd/doc.c --- /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 +#include +#include +#include +#include + +#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 = \n\ + \n\ + $(TITLE)\n\ + \n\ +

$(TITLE)

\n\ + $(BODY)\n\ +
$(SMALL Page generated by $(LINK2 http://www.digitalmars.com/d/ddoc.html, Ddoc). $(COPYRIGHT))\n\ + \n\ +\n\ +B = $0\n\ +I = $0\n\ +U = $0\n\ +P =

$0

\n\ +DL =
$0
\n\ +DT =
$0
\n\ +DD =
$0
\n\ +TABLE = $0
\n\ +TR = $0\n\ +TH = $0\n\ +TD = $0\n\ +OL =
    $0
\n\ +UL =
    $0
\n\ +LI =
  • $0
  • \n\ +BIG = $0\n\ +SMALL = $0\n\ +BR =
    \n\ +LINK = $0\n\ +LINK2 = $+\n\ +\n\ +RED = $0\n\ +BLUE = $0\n\ +GREEN = $0\n\ +YELLOW =$0\n\ +BLACK = $0\n\ +WHITE = $0\n\ +\n\ +D_CODE =
    $0
    \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 = \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 = //>/\n\ + /&/&/\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, ¯otable, mbuf.data, mbuf.offset); + + Scope *sc = Scope::createGlobal(this); // create root scope + sc->docbuf = &buf; + + DocComment *dc = DocComment::parse(sc, this, comment); + dc->pmacrotable = ¯otable; + dc->pescapetable = &escapetable; + + // Generate predefined macros + + // Set the title to be the name of the module + { char *p = toPrettyChars(); + Macro::define(¯otable, (unsigned char *)"TITLE", 5, (unsigned char *)p, strlen(p)); + } + + time_t t; + time(&t); + char *p = ctime(&t); + p = mem.strdup(p); + Macro::define(¯otable, (unsigned char *)"DATETIME", 8, (unsigned char *)p, strlen(p)); + Macro::define(¯otable, (unsigned char *)"YEAR", 4, (unsigned char *)p + 20, 4); + + char *docfilename = docfile->toChars(); + Macro::define(¯otable, (unsigned char *)"DOCFILENAME", 11, (unsigned char *)docfilename, strlen(docfilename)); + + if (dc->copyright) + { + dc->copyright->nooutput = 1; + Macro::define(¯otable, (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(¯otable, (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 '<' 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 '>' 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 '&' 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 = "<"; + break; + case '>': + s = ">"; + break; + case '&': + s = "&"; + break; + default: + s = NULL; + break; + } + return s; +} + diff -r a9e71648e74d -r c53b6e3fe49a dmd/doc.h --- /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 diff -r a9e71648e74d -r c53b6e3fe49a dmd/dsymbol.c --- /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 +#include +#include + +#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; +} + + + + diff -r a9e71648e74d -r c53b6e3fe49a dmd/dsymbol.h --- /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 */ diff -r a9e71648e74d -r c53b6e3fe49a dmd/dump.c --- /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 +#include +#include + +#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); +} + + diff -r a9e71648e74d -r c53b6e3fe49a dmd/entity.c --- /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 + +/********************************************* + * 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 diff -r a9e71648e74d -r c53b6e3fe49a dmd/enum.c --- /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 +#include + +#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"; +} + + diff -r a9e71648e74d -r c53b6e3fe49a dmd/enum.h --- /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 */ diff -r a9e71648e74d -r c53b6e3fe49a dmd/expression.c --- /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 +#include +#include +#include +#include +#include + +#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, ¶meters, &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); +} + + diff -r a9e71648e74d -r c53b6e3fe49a dmd/expression.h --- /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 */ diff -r a9e71648e74d -r c53b6e3fe49a dmd/func.c --- /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 +#include + +#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); +} + + + + diff -r a9e71648e74d -r c53b6e3fe49a dmd/gnuc.c --- /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; +} + diff -r a9e71648e74d -r c53b6e3fe49a dmd/gnuc.h --- /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 diff -r a9e71648e74d -r c53b6e3fe49a dmd/gpl.txt --- /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. + + + Copyright (C) 19yy + + 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. + + , 1 April 1989 + Ty Coon, President of Vice + +That's all there is to it! diff -r a9e71648e74d -r c53b6e3fe49a dmd/hdrgen.c --- /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 +#include +#include +#if __DMC__ +#include +#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 diff -r a9e71648e74d -r c53b6e3fe49a dmd/hdrgen.h --- /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)); } +}; + + diff -r a9e71648e74d -r c53b6e3fe49a dmd/html.c --- /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 +#include +#include +#include +#include +#include + +#include "mars.h" +#include "html.h" + +#include +#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 + * 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 = "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; +} + diff -r a9e71648e74d -r c53b6e3fe49a dmd/html.h --- /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 diff -r a9e71648e74d -r c53b6e3fe49a dmd/id.c --- /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"); +} diff -r a9e71648e74d -r c53b6e3fe49a dmd/id.h --- /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 diff -r a9e71648e74d -r c53b6e3fe49a dmd/identifier.c --- /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 +#include + +#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); +} diff -r a9e71648e74d -r c53b6e3fe49a dmd/identifier.h --- /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 */ diff -r a9e71648e74d -r c53b6e3fe49a dmd/idgen.c --- /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 +#include +#include +#include +#include + +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; +} diff -r a9e71648e74d -r c53b6e3fe49a dmd/impcnvgen.c --- /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 +#include + +#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; +} diff -r a9e71648e74d -r c53b6e3fe49a dmd/impcnvtab.c --- /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, +}; diff -r a9e71648e74d -r c53b6e3fe49a dmd/import.c --- /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 +#include + +#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(); +} + diff -r a9e71648e74d -r c53b6e3fe49a dmd/import.h --- /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 */ diff -r a9e71648e74d -r c53b6e3fe49a dmd/inifile.c --- /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 +#include +#include +#include + +#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; +} + diff -r a9e71648e74d -r c53b6e3fe49a dmd/init.c --- /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 +#include + +#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); +} + + + diff -r a9e71648e74d -r c53b6e3fe49a dmd/init.h --- /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 diff -r a9e71648e74d -r c53b6e3fe49a dmd/inline.c --- /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 +#include +#include + +#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); +} + + + diff -r a9e71648e74d -r c53b6e3fe49a dmd/interpret.c --- /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 +#include +#include + +#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; +} + diff -r a9e71648e74d -r c53b6e3fe49a dmd/lexer.c --- /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 +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef IN_GCC + +#include +#include "mem.h" + +#else + +#if __GNUC__ +#include +#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"; +} diff -r a9e71648e74d -r c53b6e3fe49a dmd/lexer.h --- /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 */ diff -r a9e71648e74d -r c53b6e3fe49a dmd/link.c --- /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 +#include +#include +#include +#include +#include + +#if _WIN32 +#include +#endif + +#if linux +#include +#include +#include +#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 +} diff -r a9e71648e74d -r c53b6e3fe49a dmd/lstring.c --- /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 + +#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; +} diff -r a9e71648e74d -r c53b6e3fe49a dmd/lstring.h --- /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 diff -r a9e71648e74d -r c53b6e3fe49a dmd/macro.c --- /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 +#include +#include +#include +#include + +#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--; +} diff -r a9e71648e74d -r c53b6e3fe49a dmd/macro.h --- /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 +#include +#include +#include + +#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 diff -r a9e71648e74d -r c53b6e3fe49a dmd/mangle.c --- /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 +#include +#include +#include + +#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; +} + + diff -r a9e71648e74d -r c53b6e3fe49a dmd/mars.c --- /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 +#include +#include +#include +#include +#include + +#if _WIN32 +#include +long __cdecl __ehfilter(LPEXCEPTION_POINTERS ep); +#endif + +#if __DMC__ +#include +#endif + +#if linux +#include +#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(¶ms, 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(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 diff -r a9e71648e74d -r c53b6e3fe49a dmd/mars.h --- /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 +#include +#include + +#ifdef __DMC__ +#ifdef DEBUG +#undef assert +#define assert(e) (static_cast((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++ 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 */ diff -r a9e71648e74d -r c53b6e3fe49a dmd/mem.c --- /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 +#include +#include + +#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); +} + + diff -r a9e71648e74d -r c53b6e3fe49a dmd/mem.h --- /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 // 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 */ diff -r a9e71648e74d -r c53b6e3fe49a dmd/module.c --- /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 +#include +#include + +#ifdef _MSC_VER +#include +#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; +} diff -r a9e71648e74d -r c53b6e3fe49a dmd/module.h --- /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 */ diff -r a9e71648e74d -r c53b6e3fe49a dmd/mtype.c --- /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 + +#include +#include +#include + +#ifdef __DMC__ +#include +#endif + +#if _MSC_VER +#include +#include +#include +#elif __DMC__ +#include +#else +//#define signbit 56 +#endif + +#if __APPLE__ +#include +static double zero = 0; +#elif __GNUC__ +#include +#include +#include +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::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(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; +} diff -r a9e71648e74d -r c53b6e3fe49a dmd/mtype.h --- /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 */ diff -r a9e71648e74d -r c53b6e3fe49a dmd/opover.c --- /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 +#include +#include +#include +#include + +#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; + } +} + diff -r a9e71648e74d -r c53b6e3fe49a dmd/optimize.c --- /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 +#include +#include +#include + +#if __DMC__ +#include +#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; +} + + diff -r a9e71648e74d -r c53b6e3fe49a dmd/parse.c --- /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 +#include + +#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)); +} + + +/********************************* ***************************/ + diff -r a9e71648e74d -r c53b6e3fe49a dmd/parse.h --- /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 */ diff -r a9e71648e74d -r c53b6e3fe49a dmd/port.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 + +#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 diff -r a9e71648e74d -r c53b6e3fe49a dmd/readme.txt --- /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 diff -r a9e71648e74d -r c53b6e3fe49a dmd/root.c --- /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 +#include +#include +#include +#include +#include + +#if _MSC_VER +#include +#endif + +#if _WIN32 +#include +#include +#endif + +#if linux +#include +#include +#include +#include +#include +#include +#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]; +} + + + + + + + + + + + + + + + diff -r a9e71648e74d -r c53b6e3fe49a dmd/root.h --- /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 +#include + +#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 diff -r a9e71648e74d -r c53b6e3fe49a dmd/scope.c --- /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 +#include + +#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); + } +} diff -r a9e71648e74d -r c53b6e3fe49a dmd/scope.h --- /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 */ diff -r a9e71648e74d -r c53b6e3fe49a dmd/statement.c --- /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 +#include +#include + +#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; +} + + diff -r a9e71648e74d -r c53b6e3fe49a dmd/statement.h --- /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 */ diff -r a9e71648e74d -r c53b6e3fe49a dmd/staticassert.c --- /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 +#include +#include + +#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(); +} diff -r a9e71648e74d -r c53b6e3fe49a dmd/staticassert.h --- /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 diff -r a9e71648e74d -r c53b6e3fe49a dmd/stringtable.c --- /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 +#include +#include + +#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; +} + + + + diff -r a9e71648e74d -r c53b6e3fe49a dmd/stringtable.h --- /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 diff -r a9e71648e74d -r c53b6e3fe49a dmd/struct.c --- /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 +#include + +#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"; +} + + diff -r a9e71648e74d -r c53b6e3fe49a dmd/template.c --- /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 +#include + +#if _WIN32 +#include +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(o); + if (!o || o->dyncast() != DYNCAST_EXPRESSION) + return NULL; + return (Expression *)o; +} + +Dsymbol *isDsymbol(Object *o) +{ + //return dynamic_cast(o); + if (!o || o->dyncast() != DYNCAST_DSYMBOL) + return NULL; + return (Dsymbol *)o; +} + +Type *isType(Object *o) +{ + //return dynamic_cast(o); + if (!o || o->dyncast() != DYNCAST_TYPE) + return NULL; + return (Type *)o; +} + +Tuple *isTuple(Object *o) +{ + //return dynamic_cast(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(); +} + diff -r a9e71648e74d -r c53b6e3fe49a dmd/template.h --- /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 */ diff -r a9e71648e74d -r c53b6e3fe49a dmd/total.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 +#include +#include +#include +#include + +#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 */ diff -r a9e71648e74d -r c53b6e3fe49a dmd/unialpha.c --- /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 + +/******************************* + * 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; +} + diff -r a9e71648e74d -r c53b6e3fe49a dmd/utf.c --- /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 +#include + +#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; +} + diff -r a9e71648e74d -r c53b6e3fe49a dmd/utf.h --- /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 diff -r a9e71648e74d -r c53b6e3fe49a dmd/version.c --- /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 +#include + +#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"; +} + + diff -r a9e71648e74d -r c53b6e3fe49a dmd/version.h --- /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 */ diff -r a9e71648e74d -r c53b6e3fe49a gen/elem.c --- /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 + +#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(mem->getType())) + { + Logger::cout() << "unexpected type: " << *mem->getType() << '\n'; + assert(0); + } + const llvm::PointerType* pt = llvm::cast(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; +} diff -r a9e71648e74d -r c53b6e3fe49a gen/elem.h --- /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 diff -r a9e71648e74d -r c53b6e3fe49a gen/enums.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, +}; diff -r a9e71648e74d -r c53b6e3fe49a gen/irstate.c --- /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() +{ +} diff -r a9e71648e74d -r c53b6e3fe49a gen/irstate.h --- /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 +#include +#include + +#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 TypeVector; + typedef std::vector ConstantVector; + typedef std::vector 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 funcs; + llvm::Function* topfunc(); + std::stack functypes; + TypeFunction* topfunctype(); + llvm::Instruction* topallocapoint(); + + // structs + typedef std::vector StructVector; + StructVector structs; + IRStruct& topstruct(); + + // classes TODO move into IRClass + typedef std::vector ClassDeclVec; + ClassDeclVec classes; + typedef std::vector FuncDeclVec; + typedef std::vector ClassMethodVec; + ClassMethodVec classmethods; + typedef std::vector BoolVec; + BoolVec queueClassMethods; + + // D main function + bool emitMain; + llvm::Function* mainFunc; + + // L-values + bool inLvalue; + typedef std::vector LvalVec; + LvalVec lvals; + llvm::Value* toplval(); + + // basic block scopes + std::vector scopes; + IRScope& scope(); + llvm::BasicBlock* scopebegin(); + llvm::BasicBlock* scopeend(); + llvm::BasicBlock* scopebb(); + bool scopereturned(); + + // loop blocks + typedef std::vector 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 diff -r a9e71648e74d -r c53b6e3fe49a gen/logger.c --- /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 +#include +#include +#include +#include +#include + +#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 diff -r a9e71648e74d -r c53b6e3fe49a gen/logger.h --- /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 + +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 diff -r a9e71648e74d -r c53b6e3fe49a gen/runtime.c --- /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 + +#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(target->getOrInsertFunction(name, fnty)); +} diff -r a9e71648e74d -r c53b6e3fe49a gen/runtime.h --- /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); diff -r a9e71648e74d -r c53b6e3fe49a gen/symbol.h diff -r a9e71648e74d -r c53b6e3fe49a gen/tocsym.c --- /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 + +#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; +} + diff -r a9e71648e74d -r c53b6e3fe49a gen/todt.c --- /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; +} + + + diff -r a9e71648e74d -r c53b6e3fe49a gen/toir.c --- /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 +#include +#include +#include +#include + +#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(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(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(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(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(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(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(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(left->getType())) + left = new llvm::PtrToIntInst(left,LLVM_DtoSize_t(),"tmp",p->scopebb()); + + llvm::Value* right = r->getValue(); + if (llvm::isa(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(e->val->getType())); + assert(llvm::isa(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 llargs(n, 0); + + const llvm::FunctionType* llfnty = 0; + + // normal function call + if (llvm::isa(funcval->getType())) { + llfnty = llvm::cast(funcval->getType()); + } + // pointer to something + else if (llvm::isa(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(funcval->getType()->getContainedType(0))) { + funcval = new llvm::LoadInst(funcval,"tmp",p->scopebb()); + } + + // function pointer + if (llvm::isa(funcval->getType()->getContainedType(0))) { + //Logger::cout() << "function pointer type:\n" << *funcval << '\n'; + llfnty = llvm::cast(funcval->getType()->getContainedType(0)); + } + // struct pointer - delegate + else if (llvm::isa(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(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(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; idim; 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(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; igetType() << '\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; iscopebb()); + + 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(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(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(up->val)); + if (lwr_is_zero) { + e->arg = up->val; + } + else { + if (lo->type == elem::CONST) { + llvm::Constant* clo = llvm::cast(lo->val); + llvm::Constant* cup = llvm::cast(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 ctorargs; + ctorargs.push_back(e->mem); + for (size_t i=0; idim; ++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 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 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(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(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; idata[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; idim; ++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(); +} diff -r a9e71648e74d -r c53b6e3fe49a gen/tollvm.c --- /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 + +#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 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(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 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(at)) { + Logger::println("struct param"); + paramvec.push_back(llvm::PointerType::get(at)); + } + else if (llvm::isa(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 types; + types.push_back(i8ptr); + types.push_back(funcptr); + return llvm::StructType::get(types); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +llvm::Type* LLVM_DtoStructType(Type* t) +{ + assert(0); + std::vector 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 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(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 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 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 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(si->ad->llvmType); + size_t n = structtype->getNumElements(); + + assert(si->value.dim == si->vars.dim); + + std::vector 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(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 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 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 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 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(src->getType()->getContainedType(0))) + { + Logger::cout() << "invalid: " << *src << '\n'; + assert(0); + } + const llvm::ArrayType* arrty = llvm::cast(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(l->getType()); + if (llvm::isa(ptrty->getContainedType(0))) + { + const llvm::ArrayType* arrty = llvm::cast(ptrty->getContainedType(0)); + llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); + + std::vector 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(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(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(arr->getType()->getContainedType(0)); + //const llvm::PointerType* pt = llvm::cast(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 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(e->val); + delete e; + } + else if (ExpInitializer* ex = init->isExpInitializer()) + { + elem* e = ex->exp->toElem(gIR); + v = llvm::cast(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(ptrTy); + const llvm::IntegerType* vt = llvm::cast(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(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 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; idim; 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 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(e->getValue()); + } + delete e; + } + else if (ExpInitializer* ex = init->isExpInitializer()) + { + elem* e = ex->exp->toElem(gIR); + if (!e->inplace && !e->isNull()) { + _init = llvm::cast(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; +} diff -r a9e71648e74d -r c53b6e3fe49a gen/tollvm.h --- /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" diff -r a9e71648e74d -r c53b6e3fe49a gen/toobj.c --- /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 +#include +#include + +#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; ioffset) + 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; ifields.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 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(pa.get())->refineAbstractTypeTo(structtype); + structtype = llvm::cast(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; ktopstruct().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; itoObjFile(); + } + + 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; jdim; 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; itoObjFile(); + } + + // create vtable initializer + if (emit_vtable) + { + llvm::GlobalVariable* vtblVar = 0; + std::vector 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(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; ktopstruct().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(_init)) + { + assert(_init->getType()->getContainedType(0) == _type); + llvm::GlobalVariable* gv = llvm::cast(_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(_type)) + { + const llvm::ArrayType* at = llvm::cast(_type); + assert(_type->getContainedType(0) == _init->getType()); + std::vector 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(_type)) + { + const llvm::ArrayType* arrty = llvm::cast(_type); + uint64_t n = arrty->getNumElements(); + std::vector 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 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(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(at)) { + Logger::println("struct param"); + paramvec.push_back(llvm::PointerType::get(at)); + } + else if (llvm::isa(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(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(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"); +} diff -r a9e71648e74d -r c53b6e3fe49a gen/typinf.c --- /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 +#include + +#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; +} + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/build.sh --- /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 diff -r a9e71648e74d -r c53b6e3fe49a lphobos/clean.sh --- /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 diff -r a9e71648e74d -r c53b6e3fe49a lphobos/crc32.d --- /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; +} diff -r a9e71648e74d -r c53b6e3fe49a lphobos/dsss.conf --- /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 diff -r a9e71648e74d -r c53b6e3fe49a lphobos/gcstats.d --- /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 +} + + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/internal/arrays.d --- /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; +} diff -r a9e71648e74d -r c53b6e3fe49a lphobos/internal/contract.d --- /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); + } +} diff -r a9e71648e74d -r c53b6e3fe49a lphobos/internal/moduleinit.d --- /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++)(); + } +} diff -r a9e71648e74d -r c53b6e3fe49a lphobos/internal/moduleinit_backend.ll --- /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 +} diff -r a9e71648e74d -r c53b6e3fe49a lphobos/internal/objectimpl.d --- /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 < obj) $(TD < 0)) + * $(TR $(TD this == obj) $(TD 0)) + * $(TR $(TD this > obj) $(TD > 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 + * TypeidExpression. + */ +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 <, ==, or >. + 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; + ++/ diff -r a9e71648e74d -r c53b6e3fe49a lphobos/llvm/intrinsic.d --- /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* , i8 , i8 ) +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* , i16 , i16 ) +declare i32 @llvm.atomic.lcs.i32.i32p.i32.i32( i32* , i32 , i32 ) +declare i64 @llvm.atomic.lcs.i64.i64p.i64.i64( i64* , i64 , i64 ) + +declare i8 @llvm.atomic.ls.i8.i8p.i8( i8* , i8 ) +declare i16 @llvm.atomic.ls.i16.i16p.i16( i16* , i16 ) +declare i32 @llvm.atomic.ls.i32.i32p.i32( i32* , i32 ) +declare i64 @llvm.atomic.ls.i64.i64p.i64( i64* , i64 ) + +declare i8 @llvm.atomic.las.i8.i8p.i8( i8* , i8 ) +declare i16 @llvm.atomic.las.i16.i16p.i16( i16* , i16 ) +declare i32 @llvm.atomic.las.i32.i32p.i32( i32* , i32 ) +declare i64 @llvm.atomic.las.i64.i64p.i64( i64* , i64 ) + +declare i8 @llvm.atomic.lss.i8.i8.i8( i8* , i8 ) +declare i16 @llvm.atomic.lss.i16.i16.i16( i16* , i16 ) +declare i32 @llvm.atomic.lss.i32.i32.i32( i32* , i32 ) +declare i64 @llvm.atomic.lss.i64.i64.i64( i64* , i64 ) + +declare void @llvm.memory.barrier( i1 , i1 , i1 , i1 ) +*/ diff -r a9e71648e74d -r c53b6e3fe49a lphobos/object.d --- /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); +} + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/c/fenv.d --- /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 <fenv.h> + * 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); /// + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/c/linux/linux.d --- /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 and + +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 + * 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 + */ + + 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); +} diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/c/linux/linuxextern.d --- /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; +} + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/c/linux/pthread.d --- /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); +} + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/c/linux/socket.d --- /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]; + } +} + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/c/locale.d --- /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 <locale.h> + * 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(); + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/c/math.d --- /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 <math.h> + * 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); } + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/c/process.d --- /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 <process.h> + * 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 **); +} + + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/c/stdarg.d --- /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 <stdarg.h> + * 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; +} diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/c/stddef.d --- /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 <stddef.h> + * 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); +} diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/c/stdio.d --- /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 <stdio.h> + * 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); /// diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/c/stdlib.d --- /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 <stdlib.h> + * 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 diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/c/string.d --- /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 <string.h> + * 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); /// +} diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/c/time.d --- /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 <time.h> + * 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 *); diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/intrinsic.d --- /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
    + * 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", btc(array, 35)); + printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); + + printf("btc(array, 35) = %d\n", btc(array, 35)); + printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); + + printf("bts(array, 35) = %d\n", bts(array, 35)); + printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); + + printf("btr(array, 35) = %d\n", btr(array, 35)); + printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); + + printf("bt(array, 1) = %d\n", bt(array, 1)); + printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); + + return 0; +} + * --- + * Output: +
    +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
    +
    + */ +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); + + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/stdint.d --- /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. + stdint offers a portable way of trading off size + vs efficiency, in a manner compatible with the stdint.h + 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: + + + + + + + + + + +
    Exact Alias + Description + At Least Alias + Description + Fast Alias + Description +
    int8_t + exactly 8 bits signed + int_least8_t + at least 8 bits signed + int_fast8_t + fast 8 bits signed +
    uint8_t + exactly 8 bits unsigned + uint_least8_t + at least 8 bits unsigned + uint_fast8_t + fast 8 bits unsigned + +
    int16_t + exactly 16 bits signed + int_least16_t + at least 16 bits signed + int_fast16_t + fast 16 bits signed +
    uint16_t + exactly 16 bits unsigned + uint_least16_t + at least 16 bits unsigned + uint_fast16_t + fast 16 bits unsigned + +
    int32_t + exactly 32 bits signed + int_least32_t + at least 32 bits signed + int_fast32_t + fast 32 bits signed +
    uint32_t + exactly 32 bits unsigned + uint_least32_t + at least 32 bits unsigned + uint_fast32_t + fast 32 bits unsigned + +
    int64_t + exactly 64 bits signed + int_least64_t + at least 64 bits signed + int_fast64_t + fast 64 bits signed +
    uint64_t + exactly 64 bits unsigned + uint_least64_t + at least 64 bits unsigned + uint_fast64_t + fast 64 bits unsigned +
    + + The ptr aliases are integral types guaranteed to be large enough + to hold a pointer without losing bits: + + + + +
    Alias + Description +
    intptr_t + signed integral type large enough to hold a pointer +
    uintptr_t + unsigned integral type large enough to hold a pointer +
    + + The max aliases are the largest integral types: + + + + +
    Alias + Description +
    intmax_t + the largest signed integral type +
    uintmax_t + the largest unsigned integral type +
    + + * 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; + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfo/ti_Aint.d --- /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); + } +} + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfo/ti_byte.d --- /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; + } +} + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfo/ti_char.d --- /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]; + } +} + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfo/ti_int.d --- /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; + } +} + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfo/ti_ptr.d --- /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; + } +} + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfo/ti_short.d --- /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; + } +} + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfo/ti_ubyte.d --- /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"; } +} diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfo/ti_uint.d --- /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; + } +} + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfo/ti_ushort.d --- /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; + } +} + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfounsupported/ti_AC.d --- /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); + } +} + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfounsupported/ti_Acdouble.d --- /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); + } +} + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfounsupported/ti_Acfloat.d --- /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); + } +} + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfounsupported/ti_Acreal.d --- /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); + } +} + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfounsupported/ti_Adouble.d --- /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); + } +} diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfounsupported/ti_Afloat.d --- /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); + } +} diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfounsupported/ti_Ag.d --- /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); + } +} + + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfounsupported/ti_Aint.d --- /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); + } +} + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfounsupported/ti_Along.d --- /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); + } +} + + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfounsupported/ti_Areal.d --- /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); + } +} diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfounsupported/ti_Ashort.d --- /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); + } +} + + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfounsupported/ti_C.d --- /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; + } +} + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfounsupported/ti_byte.d --- /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; + } +} + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfounsupported/ti_cdouble.d --- /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]; + } +} + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfounsupported/ti_cfloat.d --- /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]; + } +} + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfounsupported/ti_char.d --- /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]; + } +} + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfounsupported/ti_creal.d --- /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]; + } +} + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfounsupported/ti_dchar.d --- /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]; + } +} + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfounsupported/ti_delegate.d --- /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; + } +} + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfounsupported/ti_double.d --- /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]; + } +} + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfounsupported/ti_float.d --- /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]; + } +} + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfounsupported/ti_idouble.d --- /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"; } +} + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfounsupported/ti_ifloat.d --- /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"; } +} + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfounsupported/ti_int.d --- /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; + } +} + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfounsupported/ti_ireal.d --- /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"; } +} + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfounsupported/ti_long.d --- /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; + } +} + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfounsupported/ti_ptr.d --- /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; + } +} + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfounsupported/ti_real.d --- /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]; + } +} + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfounsupported/ti_short.d --- /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; + } +} + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfounsupported/ti_ubyte.d --- /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"; } +} diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfounsupported/ti_uint.d --- /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; + } +} + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfounsupported/ti_ulong.d --- /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; + } +} + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfounsupported/ti_ushort.d --- /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; + } +} + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfounsupported/ti_void.d --- /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; + } +} + diff -r a9e71648e74d -r c53b6e3fe49a lphobos/std/typeinfounsupported/ti_wchar.d --- /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]; + } +} + diff -r a9e71648e74d -r c53b6e3fe49a premake.lua --- /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" } diff -r a9e71648e74d -r c53b6e3fe49a test/a.d --- /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"); +} diff -r a9e71648e74d -r c53b6e3fe49a test/alignment.d --- /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; +} diff -r a9e71648e74d -r c53b6e3fe49a test/arrayinit.d --- /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]; diff -r a9e71648e74d -r c53b6e3fe49a test/arrays.d --- /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>>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"); +} diff -r a9e71648e74d -r c53b6e3fe49a test/c.d --- /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); +} diff -r a9e71648e74d -r c53b6e3fe49a test/classes.d --- /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; +} diff -r a9e71648e74d -r c53b6e3fe49a test/classes2.d --- /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(); +} diff -r a9e71648e74d -r c53b6e3fe49a test/classes3.d --- /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); +} diff -r a9e71648e74d -r c53b6e3fe49a test/classes4.d --- /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);} +} diff -r a9e71648e74d -r c53b6e3fe49a test/comma.d --- /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); +} diff -r a9e71648e74d -r c53b6e3fe49a test/cond.d --- /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"); +} diff -r a9e71648e74d -r c53b6e3fe49a test/condexp.d --- /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);*/ +} diff -r a9e71648e74d -r c53b6e3fe49a test/cyclic.d --- /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; +} diff -r a9e71648e74d -r c53b6e3fe49a test/d.d --- /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; +} diff -r a9e71648e74d -r c53b6e3fe49a test/dgs.d --- /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 = + + else if (op == '-') + rval = − + 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"); +} diff -r a9e71648e74d -r c53b6e3fe49a test/dotproduct.d --- /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; +} + diff -r a9e71648e74d -r c53b6e3fe49a test/e.d --- /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); +} diff -r a9e71648e74d -r c53b6e3fe49a test/f.d --- /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; +} diff -r a9e71648e74d -r c53b6e3fe49a test/floatcmp.d --- /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(); +} ++/ diff -r a9e71648e74d -r c53b6e3fe49a test/forwdecl.d --- /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; +} diff -r a9e71648e74d -r c53b6e3fe49a test/funcptr.d --- /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"); +} diff -r a9e71648e74d -r c53b6e3fe49a test/funcs.d --- /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++; +} diff -r a9e71648e74d -r c53b6e3fe49a test/imports_1of2.d --- /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); +} diff -r a9e71648e74d -r c53b6e3fe49a test/imports_2of2.d --- /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; +} diff -r a9e71648e74d -r c53b6e3fe49a test/intrinsics.d --- /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); + } +} diff -r a9e71648e74d -r c53b6e3fe49a test/pointers.d --- /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; +} diff -r a9e71648e74d -r c53b6e3fe49a test/pt.d --- /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; +} diff -r a9e71648e74d -r c53b6e3fe49a test/ptrarith.d --- /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; +} diff -r a9e71648e74d -r c53b6e3fe49a test/sieve.d --- /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; +} diff -r a9e71648e74d -r c53b6e3fe49a test/slices.d --- /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 diff -r a9e71648e74d -r c53b6e3fe49a test/static_ctor.d --- /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"); +} diff -r a9e71648e74d -r c53b6e3fe49a test/staticarrays.d --- /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(); +} diff -r a9e71648e74d -r c53b6e3fe49a test/structinit.d --- /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)); +} diff -r a9e71648e74d -r c53b6e3fe49a test/structinit2.d --- /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; +} diff -r a9e71648e74d -r c53b6e3fe49a test/structs.d --- /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(); +} diff -r a9e71648e74d -r c53b6e3fe49a test/structs2.d --- /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() +{ +} diff -r a9e71648e74d -r c53b6e3fe49a test/terms.d --- /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; + } +} diff -r a9e71648e74d -r c53b6e3fe49a test/typeinfo.d --- /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; +} diff -r a9e71648e74d -r c53b6e3fe49a test/v2d.d --- /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"); +} diff -r a9e71648e74d -r c53b6e3fe49a test/virtcall.d --- /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(); +} diff -r a9e71648e74d -r c53b6e3fe49a tester.sh --- /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