diff options
author | SimplyTheOther <simplytheother@gmail.com> | 2020-11-27 14:57:04 +0000 |
---|---|---|
committer | Philip Herron <philip.herron@embecosm.com> | 2020-11-27 14:57:04 +0000 |
commit | 9ccce9982b37580c6d1232cb6224b44c1f46a978 (patch) | |
tree | b5c46f0a6d43ce5b63453488606334ee85ff1d56 | |
parent | bc4080fb5dafbc26e9a5d8e924608d8a8969e33a (diff) | |
download | gcc-9ccce9982b37580c6d1232cb6224b44c1f46a978.zip gcc-9ccce9982b37580c6d1232cb6224b44c1f46a978.tar.gz gcc-9ccce9982b37580c6d1232cb6224b44c1f46a978.tar.bz2 |
Fixed data structure for storing target data
62 files changed, 24766 insertions, 6738 deletions
diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in index 5abdb40..551eb63 100644 --- a/gcc/rust/Make-lang.in +++ b/gcc/rust/Make-lang.in @@ -22,6 +22,9 @@ # Installation name. +RSFLEXFLAGS= +RSBISONFLAGS=-v --debug + GCCRUST_INSTALL_NAME := $(shell echo gccrust|sed '$(program_transform_name)') GCCRUST_TARGET_INSTALL_NAME := $(target_noncanonical)-$(shell echo gccrust|sed '$(program_transform_name)') @@ -53,7 +56,11 @@ RUST_OBJS = \ rust/rust-backend.o \ rust/rust-linemap.o \ rust/rust-gcc-diagnostics.o \ - rust/main.o + rust/rust-gcc.o \ + rust/node.o \ + rust/rs-parser.o \ + rust/rs-lexer.o \ + rust/rustly.o rust_OBJS = $(RUST_OBJS) rust/rustspec.o @@ -89,10 +96,10 @@ $(build_htmldir)/rust/index.html: $(RUST_TEXI_FILES) $(TEXI2HTML) -I $(gcc_docdir) -I $(gcc_docdir)/include \ -I $(srcdir)/rust -o $(@D) $< -.INTERMEDIATE: gccrust.pod +# .INTERMEDIATE: gccrust.pod -gccrust.pod: rust/gccrust.texi - -$(TEXI2POD) -D gccrust < $< > $@ +# gccrust.pod: rust/gccrust.texi +# -$(TEXI2POD) -D gccrust < $< > $@ # Build hooks. @@ -110,9 +117,10 @@ rust.tags: force cd $(srcdir)/rust; \ etags -o TAGS.sub *.c *.h rustfrontend/*.h rustfrontend/*.cc; \ etags --include TAGS.sub --include ../TAGS.sub -rust.man: doc/gccrust.1 -rust.srcman: doc/gccrust.1 - -cp -p $^ $(srcdir)/doc +rust.man: +# rust.man: doc/gccrust.1 +# rust.srcman: doc/gccrust.1 +# -cp -p $^ $(srcdir)/doc lang_checks += check-rust lang_checks_parallelized += check-rust @@ -123,10 +131,6 @@ selftest-rust: # Install hooks. -# Install hooks. - -# Install everything that is part of the front end, apart from the compiler executables listed in -# compilers in config-lang.in. rust.install-common: installdirs -rm -f $(DESTDIR)$(bindir)/$(GCCRUST_INSTALL_NAME)$(exeext) $(INSTALL_PROGRAM) gccrust$(exeext) $(DESTDIR)$(bindir)/$(GCCRUST_INSTALL_NAME)$(exeext) @@ -140,44 +144,46 @@ rust.install-common: installdirs fi; \ fi -# Install headers needed for plugins. rust.install-plugin: -rust.install-info: $(DESTDIR)$(infodir)/gccrust.info - -rust.install-pdf: doc/gccrust.pdf - @$(NORMAL_INSTALL) - test -z "$(pdfdir)" || $(mkinstalldirs) "$(DESTDIR)$(pdfdir)/gcc" - @for p in doc/gccrust.pdf; do \ - if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ - f=$(pdf__strip_dir) \ - echo " $(INSTALL_DATA) '$$d$$p' '$(DESTDIR)$(pdfdir)/gcc/$$f'"; \ - $(INSTALL_DATA) "$$d$$p" "$(DESTDIR)$(pdfdir)/gcc/$$f"; \ - done - -rust.install-html: $(build_htmldir)/rust - @$(NORMAL_INSTALL) - test -z "$(htmldir)" || $(mkinstalldirs) "$(DESTDIR)$(htmldir)" - @for p in $(build_htmldir)/rust; do \ - if test -f "$$p" || test -d "$$p"; then d=""; else d="$(srcdir)/"; fi; \ - f=$(html__strip_dir) \ - if test -d "$$d$$p"; then \ - echo " $(mkinstalldirs) '$(DESTDIR)$(htmldir)/$$f'"; \ - $(mkinstalldirs) "$(DESTDIR)$(htmldir)/$$f" || exit 1; \ - echo " $(INSTALL_DATA) '$$d$$p'/* '$(DESTDIR)$(htmldir)/$$f'"; \ - $(INSTALL_DATA) "$$d$$p"/* "$(DESTDIR)$(htmldir)/$$f"; \ - else \ - echo " $(INSTALL_DATA) '$$d$$p' '$(DESTDIR)$(htmldir)/$$f'"; \ - $(INSTALL_DATA) "$$d$$p" "$(DESTDIR)$(htmldir)/$$f"; \ - fi; \ - done - -rust.install-man: $(DESTDIR)$(man1dir)/$(GCCRUST_INSTALL_NAME)$(man1ext) - -$(DESTDIR)$(man1dir)/$(GCCRUST_INSTALL_NAME)$(man1ext): doc/gccrust.1 installdirs - -rm -f $@ - -$(INSTALL_DATA) $< $@ - -chmod a-x $@ +# rust.install-info: $(DESTDIR)$(infodir)/gccrust.info +rust.install-info: + +# rust.install-pdf: doc/gccrust.pdf +# @$(NORMAL_INSTALL) +# test -z "$(pdfdir)" || $(mkinstalldirs) "$(DESTDIR)$(pdfdir)/gcc" +# @for p in doc/gccrust.pdf; do \ +# if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ +# f=$(pdf__strip_dir) \ +# echo " $(INSTALL_DATA) '$$d$$p' '$(DESTDIR)$(pdfdir)/gcc/$$f'"; \ +# $(INSTALL_DATA) "$$d$$p" "$(DESTDIR)$(pdfdir)/gcc/$$f"; \ +# done +rust.install-pdf: + +# rust.install-html: $(build_htmldir)/rust +# @$(NORMAL_INSTALL) +# test -z "$(htmldir)" || $(mkinstalldirs) "$(DESTDIR)$(htmldir)" +# @for p in $(build_htmldir)/rust; do \ +# if test -f "$$p" || test -d "$$p"; then d=""; else d="$(srcdir)/"; fi; \ +# f=$(html__strip_dir) \ +# if test -d "$$d$$p"; then \ +# echo " $(mkinstalldirs) '$(DESTDIR)$(htmldir)/$$f'"; \ +# $(mkinstalldirs) "$(DESTDIR)$(htmldir)/$$f" || exit 1; \ +# echo " $(INSTALL_DATA) '$$d$$p'/* '$(DESTDIR)$(htmldir)/$$f'"; \ +# $(INSTALL_DATA) "$$d$$p"/* "$(DESTDIR)$(htmldir)/$$f"; \ +# else \ +# echo " $(INSTALL_DATA) '$$d$$p' '$(DESTDIR)$(htmldir)/$$f'"; \ +# $(INSTALL_DATA) "$$d$$p" "$(DESTDIR)$(htmldir)/$$f"; \ +# fi; \ +# done + +# rust.install-man: $(DESTDIR)$(man1dir)/$(GCCRUST_INSTALL_NAME)$(man1ext) +rust.install-man: + +# $(DESTDIR)$(man1dir)/$(GCCRUST_INSTALL_NAME)$(man1ext): doc/gccrust.1 installdirs +# -rm -f $@ +# -$(INSTALL_DATA) $< $@ +# -chmod a-x $@ rust.uninstall: rm -rf $(DESTDIR)$(bindir)/$(GCCRUST_INSTALL_NAME)$(exeext) @@ -218,10 +224,23 @@ RUSTINCLUDES = -I $(srcdir)/rust -I $(srcdir)/rust/rustfrontend CFLAGS-rust/rust-gcc.o += $(RUSTINCLUDES) CFLAGS-rust/rust-linemap.o += $(RUSTINCLUDES) -CFLAGS-rust/rust-sha1.o += $(RUSTINCLUDES) CFLAGS-rust/rust-gcc-diagnostics.o += $(RUSTINCLUDES) CFLAGS-rust/rust-encode-id.o += $(RUSTINCLUDES) +rust/rs-parser.cc: rust/rustfrontend/rs-parser.y + $(BISON) $(RSBISONFLAGS) --defines=rust/rs-parser.h -o $@ $< + +rust/rs-lexer.cc: rust/rustfrontend/rs-lexer.l + $(FLEX) $(RSFLEXFLAGS) -o $@ $< + +rust/rs-parser.o: rust/rs-parser.cc + $(COMPILE) $(RUSTINCLUDES) $< + $(POSTCOMPILE) + +rust/rs-lexer.o: rust/rs-lexer.cc + $(COMPILE) $(RUSTINCLUDES) $< + $(POSTCOMPILE) + rust/%.o: rust/rustfrontend/%.cc $(COMPILE) $(RUSTINCLUDES) $< $(POSTCOMPILE) diff --git a/gcc/rust/config-lang.in b/gcc/rust/config-lang.in index c023de0..0fd7109 100644 --- a/gcc/rust/config-lang.in +++ b/gcc/rust/config-lang.in @@ -23,26 +23,12 @@ # # language - name of language as it would appear in $(LANGUAGES) # compilers - value to add to $(COMPILERS) -# diff_excludes - files to ignore when building diffs between two versions. language="rust" - -# Space-separated list of compiler executables that will be run by the driver. The names here will -# each end with ‘\$(exeext)’. compilers="rust1\$(exeext)" -# Do not build by default. build_by_default="no" -# Lists (space-separated) language front ends other than C that this front end requires to be -# enabled (with the names given being their language settings). -#lang_requires_boot_languages=c++ - -# Lists (space-separated) targets in the top level Makefile to build the runtime libraries -# for this language, such as target-libobjc. target_libs="target-libffi target-libbacktrace" -# Space-separated list of files that should be scanned by gengtype.c to generate the garbage -# collection tables and routines for this language. This excludes the files that are common to all -# front ends. gtfiles="\$(srcdir)/rust/rust-lang.c \$(srcdir)/rust/rust-c.h" diff --git a/gcc/rust/lang-specs.h b/gcc/rust/lang-specs.h index 9b4a3ec..513e951 100644 --- a/gcc/rust/lang-specs.h +++ b/gcc/rust/lang-specs.h @@ -17,15 +17,9 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -// describes Rust front-end to GCC driver - -/* tells GCC to invoke Rust frontend on .rs files, gives instructions on - other programs to be run, such as assembler, etc. - In this, it has grs1 as the actual compiler and whatever */ /* This is the contribution to the `default_compilers' array in gcc.c for the Rust language. */ + {".rs", "@rs", 0, 1, 0}, {"@rs", "rust1 %i %(cc1_options) %{I*} %{L*} %D %{!fsyntax-only:%(invoke_as)}", 0, 1, 0}, - -// "May take a while" to write this file - refer to other language lang-specs.h
\ No newline at end of file diff --git a/gcc/rust/lang.opt b/gcc/rust/lang.opt index 7e67bda..42c6093 100644 --- a/gcc/rust/lang.opt +++ b/gcc/rust/lang.opt @@ -22,8 +22,6 @@ ; Please try to keep this file in ASCII collating order. -; Describes command-line options used by this frontend - Language Rust diff --git a/gcc/rust/old/rdot-dataflow.cc b/gcc/rust/old/rdot-dataflow.cc index 575222a..f63afb8 100644 --- a/gcc/rust/old/rdot-dataflow.cc +++ b/gcc/rust/old/rdot-dataflow.cc @@ -16,122 +16,147 @@ #include "rust.h" -static std::vector<std::map<std::string, rdot>*> context; -static rdot dot_pass_typeifyExprNode(rdot); -static bool dot_pass_typeCompare(const rdot, const rdot); +static std::vector<std::map<std::string, rdot> *> context; +static rdot dot_pass_typeifyExprNode (rdot); +static bool dot_pass_typeCompare (const rdot, const rdot); static rdot impl_master = NULL_DOT; -// Seems to push a new empty map onto the "context" vector -static void dot_pass_dataFlow_pushCtx(void) { - std::map<std::string, rdot>* ctx = new std::map<std::string, rdot>; - context.push_back(ctx); +static +void dot_pass_dataFlow_pushCtx (void) +{ + std::map<std::string, rdot> * ctx = new std::map<std::string, rdot>; + context.push_back (ctx); } -// Seems to pop the map off of the end of the "context" vector (i.e. deletes it) -static void dot_pass_dataFlow_popCtx(void) { - std::map<std::string, rdot>* ctx = context.back(); - context.pop_back(); - delete ctx; +static +void dot_pass_dataFlow_popCtx (void) +{ + std::map<std::string, rdot> * ctx = context.back (); + context.pop_back (); + delete ctx; } -// Presumably looks up id in the context map somehow, and returns the value -static rdot dot_pass_dataFlow_lookup(const char* id) { - rdot retval = NULL_DOT; - std::vector<std::map<std::string, rdot>*>::reverse_iterator it; - for (it = context.rbegin(); it != context.rend(); ++it) { - std::map<std::string, rdot>* ctx = *it; - if (ctx->count(std::string(id))) { - retval = (*ctx)[std::string(id)]; - break; +static +rdot dot_pass_dataFlow_lookup (const char * id) +{ + rdot retval = NULL_DOT; + std::vector<std::map<std::string, rdot> *>::reverse_iterator it; + for (it = context.rbegin (); it != context.rend (); ++it) + { + std::map<std::string, rdot> * ctx = *it; + if (ctx->count (std::string (id))) + { + retval = (*ctx)[std::string (id)]; + break; } } - return retval; + return retval; } -// Appends node to the back of context? Or replaces final context with node? -static bool dot_pass_dataFlow_pushDecl(rdot node, const char* id) { - rdot check = dot_pass_dataFlow_lookup(id); - if (check != NULL_DOT) { - error("DataFlow duplicate declaration [%s]\n", id); - return true; +static +bool dot_pass_dataFlow_pushDecl (rdot node, const char * id) +{ + rdot check = dot_pass_dataFlow_lookup (id); + if (check != NULL_DOT) + { + error ("DataFlow duplicate declaration [%s]\n", id); + return true; } - bool retval = false; - if ((RDOT_TYPE(node) == D_VAR_DECL) || (RDOT_TYPE(node) == D_STRUCT_METHOD) - || (RDOT_TYPE(node) == D_STRUCT_TYPE)) { - std::map<std::string, rdot>* ctx = context.back(); - (*ctx)[std::string(id)] = node; - } else { - error("Invalid dataflow declaration pushing to context [%s]\n", - RDOT_OPCODE_STR(node)); - retval = true; + bool retval = false; + if ((RDOT_TYPE (node) == D_VAR_DECL) + || (RDOT_TYPE (node) == D_STRUCT_METHOD) + || (RDOT_TYPE (node) == D_STRUCT_TYPE)) + { + std::map<std::string, rdot> * ctx = context.back (); + (*ctx) [std::string (id)] = node; + } + else + { + error ("Invalid dataflow declaration pushing to context [%s]\n", + RDOT_OPCODE_STR (node)); + retval = true; } - return retval; + return retval; } -static void dot_pass_dataFlowToplevel(rdot); -static void dot_pass_dataFlowFunction(rdot); -static void dot_pass_dataFlowBlock(rdot); - -// Only returns true if node's type is boolean, int, float, or unsigned int -static bool verifyType(rdot node) { - bool retval = false; - switch (RDOT_TYPE(node)) { - case RTYPE_BOOL: - case RTYPE_INT: - case RTYPE_FLOAT: - case RTYPE_UINT: - retval = true; - break; - - default: - break; +static void dot_pass_dataFlowToplevel (rdot); +static void dot_pass_dataFlowFunction (rdot); +static void dot_pass_dataFlowBlock (rdot); + +static +bool verifyType (rdot node) +{ + bool retval = false; + switch (RDOT_TYPE (node)) + { + case RTYPE_BOOL: + case RTYPE_INT: + case RTYPE_FLOAT: + case RTYPE_UINT: + retval = true; + break; + + default: + break; } - return retval; + return retval; } -// Presumably returns the variable declaration contained in the node -static rdot dot_pass_dataFlow_getDecl(rdot node) { - rdot retval = NULL_DOT; - if (RDOT_T_FIELD(node) == D_D_EXPR) { - // only if its a modify expr - if (RDOT_TYPE(node) == D_MODIFY_EXPR) { - rdot decl = RDOT_lhs_TT(node); - if (RDOT_TYPE(decl) == D_VAR_DECL) - retval = decl; - } else if (RDOT_TYPE(node) == D_VAR_DECL) - retval = node; +static +rdot dot_pass_dataFlow_getDecl (rdot node) +{ + rdot retval = NULL_DOT; + if (RDOT_T_FIELD (node) == D_D_EXPR) + { + // only if its a modify expr + if (RDOT_TYPE (node) == D_MODIFY_EXPR) + { + rdot decl = RDOT_lhs_TT (node); + if (RDOT_TYPE (decl) == D_VAR_DECL) + retval = decl; + } + else if (RDOT_TYPE (node) == D_VAR_DECL) + retval = node; } - return retval; + return retval; } -// Seems to add return values to retval vector? Finds return values? -static void dot_pass_dataFlowBlock_retvals(rdot suite, std::vector<rdot>* retval) { - rdot next; - for (next = suite; next != NULL_DOT; next = RDOT_CHAIN(next)) { - if (RDOT_T_FIELD(next) == D_D_EXPR) { - if (DOT_RETVAL(next)) - retval->push_back(next); - } else { - switch (RDOT_TYPE(next)) { - case D_STRUCT_WHILE: - dot_pass_dataFlowBlock_retvals(RDOT_rhs_TT(next), retval); - break; - - case D_STRUCT_IF: { - rdot ifblock = RDOT_lhs_TT(next); - rdot elseblock = RDOT_rhs_TT(next); - dot_pass_dataFlowBlock_retvals(RDOT_rhs_TT(ifblock), retval); - if (elseblock != NULL_DOT) - dot_pass_dataFlowBlock_retvals(RDOT_lhs_TT(elseblock), retval); - } break; - - default: - error("unable to figure out what to do with [%s]", - RDOT_OPCODE_STR(next)); - break; - } - } +static +void dot_pass_dataFlowBlock_retvals (rdot suite, std::vector<rdot> * retval) +{ + rdot next; + for (next = suite; next != NULL_DOT; next = RDOT_CHAIN (next)) + { + if (RDOT_T_FIELD (next) == D_D_EXPR) + { + if (DOT_RETVAL (next)) + retval->push_back (next); + } + else + { + switch (RDOT_TYPE (next)) + { + case D_STRUCT_WHILE: + dot_pass_dataFlowBlock_retvals (RDOT_rhs_TT (next), retval); + break; + + case D_STRUCT_IF: + { + rdot ifblock = RDOT_lhs_TT (next); + rdot elseblock = RDOT_rhs_TT (next); + dot_pass_dataFlowBlock_retvals (RDOT_rhs_TT (ifblock), retval); + if (elseblock != NULL_DOT) + dot_pass_dataFlowBlock_retvals (RDOT_lhs_TT (elseblock), retval); + } + break; + + default: + error ("unable to figure out what to do with [%s]", + RDOT_OPCODE_STR (next)); + break; + } + } } } @@ -146,132 +171,155 @@ static void dot_pass_dataFlowBlock_retvals(rdot suite, std::vector<rdot>* retval let x = 1; ruturns RDOT (1) */ -static rdot dot_pass_dataFlow_getRef(rdot decl, rdot var_decl) { - rdot retval = NULL_DOT; - if (RDOT_TYPE(decl) == D_MODIFY_EXPR) { - rdot lhs = RDOT_lhs_TT(decl); - rdot rhs = RDOT_rhs_TT(decl); - - switch (RDOT_TYPE(lhs)) { - case D_VAR_DECL: { - if (var_decl == lhs) - retval = rhs; - } break; - - case D_IDENTIFIER: { - const char* vid = RDOT_IDENTIFIER_POINTER(RDOT_lhs_TT(var_decl)); - const char* cid = RDOT_IDENTIFIER_POINTER(lhs); - // we found a reference assignment... - if (strcmp(vid, cid) == 0) - retval = rhs; - } break; - - default: - break; +static +rdot dot_pass_dataFlow_getRef (rdot decl, rdot var_decl) +{ + rdot retval = NULL_DOT; + if (RDOT_TYPE (decl) == D_MODIFY_EXPR) + { + rdot lhs = RDOT_lhs_TT (decl); + rdot rhs = RDOT_rhs_TT (decl); + + switch (RDOT_TYPE (lhs)) + { + case D_VAR_DECL: + { + if (var_decl == lhs) + retval = rhs; + } + break; + + case D_IDENTIFIER: + { + const char * vid = RDOT_IDENTIFIER_POINTER (RDOT_lhs_TT (var_decl)); + const char * cid = RDOT_IDENTIFIER_POINTER (lhs); + // we found a reference assignment... + if (strcmp (vid, cid) == 0) + retval = rhs; + } + break; + + default: + break; } } - return retval; + return retval; } -// Seems to be a more complicated version of getRef that can also get references in other places -static std::vector<rdot>* dot_pass_getReferences(rdot vDecl, rdot suite) { - std::vector<rdot>* retval = new std::vector<rdot>; - rdot node; - for (node = suite; node != NULL_DOT; node = RDOT_CHAIN(node)) { - switch (RDOT_TYPE(node)) { - case D_PRIMITIVE: - case D_CALL_EXPR: - case D_ATTRIB_REF: - break; - - case D_MODIFY_EXPR: { - rdot ref = dot_pass_dataFlow_getRef(node, vDecl); - if (ref != NULL_DOT) - retval->push_back(ref); - } break; - - case D_STRUCT_WHILE: { - rdot wsuite = RDOT_rhs_TT(node); - std::vector<rdot>* refs = dot_pass_getReferences(vDecl, wsuite); - // append to the list - std::vector<rdot>::iterator it; - for (it = refs->begin(); it != refs->end(); ++it) - retval->push_back(*it); - delete refs; - } break; - - case D_STRUCT_IF: { - rdot ifb = RDOT_lhs_TT(node); - rdot elb = RDOT_rhs_TT(node); - - rdot ifsuite = RDOT_rhs_TT(ifb); - std::vector<rdot>* refs = dot_pass_getReferences(vDecl, ifsuite); - - // append to the list - std::vector<rdot>::iterator it; - for (it = refs->begin(); it != refs->end(); ++it) - retval->push_back(*it); - delete refs; - - if (elb != NULL_DOT) { - refs = dot_pass_getReferences(vDecl, RDOT_lhs_TT(elb)); - for (it = refs->begin(); it != refs->end(); ++it) - retval->push_back(*it); - delete refs; - } - } - - default: - break; - } +static +std::vector<rdot> * dot_pass_getReferences (rdot vDecl, rdot suite) +{ + std::vector<rdot> * retval = new std::vector<rdot>; + rdot node; + for (node = suite; node != NULL_DOT; node = RDOT_CHAIN (node)) + { + switch (RDOT_TYPE (node)) + { + case D_PRIMITIVE: + case D_CALL_EXPR: + case D_ATTRIB_REF: + break; + + case D_MODIFY_EXPR: + { + rdot ref = dot_pass_dataFlow_getRef (node, vDecl); + if (ref != NULL_DOT) + retval->push_back (ref); + } + break; + + case D_STRUCT_WHILE: + { + rdot wsuite = RDOT_rhs_TT (node); + std::vector<rdot> * refs = dot_pass_getReferences (vDecl, wsuite); + // append to the list + std::vector<rdot>::iterator it; + for (it = refs->begin (); it != refs->end (); ++it) + retval->push_back (*it); + delete refs; + } + break; + + case D_STRUCT_IF: + { + rdot ifb = RDOT_lhs_TT (node); + rdot elb = RDOT_rhs_TT (node); + + rdot ifsuite = RDOT_rhs_TT (ifb); + std::vector<rdot> * refs = dot_pass_getReferences (vDecl, ifsuite); + + // append to the list + std::vector<rdot>::iterator it; + for (it = refs->begin (); it != refs->end (); ++it) + retval->push_back (*it); + delete refs; + + if (elb != NULL_DOT) + { + refs = dot_pass_getReferences (vDecl, RDOT_lhs_TT (elb)); + for (it = refs->begin (); it != refs->end (); ++it) + retval->push_back (*it); + delete refs; + } + } + + default: + break; + } } - return retval; + return retval; } -// Seems to compare types of x and y -static bool dot_pass_typeCompare(const rdot x, const rdot y) { - bool retval = false; - if (RDOT_TYPE(x) == RDOT_TYPE(y)) - if (RDOT_MEM_MODIFIER(x)->size() == RDOT_MEM_MODIFIER(y)->size()) { - retval = true; - std::vector<ALLOCA_>::iterator xit; - std::vector<ALLOCA_>::iterator yit; - for (xit = RDOT_MEM_MODIFIER(x)->begin(), - yit = RDOT_MEM_MODIFIER(y)->begin(); - xit != RDOT_MEM_MODIFIER(x)->end(); - ++xit, ++yit) { - if (*xit != *yit) { - retval = false; - break; - } - } - } - return retval; +static bool +dot_pass_typeCompare (const rdot x, const rdot y) +{ + bool retval = false; + if (RDOT_TYPE (x) == RDOT_TYPE (y)) + if (RDOT_MEM_MODIFIER (x)->size () == RDOT_MEM_MODIFIER (y)->size ()) + { + retval = true; + std::vector<ALLOCA_>::iterator xit; + std::vector<ALLOCA_>::iterator yit; + for (xit = RDOT_MEM_MODIFIER (x)->begin (), + yit = RDOT_MEM_MODIFIER (y)->begin (); + xit != RDOT_MEM_MODIFIER (x)->end (); + ++xit, ++yit) + { + if (*xit != *yit) + { + retval = false; + break; + } + } + } + return retval; } -// Seems to return a string created from allocations (dereference and reference) -static char* dot_pass_typeString(const rdot node) { - char buffer[128]; - size_t offset = 0; - - std::vector<ALLOCA_>::iterator it; - for (it = RDOT_MEM_MODIFIER(node)->begin(); - it != RDOT_MEM_MODIFIER(node)->end(); - ++it) { - switch (*it) { - case ALLOC_DEREF: - buffer[offset++] = '*'; - break; - case ALLOC_HEAP: - buffer[offset++] = '~'; - break; - case ALLOC_REF: - buffer[offset++] = '&'; - break; - } +static char * +dot_pass_typeString (const rdot node) +{ + char buffer [128]; + size_t offset = 0; + + std::vector<ALLOCA_>::iterator it; + for (it = RDOT_MEM_MODIFIER (node)->begin (); + it != RDOT_MEM_MODIFIER (node)->end (); ++it ) + { + switch (*it) + { + case ALLOC_DEREF: + buffer [offset++] = '*'; + break; + case ALLOC_HEAP: + buffer [offset++] = '~'; + break; + case ALLOC_REF: + buffer [offset++] = '&'; + break; + } } - strcpy(buffer + offset, RDOT_OPCODE_STR(node)); - return xstrdup(buffer); + strcpy (buffer+offset, RDOT_OPCODE_STR (node)); + return xstrdup (buffer); } /** @@ -280,494 +328,556 @@ static char* dot_pass_typeString(const rdot node) { * infer, int, string * infer, int, infer. Does it mean its an int probably. * Currently it drops any possible type to be an int - * - * Presumably infers type of refs **/ -static rdot dot_pass_inferTheType(std::vector<rdot>* refs, const char* id) { - rdot retval = NULL_DOT; - rdot _retval = rdot_build_decl1(RTYPE_INFER, NULL_DOT); - gcc_assert(refs->size() > 0); - - std::vector<rdot> possible_types; - std::vector<rdot>::iterator it; - for (it = refs->begin(); it != refs->end(); ++it) { - rdot pos = dot_pass_typeifyExprNode(*it); - if (RDOT_TYPE(pos) != RTYPE_INFER) - possible_types.push_back(pos); +static +rdot dot_pass_inferTheType (std::vector<rdot> * refs, const char * id) +{ + rdot retval = NULL_DOT; + rdot _retval = rdot_build_decl1 (RTYPE_INFER, NULL_DOT); + gcc_assert (refs->size () > 0); + + std::vector<rdot> possible_types; + std::vector<rdot>::iterator it; + for (it = refs->begin (); it != refs->end (); ++it) + { + rdot pos = dot_pass_typeifyExprNode (*it); + if (RDOT_TYPE (pos) != RTYPE_INFER) + possible_types.push_back (pos); } - if (possible_types.size() == 0) - retval = _retval; - else { - bool first = true; - std::vector<rdot>::iterator pit; - for (pit = possible_types.begin(); pit != possible_types.end(); ++pit) { - if (first == true) { - retval = *pit; - first = false; - } - if (!dot_pass_typeCompare(retval, *pit)) { - char* t1 = dot_pass_typeString(retval); - char* t2 = dot_pass_typeString(*pit); - error("Ambigious types found for [%s] -> [%s] OR [%s]", id, t1, t2); - retval = _retval; - free(t1); - free(t2); - break; - } - } + if (possible_types.size () == 0) + retval = _retval; + else + { + bool first = true; + std::vector<rdot>::iterator pit; + for (pit = possible_types.begin (); pit != possible_types.end (); ++pit) + { + if (first == true) + { + retval = *pit; + first = false; + } + if (!dot_pass_typeCompare (retval, *pit)) + { + char * t1 = dot_pass_typeString (retval); + char * t2 = dot_pass_typeString (*pit); + error ("Ambigious types found for [%s] -> [%s] OR [%s]", id, t1, t2); + retval = _retval; + free (t1); + free (t2); + break; + } + } } - return retval; + return retval; } -// Seems to determine the type of a primitive (and apply it)? -static rdot dot_pass_typeifyPrimitive(rdot node) { - rdot retval = rdot_build_decl1(RTYPE_INFER, NULL_DOT); - gcc_assert(RDOT_TYPE(node) == D_PRIMITIVE); - - switch (node->opa.tc.T == D_T_INTEGER) { - case D_T_INTEGER: - RDOT_TYPE(retval) = RTYPE_INT; - break; - - default: - error("Unable to figure out type for this primitive [%s]!", - RDOT_CODE_STR(node->opa.tc.T)); - break; +static +rdot dot_pass_typeifyPrimitive (rdot node) +{ + rdot retval = rdot_build_decl1 (RTYPE_INFER, NULL_DOT); + gcc_assert (RDOT_TYPE (node) == D_PRIMITIVE); + + switch (node->opa.tc.T == D_T_INTEGER) + { + case D_T_INTEGER: + RDOT_TYPE (retval) = RTYPE_INT; + break; + + default: + error ("Unable to figure out type for this primitive [%s]!", + RDOT_CODE_STR (node->opa.tc.T)); + break; } - std::vector<ALLOCA_>::iterator it; - for (it = RDOT_MEM_MODIFIER(node)->begin(); - it != RDOT_MEM_MODIFIER(node)->end(); - ++it) - RDOT_MEM_MODIFIER(retval)->push_back(*it); - return retval; + std::vector<ALLOCA_>::iterator it; + for (it = RDOT_MEM_MODIFIER (node)->begin (); + it != RDOT_MEM_MODIFIER (node)->end (); ++it) + RDOT_MEM_MODIFIER (retval)->push_back (*it); + return retval; } -/* FIXME maybe i feel this isn't done very well at all here - * - * Seems to determine type of an expression node and return something idk, very complicated */ -static rdot dot_pass_typeifyExprNode(rdot node) { - rdot retval = rdot_build_decl1(RTYPE_INFER, NULL_DOT); - switch (RDOT_TYPE(node)) { - case D_PRIMITIVE: - retval = dot_pass_typeifyPrimitive(node); - break; - - case D_IDENTIFIER: { - rdot lookup = dot_pass_dataFlow_lookup(RDOT_IDENTIFIER_POINTER(node)); - if (lookup == NULL_DOT) - error("unable to find declaration of [%s] in current scope", - RDOT_IDENTIFIER_POINTER(node)); - else { - gcc_assert(RDOT_TYPE(lookup) == D_VAR_DECL); - RDOT_TYPE(retval) = RDOT_TYPE(RDOT_rhs_TT(lookup)); - if (RDOT_TYPE(retval) == RTYPE_USER_STRUCT) { - RDOT_lhs_TT(retval) = RDOT_lhs_TT(RDOT_rhs_TT(lookup)); - RDOT_rhs_TT(retval) = RDOT_rhs_TT(RDOT_rhs_TT(lookup)); - } - std::vector<ALLOCA_>::iterator it; - if (RDOT_MEM_MODIFIER(node)) - for (it = RDOT_MEM_MODIFIER(node)->begin(); - it != RDOT_MEM_MODIFIER(node)->end(); - ++it) - RDOT_MEM_MODIFIER(retval)->push_back(*it); - if (RDOT_MEM_MODIFIER(RDOT_rhs_TT(lookup))) - for (it = RDOT_MEM_MODIFIER(RDOT_rhs_TT(lookup))->begin(); - it != RDOT_MEM_MODIFIER(RDOT_rhs_TT(lookup))->end(); - ++it) - RDOT_MEM_MODIFIER(retval)->push_back(*it); - } - } break; - - case D_STRUCT_INIT: { - const char* slookup = RDOT_IDENTIFIER_POINTER(RDOT_lhs_TT(node)); - rdot lookup = dot_pass_dataFlow_lookup(slookup); - if (lookup != NULL_DOT) { - if (RDOT_TYPE(lookup) == D_STRUCT_TYPE) { - RDOT_TYPE(retval) = RTYPE_USER_STRUCT; - RDOT_lhs_TT(retval) = RDOT_lhs_TT(lookup); // identifier node - RDOT_rhs_TT(retval) = RDOT_rhs_TT(lookup); // struct layout - std::vector<ALLOCA_>::iterator it; - if (RDOT_MEM_MODIFIER(node)) - for (it = RDOT_MEM_MODIFIER(node)->begin(); - it != RDOT_MEM_MODIFIER(node)->end(); - ++it) - RDOT_MEM_MODIFIER(retval)->push_back(*it); - if (RDOT_MEM_MODIFIER(lookup)) - for (it = RDOT_MEM_MODIFIER(lookup)->begin(); - it != RDOT_MEM_MODIFIER(lookup)->end(); - ++it) - RDOT_MEM_MODIFIER(retval)->push_back(*it); - } else - error("unable to determine type of [%s] struct initilization, " - "[%s] was found in this scope", - slookup, - RDOT_OPCODE_STR(lookup)); - } else - error("[%s] does not name a type in scope", slookup); - } break; - - case D_CALL_EXPR: { - const char* callid = RDOT_IDENTIFIER_POINTER(RDOT_lhs_TT(node)); - rdot lookup = dot_pass_dataFlow_lookup(callid); - if (lookup != NULL_DOT) { - gcc_assert(RDOT_TYPE(lookup) == D_STRUCT_METHOD); - RDOT_TYPE(retval) = RDOT_TYPE(RDOT_FIELD2(lookup)); - std::vector<ALLOCA_>* mods = RDOT_MEM_MODIFIER(RDOT_FIELD2(lookup)); +/* FIXME maybe i feel this isn't done very well at all here */ +static +rdot dot_pass_typeifyExprNode (rdot node) +{ + rdot retval = rdot_build_decl1 (RTYPE_INFER, NULL_DOT); + switch (RDOT_TYPE (node)) + { + case D_PRIMITIVE: + retval = dot_pass_typeifyPrimitive (node); + break; + + case D_IDENTIFIER: + { + rdot lookup = dot_pass_dataFlow_lookup (RDOT_IDENTIFIER_POINTER (node)); + if (lookup == NULL_DOT) + error ("unable to find declaration of [%s] in current scope", + RDOT_IDENTIFIER_POINTER (node)); + else + { + gcc_assert (RDOT_TYPE (lookup) == D_VAR_DECL); + RDOT_TYPE (retval) = RDOT_TYPE (RDOT_rhs_TT (lookup)); + if (RDOT_TYPE (retval) == RTYPE_USER_STRUCT) + { + RDOT_lhs_TT (retval) = RDOT_lhs_TT (RDOT_rhs_TT (lookup)); + RDOT_rhs_TT (retval) = RDOT_rhs_TT (RDOT_rhs_TT (lookup)); + } + std::vector<ALLOCA_>::iterator it; + if (RDOT_MEM_MODIFIER (node)) + for (it = RDOT_MEM_MODIFIER (node)->begin (); + it != RDOT_MEM_MODIFIER (node)->end (); ++it) + RDOT_MEM_MODIFIER (retval)->push_back (*it); + if (RDOT_MEM_MODIFIER (RDOT_rhs_TT (lookup))) + for (it = RDOT_MEM_MODIFIER (RDOT_rhs_TT (lookup))->begin (); + it != RDOT_MEM_MODIFIER (RDOT_rhs_TT (lookup))->end (); ++it) + RDOT_MEM_MODIFIER (retval)->push_back (*it); + } + } + break; + + case D_STRUCT_INIT: + { + const char * slookup = RDOT_IDENTIFIER_POINTER (RDOT_lhs_TT (node)); + rdot lookup = dot_pass_dataFlow_lookup (slookup); + if (lookup != NULL_DOT) + { + if (RDOT_TYPE (lookup) == D_STRUCT_TYPE) + { + RDOT_TYPE (retval) = RTYPE_USER_STRUCT; + RDOT_lhs_TT (retval) = RDOT_lhs_TT (lookup); // identifier node + RDOT_rhs_TT (retval) = RDOT_rhs_TT (lookup); // struct layout std::vector<ALLOCA_>::iterator it; - if (RDOT_MEM_MODIFIER(node)) - for (it = RDOT_MEM_MODIFIER(node)->begin(); - it != RDOT_MEM_MODIFIER(node)->end(); - ++it) - RDOT_MEM_MODIFIER(retval)->push_back(*it); - if (mods) - for (it = mods->begin(); it != mods->end(); ++it) - RDOT_MEM_MODIFIER(retval)->push_back(*it); - } else - error("unable to find declaration of [%s] in current scope", - callid); - } break; - - case D_ATTRIB_REF: { - rdot lhs = RDOT_lhs_TT(node); - rdot base_type = dot_pass_typeifyExprNode(lhs); - gcc_assert(RDOT_TYPE(base_type) == RTYPE_USER_STRUCT); - } break; - - case D_ACC_EXPR: { - rdot impl = RDOT_lhs_TT(node); - char* implid = RDOT_IDENTIFIER_POINTER(impl); - rdot lookup = dot_pass_dataFlow_lookup(implid); - - bool found = false; - rdot next; - for (next = RDOT_rhs_TT(RDOT_FIELD(lookup)); - next != NULL_DOT; - next = RDOT_CHAIN(next)) { - switch (RDOT_TYPE(next)) { - case D_STRUCT_METHOD: - RDOT_TYPE(retval) = RDOT_TYPE(RDOT_FIELD2(next)); - break; - - default: - error_at(RDOT_LOCATION(next), "unable to identify [%s] for type inferance", - RDOT_OPCODE_STR(next)); - break; - } - } - if (!found) - break; - } break; - - case D_ADD_EXPR: - case D_MINUS_EXPR: - case D_MULT_EXPR: - case D_DIVD_EXPR: { - rdot lhs = RDOT_lhs_TT(node); - rdot rhs = RDOT_rhs_TT(node); - - rdot lt = dot_pass_typeifyExprNode(lhs); - rdot rt = dot_pass_typeifyExprNode(rhs); - - if (RDOT_TYPE(lt) != RTYPE_INFER || RDOT_TYPE(rt) != RTYPE_INFER) { - if (RDOT_TYPE(lt) == RDOT_TYPE(rt)) - retval = lt; - else { - if (RDOT_TYPE(lt) == RTYPE_INFER || RDOT_TYPE(rt) == RTYPE_INFER) - retval = RDOT_TYPE(lt) == RTYPE_INFER ? rt : lt; - else - error("unable to coerce types [%s] and [%s]", - RDOT_OPCODE_STR(lt), - RDOT_OPCODE_STR(rt)); - } - } - } break; - - default: - error("Unable to figure out the type of this [%s]", - RDOT_OPCODE_STR(node)); - break; + if (RDOT_MEM_MODIFIER (node)) + for (it = RDOT_MEM_MODIFIER (node)->begin (); + it != RDOT_MEM_MODIFIER (node)->end (); ++it) + RDOT_MEM_MODIFIER (retval)->push_back (*it); + if (RDOT_MEM_MODIFIER (lookup)) + for (it = RDOT_MEM_MODIFIER (lookup)->begin (); + it != RDOT_MEM_MODIFIER (lookup)->end (); ++it) + RDOT_MEM_MODIFIER (retval)->push_back (*it); + } + else + error ("unable to determine type of [%s] struct initilization, " + "[%s] was found in this scope", + slookup, RDOT_OPCODE_STR (lookup)); + } + else + error ("[%s] does not name a type in scope", slookup); + } + break; + + case D_CALL_EXPR: + { + const char * callid = RDOT_IDENTIFIER_POINTER (RDOT_lhs_TT (node)); + rdot lookup = dot_pass_dataFlow_lookup (callid); + if (lookup != NULL_DOT) + { + gcc_assert (RDOT_TYPE (lookup) == D_STRUCT_METHOD); + RDOT_TYPE (retval) = RDOT_TYPE (RDOT_FIELD2 (lookup)); + std::vector<ALLOCA_> * mods = RDOT_MEM_MODIFIER (RDOT_FIELD2 (lookup)); + std::vector<ALLOCA_>::iterator it; + if (RDOT_MEM_MODIFIER (node)) + for (it = RDOT_MEM_MODIFIER (node)->begin (); + it != RDOT_MEM_MODIFIER (node)->end (); ++it) + RDOT_MEM_MODIFIER (retval)->push_back (*it); + if (mods) + for (it = mods->begin (); it != mods->end (); ++it) + RDOT_MEM_MODIFIER (retval)->push_back (*it); + } + else + error ("unable to find declaration of [%s] in current scope", + callid); + } + break; + + case D_ATTRIB_REF: + { + rdot lhs = RDOT_lhs_TT (node); + rdot base_type = dot_pass_typeifyExprNode (lhs); + gcc_assert (RDOT_TYPE (base_type) == RTYPE_USER_STRUCT); + } + break; + + case D_ACC_EXPR: + { + rdot impl = RDOT_lhs_TT (node); + char * implid = RDOT_IDENTIFIER_POINTER (impl); + rdot lookup = dot_pass_dataFlow_lookup (implid); + + bool found = false; + rdot next; + for (next = RDOT_rhs_TT (RDOT_FIELD (lookup)); + next != NULL_DOT; next = RDOT_CHAIN (next)) + { + switch (RDOT_TYPE (next)) + { + case D_STRUCT_METHOD: + RDOT_TYPE (retval) = RDOT_TYPE (RDOT_FIELD2 (next)); + break; + + default: + error_at (RDOT_LOCATION (next), "unable to identify [%s] for type inferance", + RDOT_OPCODE_STR (next)); + break; + } + } + if (!found) + break; + } + break; + + case D_ADD_EXPR: + case D_MINUS_EXPR: + case D_MULT_EXPR: + case D_DIVD_EXPR: + { + rdot lhs = RDOT_lhs_TT (node); + rdot rhs = RDOT_rhs_TT (node); + + rdot lt = dot_pass_typeifyExprNode (lhs); + rdot rt = dot_pass_typeifyExprNode (rhs); + + if (RDOT_TYPE (lt) != RTYPE_INFER + || RDOT_TYPE (rt) != RTYPE_INFER) + { + if (RDOT_TYPE (lt) == RDOT_TYPE (rt)) + retval = lt; + else + { + if (RDOT_TYPE (lt) == RTYPE_INFER || RDOT_TYPE (rt) == RTYPE_INFER) + retval = RDOT_TYPE (lt) == RTYPE_INFER ? rt : lt; + else + error ("unable to coerce types [%s] and [%s]", + RDOT_OPCODE_STR (lt), RDOT_OPCODE_STR (rt)); + } + } + } + break; + + default: + error ("Unable to figure out the type of this [%s]", + RDOT_OPCODE_STR (node)); + break; } - bool skip_next = false; - std::vector<ALLOCA_> nmods; - std::vector<ALLOCA_>* pmods = RDOT_MEM_MODIFIER(retval); - - std::vector<ALLOCA_>::iterator it; - for (it = pmods->begin(); it != pmods->end(); ++it) { - switch (*it) { - case ALLOC_DEREF: - skip_next = true; - break; - - default: { - if (!skip_next) { - nmods.push_back(*it); - skip_next = false; - } - } break; - } + bool skip_next = false; + std::vector<ALLOCA_> nmods; + std::vector<ALLOCA_> * pmods = RDOT_MEM_MODIFIER (retval); + + std::vector<ALLOCA_>::iterator it; + for (it = pmods->begin (); it != pmods->end (); ++it) + { + switch (*it) + { + case ALLOC_DEREF: + skip_next = true; + break; + + default: + { + if (!skip_next) + { + nmods.push_back (*it); + skip_next = false; + } + } + break; + } } - RDOT_MMEM_COPY((&nmods), RDOT_MEM_MODIFIER(retval)); - return retval; + RDOT_MMEM_COPY ((&nmods), RDOT_MEM_MODIFIER (retval)); + return retval; } -// Seems to check for mutability of node (mut check) and creates error if it is violated -static void dot_pass_mutability(const rdot node) { - rdot lhs = RDOT_lhs_TT(node); - if (RDOT_TYPE(lhs) != D_VAR_DECL) { - // check the nodes mutability - switch (RDOT_TYPE(lhs)) { - case D_IDENTIFIER: { - const char* ident = RDOT_IDENTIFIER_POINTER(lhs); - const rdot node = dot_pass_dataFlow_lookup(ident); - if (node == NULL_DOT) - error_at(RDOT_LOCATION(node), "Unable to find decl [%s] in current scope", ident); - else if (RDOT_qual(node) == true) - error_at(RDOT_LOCATION(node), "Unable to modify [%s] it is immutable", ident); - } break; - - default: { - const char* nstr = RDOT_OPCODE_STR(lhs); - warning_at(RDOT_LOCATION(node), 0, "TODO unable to verify assignment" - "mutability for [%s]", - nstr); - } break; - } +static +void dot_pass_mutability (const rdot node) +{ + rdot lhs = RDOT_lhs_TT (node); + if (RDOT_TYPE (lhs) != D_VAR_DECL) + { + // check the nodes mutability + switch (RDOT_TYPE (lhs)) + { + case D_IDENTIFIER: + { + const char * ident = RDOT_IDENTIFIER_POINTER (lhs); + const rdot node = dot_pass_dataFlow_lookup (ident); + if (node == NULL_DOT) + error_at (RDOT_LOCATION (node), "Unable to find decl [%s] in current scope", ident); + else if (RDOT_qual (node) == true) + error_at (RDOT_LOCATION (node), "Unable to modify [%s] it is immutable", ident); + } + break; + + default: + { + const char * nstr = RDOT_OPCODE_STR (lhs); + warning_at (RDOT_LOCATION (node), 0, "TODO unable to verify assignment" + "mutability for [%s]", nstr); + } + break; + } } } -/* Seems to check for various stuff - top level for checking a full block? - * - * Potentially defines block declarations and adds them to decls? (pass by reference) */ -static void dot_pass_dataFlowBlock_(rdot suite, std::vector<rdot>* decls) { - rdot node; - for (node = suite; node != NULL_DOT; node = RDOT_CHAIN(node)) { - if (RDOT_T_FIELD(node) == D_D_EXPR) { - if (RDOT_TYPE(node) == D_MODIFY_EXPR) - dot_pass_mutability(node); - - const char* id = NULL; - rdot decl = dot_pass_dataFlow_getDecl(node); - if (decl != NULL_DOT) { - gcc_assert(RDOT_TYPE(decl) == D_VAR_DECL); - id = RDOT_IDENTIFIER_POINTER(RDOT_lhs_TT(decl)); - decls->push_back(decl); - - // push it into the current context... - rdot lookup = dot_pass_dataFlow_lookup(id); - if (lookup != NULL_DOT) - error("Duplicate declaration of [%s] to [%s]", - id, - RDOT_OPCODE_STR(lookup)); - else - gcc_assert(!dot_pass_dataFlow_pushDecl(decl, id)); - } - } else { - switch (RDOT_TYPE(node)) { - case D_STRUCT_IF: { - rdot sif = RDOT_lhs_TT(node); - rdot ses = RDOT_rhs_TT(node); - - dot_pass_dataFlowBlock_(RDOT_rhs_TT(sif), decls); - if (ses != NULL_DOT) - dot_pass_dataFlowBlock_(RDOT_lhs_TT(ses), decls); - } break; - - case D_STRUCT_WHILE: - dot_pass_dataFlowBlock_(RDOT_rhs_TT(node), decls); - break; - - case D_STRUCT_LOOP: - dot_pass_dataFlowBlock_(RDOT_lhs_TT(node), decls); - break; - - case C_BREAK_STMT: - case C_CONT_STMT: - break; - - default: - error("Unhandled data flow in block on [%s]\n", RDOT_OPCODE_STR(node)); - break; +static +void dot_pass_dataFlowBlock_ (rdot suite, std::vector<rdot> * decls) +{ + rdot node; + for (node = suite; node != NULL_DOT; node = RDOT_CHAIN (node)) + { + if (RDOT_T_FIELD (node) == D_D_EXPR) + { + if (RDOT_TYPE (node) == D_MODIFY_EXPR) + dot_pass_mutability (node); + + const char * id = NULL; + rdot decl = dot_pass_dataFlow_getDecl (node); + if (decl != NULL_DOT) + { + gcc_assert (RDOT_TYPE (decl) == D_VAR_DECL); + id = RDOT_IDENTIFIER_POINTER (RDOT_lhs_TT (decl)); + decls->push_back (decl); + + // push it into the current context... + rdot lookup = dot_pass_dataFlow_lookup (id); + if (lookup != NULL_DOT) + error ("Duplicate declaration of [%s] to [%s]", + id, RDOT_OPCODE_STR (lookup)); + else + gcc_assert (!dot_pass_dataFlow_pushDecl (decl, id)); } } + else + { + switch (RDOT_TYPE (node)) + { + case D_STRUCT_IF: + { + rdot sif = RDOT_lhs_TT (node); + rdot ses = RDOT_rhs_TT (node); + + dot_pass_dataFlowBlock_ (RDOT_rhs_TT (sif), decls); + if (ses != NULL_DOT) + dot_pass_dataFlowBlock_ (RDOT_lhs_TT (ses), decls); + } + break; + + case D_STRUCT_WHILE: + dot_pass_dataFlowBlock_ (RDOT_rhs_TT (node), decls); + break; + + case D_STRUCT_LOOP: + dot_pass_dataFlowBlock_ (RDOT_lhs_TT (node), decls); + break; + + case C_BREAK_STMT: + case C_CONT_STMT: + break; + + default: + error ("Unhandled data flow in block on [%s]\n", RDOT_OPCODE_STR (node)); + break; + } + } } } -// Seems to get all references for usage of all defined block declarations for type inference reasons -static void dot_pass_dataFlowBlock(rdot suite) { - std::vector<rdot> block_decls; - dot_pass_dataFlowBlock_(suite, &block_decls); - - // now we have all defined block declarations now need to get all - // references in their use if they have an undefined type. - std::vector<rdot>::iterator it; - for (it = block_decls.begin(); it != block_decls.end(); ++it) { - rdot decl = *it; - gcc_assert(RDOT_TYPE(decl) == D_VAR_DECL); - rdot idecl = RDOT_lhs_TT(decl); - const char* ident = RDOT_IDENTIFIER_POINTER(idecl); - if (RDOT_TYPE(RDOT_rhs_TT(decl)) == RTYPE_INFER) { - std::vector<rdot>* refs = dot_pass_getReferences(decl, suite); - if (refs->size() == 0) { - error("Unable to infer type of [%s] it looks to " - "be unused in this scope", - ident); - continue; - } - RDOT_rhs_TT(decl) = dot_pass_inferTheType(refs, ident); - if (RDOT_TYPE(RDOT_rhs_TT(decl)) == RTYPE_INFER) - error("Compiler was unable to infer the type for [%s]", ident); - delete refs; - } +static +void dot_pass_dataFlowBlock (rdot suite) +{ + std::vector<rdot> block_decls; + dot_pass_dataFlowBlock_ (suite, &block_decls); + + // now we have all defined block declarations now need to get all + // references in their use if they have an undefined type. + std::vector<rdot>::iterator it; + for (it = block_decls.begin (); it != block_decls.end (); ++it) + { + rdot decl = *it; + gcc_assert (RDOT_TYPE (decl) == D_VAR_DECL); + rdot idecl = RDOT_lhs_TT (decl); + const char * ident = RDOT_IDENTIFIER_POINTER (idecl); + if (RDOT_TYPE (RDOT_rhs_TT (decl)) == RTYPE_INFER) + { + std::vector<rdot> * refs = dot_pass_getReferences (decl, suite); + if (refs->size () == 0) + { + error ("Unable to infer type of [%s] it looks to " + "be unused in this scope", ident); + continue; + } + RDOT_rhs_TT (decl) = dot_pass_inferTheType (refs, ident); + if (RDOT_TYPE (RDOT_rhs_TT (decl)) == RTYPE_INFER) + error ("Compiler was unable to infer the type for [%s]", ident); + delete refs; + } } } -// Checks data flow for entire function - calls stuff leading to type inference, return values, etc. -static void dot_pass_dataFlowFunction(rdot node) { - const char* method_id = RDOT_IDENTIFIER_POINTER(RDOT_FIELD(node)); - rdot type = RDOT_FIELD2(node); - - // rust does not infer function types empty types are default void - // and parameters are synatically required to be typed - dot_pass_dataFlow_pushCtx(); - - // fill up the parameters here - rdot params; - for (params = RDOT_lhs_TT(node); params != NULL_DOT; - params = RDOT_CHAIN(params)) { - rdot pident = RDOT_lhs_TT(params); - rdot ptype = RDOT_rhs_TT(params); - - const char* cpid = RDOT_IDENTIFIER_POINTER(pident); - if (strcmp(cpid, "self") == 0) { - gcc_assert(impl_master != NULL_DOT); - rdot stid = RDOT_lhs_TT(impl_master); - ptype = rdot_build_decl1(RTYPE_USER_STRUCT, stid); - } - rdot vpdecl = rdot_build_varDecl(ptype, RDOT_qual(params), pident); - bool chk = dot_pass_dataFlow_pushDecl(vpdecl, - RDOT_IDENTIFIER_POINTER(pident)); - gcc_assert(chk == false); +static +void dot_pass_dataFlowFunction (rdot node) +{ + const char * method_id = RDOT_IDENTIFIER_POINTER (RDOT_FIELD (node)); + rdot type = RDOT_FIELD2 (node); + + // rust does not infer function types empty types are default void + // and parameters are synatically required to be typed + dot_pass_dataFlow_pushCtx (); + + // fill up the parameters here + rdot params; + for (params = RDOT_lhs_TT (node); params != NULL_DOT; + params = RDOT_CHAIN (params)) + { + rdot pident = RDOT_lhs_TT (params); + rdot ptype = RDOT_rhs_TT (params); + + const char * cpid = RDOT_IDENTIFIER_POINTER (pident); + if (strcmp (cpid, "self") == 0) + { + gcc_assert (impl_master != NULL_DOT); + rdot stid = RDOT_lhs_TT (impl_master); + ptype = rdot_build_decl1 (RTYPE_USER_STRUCT, stid); + } + rdot vpdecl = rdot_build_varDecl (ptype, RDOT_qual (params), pident); + bool chk = dot_pass_dataFlow_pushDecl (vpdecl, + RDOT_IDENTIFIER_POINTER (pident)); + gcc_assert (chk == false); } - rdot suite = RDOT_rhs_TT(node); - dot_pass_dataFlowBlock(suite); - - // now check the return type is correct - /* make sure its a valid type! */ - if (type != NULL) { - bool verify = verifyType(type); - if (verify == false) - error("unable to verify return type of %s [%s]\n", - method_id, - RDOT_OPCODE_STR(type)); - else { - std::vector<rdot> retvals; - dot_pass_dataFlowBlock_retvals(suite, &retvals); - - if (retvals.size() == 0) - error("Function [%s] does not seem to return anything!", method_id); - else { - rdot retype = dot_pass_inferTheType(&retvals, method_id); - if (RDOT_TYPE(retype) == RTYPE_INFER) - error("gcc rust was unable to verify the return type of [%s]", - method_id); - } - } + rdot suite = RDOT_rhs_TT (node); + dot_pass_dataFlowBlock (suite); + + // now check the return type is correct + /* make sure its a valid type! */ + if (type != NULL) + { + bool verify = verifyType (type); + if (verify == false) + error ("unable to verify return type of %s [%s]\n", + method_id, RDOT_OPCODE_STR (type)); + else + { + std::vector<rdot> retvals; + dot_pass_dataFlowBlock_retvals (suite, &retvals); + + if (retvals.size () == 0) + error ("Function [%s] does not seem to return anything!", method_id); + else + { + rdot retype = dot_pass_inferTheType (&retvals, method_id); + if (RDOT_TYPE (retype) == RTYPE_INFER) + error ("gcc rust was unable to verify the return type of [%s]", + method_id); + } + } } - dot_pass_dataFlow_popCtx(); + dot_pass_dataFlow_popCtx (); } -// Presumably top level entry for checking data flow - switches to method (function), struct, struct impl -static void dot_pass_dataFlowToplevel(rdot node) { - switch (RDOT_TYPE(node)) { - case D_STRUCT_METHOD: - dot_pass_dataFlowFunction(node); - break; - - /* need to dataflow the layout to check the types eventually */ - case D_STRUCT_TYPE: - break; - - case D_STRUCT_IMPL: { - // look up to make sure the impl name is available... - const char* implid = RDOT_IDENTIFIER_POINTER(RDOT_lhs_TT(node)); - rdot lookup = dot_pass_dataFlow_lookup(implid); - if (lookup == NULL_DOT) - error("impl [%s] does not reference a type in scope", implid); - else { - if (RDOT_TYPE(lookup) != D_STRUCT_TYPE) - error("impl [%s] does not reference a struct points to [%s]", - implid, - RDOT_OPCODE_STR(lookup)); - else { - RDOT_FIELD(lookup) = node; - impl_master = lookup; - rdot next; - for (next = RDOT_rhs_TT(node); next != NULL_DOT; - next = RDOT_CHAIN(next)) - dot_pass_dataFlowFunction(next); - impl_master = NULL_DOT; - } - } - } break; - - default: - error("Unable to dataflow %s\n", RDOT_OPCODE_STR(node)); - break; +static +void dot_pass_dataFlowToplevel (rdot node) +{ + switch (RDOT_TYPE (node)) + { + case D_STRUCT_METHOD: + dot_pass_dataFlowFunction (node); + break; + + /* need to dataflow the layout to check the types eventually */ + case D_STRUCT_TYPE: + break; + + case D_STRUCT_IMPL: + { + // look up to make sure the impl name is available... + const char * implid = RDOT_IDENTIFIER_POINTER (RDOT_lhs_TT (node)); + rdot lookup = dot_pass_dataFlow_lookup (implid); + if (lookup == NULL_DOT) + error ("impl [%s] does not reference a type in scope", implid); + else + { + if (RDOT_TYPE (lookup) != D_STRUCT_TYPE) + error ("impl [%s] does not reference a struct points to [%s]", + implid, RDOT_OPCODE_STR (lookup)); + else + { + RDOT_FIELD (lookup) = node; + impl_master = lookup; + rdot next; + for (next = RDOT_rhs_TT (node); next != NULL_DOT; + next = RDOT_CHAIN (next)) + dot_pass_dataFlowFunction (next); + impl_master = NULL_DOT; + } + } + } + break; + + default: + error ("Unable to dataflow %s\n", RDOT_OPCODE_STR (node)); + break; } } -// may be true top-level entry for checking data flow and inferring types - seems to call even top level function -vec<rdot, va_gc>* dot_pass_inferTypes(vec<rdot, va_gc>* decls) { - dot_pass_dataFlow_pushCtx(); - - rdot idtx = NULL_DOT; - size_t i; - for (i = 0; decls->iterate(i, &idtx); ++i) { - rdot node = idtx; - switch (RDOT_TYPE(node)) { - case D_STRUCT_METHOD: { - const char* id = RDOT_IDENTIFIER_POINTER(RDOT_FIELD(node)); - if (dot_pass_dataFlow_lookup(id)) - error("Duplicate declaration against this function [%s]\n", id); - else - dot_pass_dataFlow_pushDecl(node, id); - } break; - - case D_STRUCT_TYPE: { - const char* id = RDOT_IDENTIFIER_POINTER(RDOT_lhs_TT(node)); - if (dot_pass_dataFlow_lookup(id)) - error("Duplicate declaration against this type [%s]\n", id); - else - dot_pass_dataFlow_pushDecl(node, id); - } break; - - case D_STRUCT_IMPL: { - // look up to make sure the impl name is available... - const char* implid = RDOT_IDENTIFIER_POINTER(RDOT_lhs_TT(node)); - rdot lookup = dot_pass_dataFlow_lookup(implid); - if (lookup == NULL_DOT) - error("impl [%s] does not reference a type in scope", implid); - else { - if (RDOT_TYPE(lookup) != D_STRUCT_TYPE) - error("impl [%s] does not reference a struct points to [%s]", - implid, - RDOT_OPCODE_STR(lookup)); - else - RDOT_FIELD(lookup) = node; - } - } break; - - default: - break; - } +vec<rdot,va_gc> * dot_pass_inferTypes (vec<rdot,va_gc> * decls) +{ + dot_pass_dataFlow_pushCtx (); + + rdot idtx = NULL_DOT; + size_t i; + for (i = 0; decls->iterate (i, &idtx); ++i) + { + rdot node = idtx; + switch (RDOT_TYPE (node)) + { + case D_STRUCT_METHOD: + { + const char * id = RDOT_IDENTIFIER_POINTER (RDOT_FIELD (node)); + if (dot_pass_dataFlow_lookup (id)) + error ("Duplicate declaration against this function [%s]\n", id); + else + dot_pass_dataFlow_pushDecl (node, id); + } + break; + + case D_STRUCT_TYPE: + { + const char * id = RDOT_IDENTIFIER_POINTER (RDOT_lhs_TT (node)); + if (dot_pass_dataFlow_lookup (id)) + error ("Duplicate declaration against this type [%s]\n", id); + else + dot_pass_dataFlow_pushDecl (node, id); + } + break; + + case D_STRUCT_IMPL: + { + // look up to make sure the impl name is available... + const char * implid = RDOT_IDENTIFIER_POINTER (RDOT_lhs_TT (node)); + rdot lookup = dot_pass_dataFlow_lookup (implid); + if (lookup == NULL_DOT) + error ("impl [%s] does not reference a type in scope", implid); + else + { + if (RDOT_TYPE (lookup) != D_STRUCT_TYPE) + error ("impl [%s] does not reference a struct points to [%s]", + implid, RDOT_OPCODE_STR (lookup)); + else + RDOT_FIELD (lookup) = node; + } + } + break; + + default: + break; + } } - for (i = 0; decls->iterate(i, &idtx); ++i) - dot_pass_dataFlowToplevel(idtx); + for (i = 0; decls->iterate (i, &idtx); ++i) + dot_pass_dataFlowToplevel (idtx); - dot_pass_dataFlow_popCtx(); - return decls; + dot_pass_dataFlow_popCtx (); + return decls; } diff --git a/gcc/rust/old/rdot-generic-compiler.cc b/gcc/rust/old/rdot-generic-compiler.cc index 5e7672a..13b09a4 100644 --- a/gcc/rust/old/rdot-generic-compiler.cc +++ b/gcc/rust/old/rdot-generic-compiler.cc @@ -1,4 +1,3 @@ -// rdot-generic-compiler.cc - seems to convert rdot AST representation to GENERIC representation /* This file is part of GCC. GCC is free software; you can redistribute it and/or modify @@ -19,296 +18,337 @@ #define RUST_TMP "RUST_TMP" -static std::vector<std::map<std::string, tree>*> context; - -static tree dot_pass_genFndecl_Basic(location_t, const char*, tree); -static tree dot_pass_lookupCTU(const char*); -static std::vector<tree>* dot_pass_popContext(void); -static void dot_pass_pushContext(void); -static void dot_pass_genMethodProto(rdot); -static void dot_pass_compileSuite(rdot, tree*); - -#define RDOT_ALLOCA_MODIFIERS_DO(_X, _Y) \ - if (RDOT_MEM_MODIFIER(_Y)) \ - do { \ - gcc_assert(_X != error_mark_node); \ - std::vector<ALLOCA_>::reverse_iterator __rit; \ - for (__rit = RDOT_MEM_MODIFIER(_Y)->rbegin(); \ - __rit != RDOT_MEM_MODIFIER(_Y)->rend(); \ - ++__rit) { \ - switch (*__rit) { \ - case ALLOC_HEAP: \ - _X = dot_pass_heapify(_X, TREE_TYPE(_X), TYPE_SIZE_UNIT(TREE_TYPE(_X))); \ - break; \ - case ALLOC_REF: \ - _X = build_fold_addr_expr(_X); \ - break; \ - case ALLOC_DEREF: { \ - _X = build_fold_indirect_ref_loc(RDOT_LOCATION(_Y), \ - _X); \ - TREE_THIS_NOTRAP(_X) = 1; \ - } break; \ - } \ - } \ +static std::vector<std::map<std::string, tree> *> context; + +static tree dot_pass_genFndecl_Basic (location_t, const char *, tree); +static tree dot_pass_lookupCTU (const char *); +static std::vector<tree> * dot_pass_popContext (void); +static void dot_pass_pushContext (void); +static void dot_pass_genMethodProto (rdot); +static void dot_pass_compileSuite (rdot, tree *); + +#define RDOT_ALLOCA_MODIFIERS_DO(_X, _Y) \ + if (RDOT_MEM_MODIFIER (_Y)) \ + do { \ + gcc_assert (_X != error_mark_node); \ + std::vector<ALLOCA_>::reverse_iterator __rit; \ + for (__rit = RDOT_MEM_MODIFIER (_Y)->rbegin (); \ + __rit != RDOT_MEM_MODIFIER (_Y)->rend (); ++__rit) \ + { \ + switch (*__rit) \ + { \ + case ALLOC_HEAP: \ + _X = dot_pass_heapify (_X, TREE_TYPE (_X), \ + TYPE_SIZE_UNIT (TREE_TYPE (_X))); \ + break; \ + case ALLOC_REF: \ + _X = build_fold_addr_expr (_X); \ + break; \ + case ALLOC_DEREF: \ + { \ + _X = build_fold_indirect_ref_loc (RDOT_LOCATION (_Y), \ + _X); \ + TREE_THIS_NOTRAP (_X) = 1; \ + } \ + break; \ + } \ + } \ } while (0) /* NOTE: this isn't global in the sense of the generated code, This just makes it easier for expression compilation to access the return decl */ static tree global_retDecl; -static tree* current_function_block; +static tree * current_function_block; static bool global_retDecl_; static tree __impl_type_decl = error_mark_node; static std::vector<tree> __loopContexts; -#define dot_pass_rustToGccType(_x, _y) dot_pass_rustToGccType__(_x, _y, false, NULL) - -// seems to return only the end of a string val by removing everything before the final dot -static char* dot_pass_demangleImpl(const char* val) { - // has form of type.method_name - size_t i; - size_t last_dot = 0; - for (i = 0; i < strlen(val); ++i) { - if (val[i] == '.') - last_dot = i; +#define dot_pass_rustToGccType(_x, _y) dot_pass_rustToGccType__ (_x, _y, false, NULL) + +static +char * dot_pass_demangleImpl (const char * val) +{ + // has form of type.method_name + size_t i; + size_t last_dot = 0; + for (i = 0; i < strlen (val); ++i) + { + if (val [i] == '.') + last_dot = i; } - size_t bsize = (strlen(val) - last_dot) * sizeof(char); - char* buffer = (char*)xmalloc(bsize); - memset(buffer, 0, bsize); - strncpy(buffer, val + last_dot + 1, strlen(val) - last_dot); + size_t bsize = (strlen (val) - last_dot) * sizeof (char); + char * buffer = (char *) xmalloc (bsize); + memset (buffer, 0, bsize); + strncpy (buffer, val + last_dot + 1, strlen (val) - last_dot); - return buffer; + return buffer; } -// Seems to "mangle" val (a string parameter) by prepending "__rust_" to it -static char* dot_pass_mangle(const char* val) { - // just for now pre-append __rust_[id] will do ok for now - const char* stuff = "__rust_"; - size_t blen = (strlen(stuff) + strlen(val) + 1) * sizeof(char); - char* retval = (char*)xmalloc(blen); - memset(retval, 0, blen); - snprintf(retval, blen, "%s%s", stuff, val); - return retval; +static +char * dot_pass_mangle (const char * val) +{ + // just for now pre-append __rust_[id] will do ok for now + const char * stuff = "__rust_"; + size_t blen = (strlen (stuff) + strlen (val) + 1) * sizeof (char); + char * retval = (char *) xmalloc (blen); + memset (retval, 0, blen); + snprintf (retval, blen, "%s%s", stuff, val); + return retval; } -// Seems to convert "Rust type" (rdot type) to GCC GENERIC type -static tree dot_pass_rustToGccType__(rdot type, bool consty, bool rset, tree* record) { - tree retval = error_mark_node; - switch (RDOT_TYPE(type)) { - case RTYPE_INT: - retval = integer_type_node; - break; - - case D_STRUCT_TYPE: - case D_STRUCT_INIT: - case RTYPE_USER_STRUCT: { - const char* id = RDOT_IDENTIFIER_POINTER(RDOT_lhs_TT(type)); - retval = dot_pass_lookupCTU(id); - if (rset) - *record = retval; - - if (retval == error_mark_node) - error("Unable to find struct type [%s]\n", id); - } break; - - default: - error("Unable to figure out gcc type for [%s]\n", - RDOT_OPCODE_STR(type)); - break; +static +tree dot_pass_rustToGccType__ (rdot type, bool consty, bool rset, tree * record) +{ + tree retval = error_mark_node; + switch (RDOT_TYPE (type)) + { + case RTYPE_INT: + retval = integer_type_node; + break; + + case D_STRUCT_TYPE: + case D_STRUCT_INIT: + case RTYPE_USER_STRUCT: + { + const char * id = RDOT_IDENTIFIER_POINTER (RDOT_lhs_TT (type)); + retval = dot_pass_lookupCTU (id); + if (rset) + *record = retval; + + if (retval == error_mark_node) + error ("Unable to find struct type [%s]\n", id); + } + break; + + default: + error ("Unable to figure out gcc type for [%s]\n", + RDOT_OPCODE_STR (type)); + break; } - if (RDOT_MEM_MODIFIER(type)) { - std::vector<ALLOCA_>::reverse_iterator rit; - for (rit = RDOT_MEM_MODIFIER(type)->rbegin(); - rit != RDOT_MEM_MODIFIER(type)->rend(); - ++rit) { - switch (*rit) { - case ALLOC_REF: - case ALLOC_HEAP: - retval = build_pointer_type(retval); - break; - default: - fatal_error("cannot figure out modifier applied to type [%i]", *rit); - break; - } - } + if (RDOT_MEM_MODIFIER (type)) + { + std::vector<ALLOCA_>::reverse_iterator rit; + for (rit = RDOT_MEM_MODIFIER (type)->rbegin (); + rit != RDOT_MEM_MODIFIER (type)->rend (); ++rit) + { + switch (*rit) + { + case ALLOC_REF: + case ALLOC_HEAP: + retval = build_pointer_type (retval); + break; + default: + fatal_error ("cannot figure out modifier applied to type [%i]", *rit); + break; + } + } } - if (consty) - retval = build_qualified_type(retval, TYPE_QUAL_CONST); - return retval; + if (consty) + retval = build_qualified_type (retval, TYPE_QUAL_CONST); + return retval; } -// May build a function declaration? Add one to tree? Seems to have something to do with "struct functions" -static tree dot_pass_genFndecl_Basic(location_t loc, const char* ident, tree fntype) { - tree fndecl = build_decl(loc, FUNCTION_DECL, get_identifier(ident), fntype); - TREE_STATIC(fndecl) = 0; - TREE_USED(fndecl) = 1; - TREE_PUBLIC(fndecl) = 1; - - tree argslist = NULL_TREE; - DECL_ARGUMENTS(fndecl) = argslist; - - tree resdecl = build_decl(BUILTINS_LOCATION, RESULT_DECL, NULL_TREE, TREE_TYPE(fntype)); - DECL_CONTEXT(resdecl) = fndecl; - DECL_ARTIFICIAL(resdecl) = true; - DECL_IGNORED_P(resdecl) = true; - DECL_RESULT(fndecl) = resdecl; - - if (DECL_STRUCT_FUNCTION(fndecl) == NULL) - push_struct_function(fndecl); - else - push_cfun(DECL_STRUCT_FUNCTION(fndecl)); - return fndecl; +static +tree dot_pass_genFndecl_Basic (location_t loc, const char * ident, tree fntype) +{ + tree fndecl = build_decl (loc, FUNCTION_DECL, + get_identifier (ident), fntype); + TREE_STATIC (fndecl) = 0; + TREE_USED (fndecl) = 1; + TREE_PUBLIC (fndecl) = 1; + + tree argslist = NULL_TREE; + DECL_ARGUMENTS (fndecl) = argslist; + + tree resdecl = build_decl (BUILTINS_LOCATION, RESULT_DECL, + NULL_TREE, TREE_TYPE (fntype)); + DECL_CONTEXT (resdecl) = fndecl; + DECL_ARTIFICIAL (resdecl) = true; + DECL_IGNORED_P (resdecl) = true; + DECL_RESULT (fndecl) = resdecl; + + if (DECL_STRUCT_FUNCTION (fndecl) == NULL) + push_struct_function (fndecl); + else + push_cfun (DECL_STRUCT_FUNCTION (fndecl)); + return fndecl; } -// Creates a "tree" string from an inputted string -static tree dot_pass_generateCString(const char* str) { - tree index_type = build_index_type(size_int(strlen(str))); - tree const_char_type = build_qualified_type(char_type_node, TYPE_QUAL_CONST); - tree string_type = build_array_type(const_char_type, index_type); - string_type = build_variant_type_copy(string_type); +static +tree dot_pass_generateCString (const char * str) +{ + tree index_type = build_index_type (size_int (strlen (str))); + tree const_char_type = build_qualified_type (char_type_node, TYPE_QUAL_CONST); + tree string_type = build_array_type (const_char_type, index_type); + string_type = build_variant_type_copy (string_type); - TYPE_STRING_FLAG(string_type) = 1; - tree string_val = build_string(strlen(str), str); - TREE_TYPE(string_val) = string_type; + TYPE_STRING_FLAG (string_type) = 1; + tree string_val = build_string (strlen (str), str); + TREE_TYPE (string_val) = string_type; - return string_val; + return string_val; } -// Seems to lookup struct (by name id) in context map thing, and returns the corresponding tree -static tree dot_pass_lookupCTU(const char* id) { - tree retval = error_mark_node; - - std::vector<std::map<std::string, tree>*>::reverse_iterator it; - for (it = context.rbegin(); it != context.rend(); ++it) { - std::map<std::string, tree>* ctx = *it; - if (ctx->count(std::string(id)) > 0) { - retval = ctx->at(std::string(id)); - break; +static +tree dot_pass_lookupCTU (const char * id) +{ + tree retval = error_mark_node; + + std::vector<std::map<std::string, tree> *>::reverse_iterator it; + for (it = context.rbegin (); it != context.rend (); ++it) + { + std::map<std::string, tree> * ctx = *it; + if (ctx->count (std::string (id)) > 0) + { + retval = ctx->at (std::string (id)); + break; } } - return retval; + return retval; } -// seems to add a declaration tree thing to a map -static void dot_pass_pushDecl(const char* id, tree decl) { - tree test = dot_pass_lookupCTU(id); - if (test == error_mark_node) { - std::map<std::string, tree>* ctx = context.back(); - (*ctx)[std::string(id)] = decl; - } else - error("duplicate declaration of [%s]\n", id); +static +void dot_pass_pushDecl (const char * id, tree decl) +{ + tree test = dot_pass_lookupCTU (id); + if (test == error_mark_node) + { + std::map<std::string, tree> * ctx = context.back (); + (*ctx) [std::string (id)] = decl; + } + else + error ("duplicate declaration of [%s]\n", id); } -// Seems to build a heap allocation expression of size size static tree -dot_pass_rust_RR_alloc(tree size) { - tree fntype = build_function_type_list(ptr_type_node, - size_type_node, - NULL_TREE); - tree fndecl = build_decl(BUILTINS_LOCATION, FUNCTION_DECL, get_identifier("__rust_heap_alloc"), fntype); - tree restype = TREE_TYPE(fndecl); - tree resdecl = build_decl(BUILTINS_LOCATION, RESULT_DECL, NULL_TREE, restype); - DECL_CONTEXT(resdecl) = fndecl; - DECL_RESULT(fndecl) = resdecl; - DECL_EXTERNAL(fndecl) = 1; - TREE_PUBLIC(fndecl) = 1; - return build_call_expr(fndecl, 1, size); +dot_pass_rust_RR_alloc (tree size) +{ + tree fntype = build_function_type_list (ptr_type_node, + size_type_node, + NULL_TREE); + tree fndecl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL, + get_identifier ("__rust_heap_alloc"), + fntype); + tree restype = TREE_TYPE (fndecl); + tree resdecl = build_decl (BUILTINS_LOCATION, RESULT_DECL, NULL_TREE, + restype); + DECL_CONTEXT (resdecl) = fndecl; + DECL_RESULT (fndecl) = resdecl; + DECL_EXTERNAL (fndecl) = 1; + TREE_PUBLIC (fndecl) = 1; + return build_call_expr (fndecl, 1, size); } -// Appears to return a tree/declaration that heap allocation has occurred (or should occur?) static tree -dot_pass_heap_alloc(tree size, tree type) { - tree ptype = build_pointer_type(type); - tree heap_tmp = build_decl(UNKNOWN_LOCATION, VAR_DECL, create_tmp_var_name(RUST_TMP), ptype); - dot_pass_pushDecl(IDENTIFIER_POINTER(DECL_NAME(heap_tmp)), heap_tmp); - append_to_statement_list(fold_build2(MODIFY_EXPR, ptype, heap_tmp, dot_pass_rust_RR_alloc(size)), - current_function_block); - return heap_tmp; +dot_pass_heap_alloc (tree size, tree type) +{ + tree ptype = build_pointer_type (type); + tree heap_tmp = build_decl (UNKNOWN_LOCATION, VAR_DECL, + create_tmp_var_name (RUST_TMP), + ptype); + dot_pass_pushDecl (IDENTIFIER_POINTER (DECL_NAME (heap_tmp)), heap_tmp); + append_to_statement_list (fold_build2 (MODIFY_EXPR, ptype, heap_tmp, + dot_pass_rust_RR_alloc (size)), + current_function_block); + return heap_tmp; } -// Seems to do something related to heap allocation static tree -dot_pass_heapify(tree value, tree type, tree size) { - tree alloc = dot_pass_heap_alloc(size, type); - tree gmemcpy = builtin_decl_implicit(BUILT_IN_MEMCPY); - vec<tree, va_gc>* args; - vec_alloc(args, 0); - vec_safe_push(args, alloc); - vec_safe_push(args, build_fold_addr_expr(value)); - vec_safe_push(args, size); - append_to_statement_list(build_call_expr_loc_vec(UNKNOWN_LOCATION, gmemcpy, args), - current_function_block); - return alloc; +dot_pass_heapify (tree value, tree type, tree size) +{ + tree alloc = dot_pass_heap_alloc (size, type); + tree gmemcpy = builtin_decl_implicit (BUILT_IN_MEMCPY); + vec<tree,va_gc> * args; + vec_alloc (args, 0); + vec_safe_push (args, alloc); + vec_safe_push (args, build_fold_addr_expr (value)); + vec_safe_push (args, size); + append_to_statement_list (build_call_expr_loc_vec (UNKNOWN_LOCATION, gmemcpy, args), + current_function_block); + return alloc; } -// Seems to build an integer tree node from rdot decl -static tree dot_pass_genScalar(rdot decl) { - tree retval = error_mark_node; - gcc_assert(RDOT_TYPE(decl) == D_PRIMITIVE); - gcc_assert(RDOT_lhs_T(decl) == D_TD_COM); - - switch (RDOT_lhs_TC(decl).T) { - case D_T_INTEGER: - retval = build_int_cst(integer_type_node, RDOT_lhs_TC(decl).o.integer); - break; - - default: - fatal_error("invalid scalar type %s!\n", RDOT_CODE_STR(RDOT_lhs_TC(decl).T)); - break; +static +tree dot_pass_genScalar (rdot decl) +{ + tree retval = error_mark_node; + gcc_assert (RDOT_TYPE (decl) == D_PRIMITIVE); + gcc_assert (RDOT_lhs_T (decl) == D_TD_COM); + + switch (RDOT_lhs_TC (decl).T) + { + case D_T_INTEGER: + retval = build_int_cst (integer_type_node, RDOT_lhs_TC (decl).o.integer); + break; + + default: + fatal_error ("invalid scalar type %s!\n", RDOT_CODE_STR (RDOT_lhs_TC (decl).T)); + break; } - return retval; + return retval; } -// Presumably turns a function calls into tree nodes -static tree dot_pass_genifyCall(tree mfndecl, vec<tree, va_gc>* arguments) { - tree retval = error_mark_node; - if (TREE_CODE(mfndecl) == FUNCTION_DECL) { - // size_t len = arguments->length (); - // size_t lparms = 0; - // tree types = TYPE_ARG_TYPES (mfndecl); - - /* really need to check the calling types and number of arguments */ - retval = build_call_expr_loc_vec(UNKNOWN_LOCATION, mfndecl, arguments); - } else - error("trying to call a function which isn't callable [%s]", - IDENTIFIER_POINTER(mfndecl)); - return retval; +static +tree dot_pass_genifyCall (tree mfndecl, vec<tree,va_gc> * arguments) +{ + tree retval = error_mark_node; + if (TREE_CODE (mfndecl) == FUNCTION_DECL) + { + // size_t len = arguments->length (); + // size_t lparms = 0; + // tree types = TYPE_ARG_TYPES (mfndecl); + + /* really need to check the calling types and number of arguments */ + retval = build_call_expr_loc_vec (UNKNOWN_LOCATION, mfndecl, arguments); + } + else + error ("trying to call a function which isn't callable [%s]", + IDENTIFIER_POINTER (mfndecl)); + return retval; } -// Seems to be an entry point for lowering an rdot dot expression - switches between their types and stuff -static tree dot_pass_lowerExpr(rdot dot, tree* block) { - tree retval = error_mark_node; - switch (RDOT_TYPE(dot)) { - case D_PRIMITIVE: { - retval = dot_pass_genScalar(dot); - RDOT_ALLOCA_MODIFIERS_DO(retval, dot); - } break; - - case D_IDENTIFIER: { - const char* id = RDOT_IDENTIFIER_POINTER(dot); - retval = dot_pass_lookupCTU(id); - if (retval == error_mark_node) - fatal_error("no such id [%s] in scope", id); - RDOT_ALLOCA_MODIFIERS_DO(retval, dot); - } break; - - case D_STRUCT_INIT: { - // need to go fetch the type and build the constructor... - size_t count = 0; - tree root_type = error_mark_node; - dot_pass_rustToGccType__(dot, false, true, &root_type); - gcc_assert(root_type != error_mark_node); - tree fields = TYPE_FIELDS(root_type); - - tree fnext; - for (fnext = fields; fnext != NULL_TREE; fnext = DECL_CHAIN(fnext)) - count++; - fnext = error_mark_node; - - vec<constructor_elt, va_gc>* init; - vec_alloc(init, count + 1); - - /* +static +tree dot_pass_lowerExpr (rdot dot, tree * block) +{ + tree retval = error_mark_node; + switch (RDOT_TYPE (dot)) + { + case D_PRIMITIVE: + { + retval = dot_pass_genScalar (dot); + RDOT_ALLOCA_MODIFIERS_DO (retval, dot); + } + break; + + case D_IDENTIFIER: + { + const char * id = RDOT_IDENTIFIER_POINTER (dot); + retval = dot_pass_lookupCTU (id); + if (retval == error_mark_node) + fatal_error ("no such id [%s] in scope", id); + RDOT_ALLOCA_MODIFIERS_DO (retval, dot); + } + break; + + case D_STRUCT_INIT: + { + // need to go fetch the type and build the constructor... + size_t count = 0; + tree root_type = error_mark_node; + dot_pass_rustToGccType__ (dot, false, true, &root_type); + gcc_assert (root_type != error_mark_node); + tree fields = TYPE_FIELDS (root_type); + + tree fnext; + for (fnext = fields; fnext != NULL_TREE; fnext = DECL_CHAIN (fnext)) + count++; + fnext = error_mark_node; + + vec<constructor_elt, va_gc> *init; + vec_alloc (init, count + 1); + + /* FIXME this is all very buggy: eg: struct test { @@ -319,711 +359,844 @@ static tree dot_pass_lowerExpr(rdot dot, tree* block) { initilize with test { x: 1, x: 1} will pass but it should fail needs more validation at dataflow level and here */ - tree rid = create_tmp_var_name(RUST_TMP); - retval = build_decl(RDOT_LOCATION(dot), VAR_DECL, rid, root_type); - dot_pass_pushDecl(IDENTIFIER_POINTER(rid), retval); - - constructor_elt empty = { NULL, NULL }; - rdot next; - size_t valid = 0; - for (next = RDOT_rhs_TT(dot); next != NULL_DOT; next = RDOT_CHAIN(next)) { - constructor_elt* elt = init->quick_push(empty); - gcc_assert(RDOT_TYPE(next) == D_STRUCT_PARAM); - bool found = false; - for (fnext = fields; fnext != NULL_TREE; fnext = DECL_CHAIN(fnext)) { - const char* pid = IDENTIFIER_POINTER(DECL_NAME(fnext)); - const char* sid = RDOT_IDENTIFIER_POINTER(RDOT_lhs_TT(next)); - if (strcmp(pid, sid) == 0) { - found = true; - break; - } - } - if (!found) { - error("Unable to find field [%s] in struct [%s]", - IDENTIFIER_POINTER(TYPE_NAME(root_type)), - RDOT_IDENTIFIER_POINTER(RDOT_lhs_TT(next))); - break; - } - - elt->index = fnext; - elt->value = fold_convert(TREE_TYPE(fnext), - dot_pass_lowerExpr(RDOT_rhs_TT(next), - block)); - valid++; - } - if (valid == count) { - tree cons = build_constructor(root_type, init); - append_to_statement_list(fold_build2_loc(RDOT_LOCATION(dot), INIT_EXPR, root_type, retval, cons), block); - } else { - fatal_error("Cannot initilize struct required [%lu] fields got [%lu]", - valid, - count); - // TODO better diagnostic make a map of the initilized so - // we can display the un initilized to the user - } - RDOT_ALLOCA_MODIFIERS_DO(retval, dot); - } break; - - case D_CALL_EXPR: { - const char* fnid = RDOT_IDENTIFIER_POINTER(RDOT_lhs_TT(dot)); - rdot ptr; - vec<tree, va_gc>* arguments; - vec_alloc(arguments, 0); - for (ptr = RDOT_rhs_TT(dot); ptr != NULL_DOT; - ptr = RDOT_CHAIN(ptr)) - vec_safe_push(arguments, dot_pass_lowerExpr(ptr, block)); - /* lookup the function prototype */ - tree lookup = dot_pass_lookupCTU(fnid); - if (lookup != error_mark_node) - retval = dot_pass_genifyCall(lookup, arguments); - else { - fatal_error("Unable to find callable %s\n", fnid); - retval = error_mark_node; - } - RDOT_ALLOCA_MODIFIERS_DO(retval, dot); - } break; - - case D_ATTRIB_REF: { - rdot lhs = RDOT_lhs_TT(dot); - rdot rhs = RDOT_rhs_TT(dot); - - tree lookup = dot_pass_lowerExpr(lhs, block); - switch (RDOT_TYPE(rhs)) { - case D_CALL_EXPR: { - rdot crid = RDOT_lhs_TT(rhs); - const char* rlookup = RDOT_IDENTIFIER_POINTER(crid); - tree tid = TYPE_NAME(TREE_TYPE(lookup)); - const char* ctid = IDENTIFIER_POINTER(tid); - - tree type_decl = dot_pass_lookupCTU(ctid); - // just to be sure but we will have already error'd at this point.. - gcc_assert(type_decl != error_mark_node); - - tree mths = TYPE_METHODS(type_decl); - tree next; - for (next = mths; next != NULL_TREE; next = DECL_CHAIN(next)) { - const char* mid = IDENTIFIER_POINTER(DECL_NAME(next)); - char* demangle = dot_pass_demangleImpl(mid); - if (strcmp(rlookup, demangle) == 0) { - vec<tree, va_gc>* cargs; - vec_alloc(cargs, 0); - vec_safe_push(cargs, lookup); - - rdot pnext; - for (pnext = RDOT_rhs_TT(rhs); pnext != NULL_DOT; - pnext = RDOT_CHAIN(pnext)) - vec_safe_push(cargs, dot_pass_lowerExpr(pnext, block)); - - retval = dot_pass_genifyCall(next, cargs); - break; - } - } - } break; - - case D_IDENTIFIER: { - const char* rlookup = RDOT_IDENTIFIER_POINTER(rhs); - tree fields = TYPE_FIELDS(TREE_TYPE(lookup)); - tree next; - for (next = fields; next != NULL_TREE; next = DECL_CHAIN(next)) { - const char* fid = IDENTIFIER_POINTER(DECL_NAME(next)); - if (strcmp(rlookup, fid) == 0) { - /* no idea why we need build3 here but build2 fails... */ - retval = build3(COMPONENT_REF, TREE_TYPE(next), lookup, next, NULL_TREE); - break; - } - } - } break; - - default: - fatal_error("Really don't know what happened here!\n"); - break; - } - } break; - - case D_MODIFY_EXPR: { - tree assignment = dot_pass_lowerExpr(RDOT_rhs_TT(dot), block); - tree decl = dot_pass_lowerExpr(RDOT_lhs_TT(dot), block); - retval = build2(MODIFY_EXPR, TREE_TYPE(decl), decl, assignment); - } break; - - case D_ADD_EXPR: { - rdot lhs = RDOT_lhs_TT(dot); - rdot rhs = RDOT_rhs_TT(dot); - - tree xlhs = dot_pass_lowerExpr(lhs, block); - tree xrhs = dot_pass_lowerExpr(rhs, block); - - retval = build2(PLUS_EXPR, TREE_TYPE(xlhs), xlhs, xrhs); - } break; - - case D_MINUS_EXPR: { - rdot lhs = RDOT_lhs_TT(dot); - rdot rhs = RDOT_rhs_TT(dot); - - tree xlhs = dot_pass_lowerExpr(lhs, block); - tree xrhs = dot_pass_lowerExpr(rhs, block); - - retval = build2(MINUS_EXPR, TREE_TYPE(xlhs), xlhs, xrhs); - } break; - - case D_MULT_EXPR: { - rdot lhs = RDOT_lhs_TT(dot); - rdot rhs = RDOT_rhs_TT(dot); - - tree xlhs = dot_pass_lowerExpr(lhs, block); - tree xrhs = dot_pass_lowerExpr(rhs, block); - - retval = build2(MULT_EXPR, TREE_TYPE(xlhs), xlhs, xrhs); - } break; - - case D_LESS_EQ_EXPR: { - rdot lhs = RDOT_lhs_TT(dot); - rdot rhs = RDOT_rhs_TT(dot); - - tree xlhs = dot_pass_lowerExpr(lhs, block); - tree xrhs = dot_pass_lowerExpr(rhs, block); - - retval = build2(LE_EXPR, TREE_TYPE(xlhs), xlhs, xrhs); - } break; - - case D_EQ_EQ_EXPR: { - rdot lhs = RDOT_lhs_TT(dot); - rdot rhs = RDOT_rhs_TT(dot); - - tree xlhs = dot_pass_lowerExpr(lhs, block); - tree xrhs = dot_pass_lowerExpr(rhs, block); - - retval = build2(EQ_EXPR, TREE_TYPE(xlhs), xlhs, xrhs); - } break; - - case D_VAR_DECL: { - const char* varID = RDOT_IDENTIFIER_POINTER(RDOT_lhs_TT(dot)); - bool consty = RDOT_qual(dot); - tree gcc_type = dot_pass_rustToGccType(RDOT_rhs_TT(dot), consty); - tree decl = build_decl(RDOT_LOCATION(dot), - VAR_DECL, - get_identifier(varID), - gcc_type); - if (dot_pass_lookupCTU(varID) == error_mark_node) - dot_pass_pushDecl(varID, decl); - retval = decl; - } break; - - case D_ACC_EXPR: { - rdot impl = RDOT_lhs_TT(dot); - char* implid = RDOT_IDENTIFIER_POINTER(impl); - printf("implid = %s\n", implid); - } break; - - default: - error("unhandled binary operation type [%s]!\n", RDOT_OPCODE_STR(dot)); - break; + tree rid = create_tmp_var_name (RUST_TMP); + retval = build_decl (RDOT_LOCATION (dot), VAR_DECL, rid, root_type); + dot_pass_pushDecl (IDENTIFIER_POINTER (rid), retval); + + constructor_elt empty = {NULL, NULL}; + rdot next; + size_t valid = 0; + for (next = RDOT_rhs_TT (dot); next != NULL_DOT; next = RDOT_CHAIN (next)) + { + constructor_elt* elt = init->quick_push (empty); + gcc_assert (RDOT_TYPE (next) == D_STRUCT_PARAM); + bool found = false; + for (fnext = fields; fnext != NULL_TREE; fnext = DECL_CHAIN (fnext)) + { + const char * pid = IDENTIFIER_POINTER (DECL_NAME (fnext)); + const char * sid = RDOT_IDENTIFIER_POINTER (RDOT_lhs_TT (next)); + if (strcmp (pid, sid) == 0) + { + found = true; + break; + } + } + if (!found) + { + error ("Unable to find field [%s] in struct [%s]", + IDENTIFIER_POINTER (TYPE_NAME (root_type)), + RDOT_IDENTIFIER_POINTER (RDOT_lhs_TT (next))); + break; + } + + elt->index = fnext; + elt->value = fold_convert (TREE_TYPE (fnext), + dot_pass_lowerExpr (RDOT_rhs_TT (next), + block)); + valid++; + } + if (valid == count) + { + tree cons = build_constructor (root_type, init); + append_to_statement_list (fold_build2_loc (RDOT_LOCATION (dot), INIT_EXPR, + root_type, retval, cons), block); + } + else + { + fatal_error ("Cannot initilize struct required [%lu] fields got [%lu]", + valid, count); + // TODO better diagnostic make a map of the initilized so + // we can display the un initilized to the user + } + RDOT_ALLOCA_MODIFIERS_DO (retval, dot); + } + break; + + case D_CALL_EXPR: + { + const char * fnid = RDOT_IDENTIFIER_POINTER (RDOT_lhs_TT (dot)); + rdot ptr; + vec<tree,va_gc> * arguments; + vec_alloc (arguments, 0); + for (ptr = RDOT_rhs_TT (dot); ptr != NULL_DOT; + ptr = RDOT_CHAIN (ptr)) + vec_safe_push (arguments, dot_pass_lowerExpr (ptr, block)); + /* lookup the function prototype */ + tree lookup = dot_pass_lookupCTU (fnid); + if (lookup != error_mark_node) + retval = dot_pass_genifyCall (lookup, arguments); + else + { + fatal_error ("Unable to find callable %s\n", fnid); + retval = error_mark_node; + } + RDOT_ALLOCA_MODIFIERS_DO (retval, dot); + } + break; + + case D_ATTRIB_REF: + { + rdot lhs = RDOT_lhs_TT (dot); + rdot rhs = RDOT_rhs_TT (dot); + + tree lookup = dot_pass_lowerExpr (lhs, block); + switch (RDOT_TYPE (rhs)) + { + case D_CALL_EXPR: + { + rdot crid = RDOT_lhs_TT (rhs); + const char * rlookup = RDOT_IDENTIFIER_POINTER (crid); + tree tid = TYPE_NAME (TREE_TYPE (lookup)); + const char * ctid = IDENTIFIER_POINTER (tid); + + tree type_decl = dot_pass_lookupCTU (ctid); + // just to be sure but we will have already error'd at this point.. + gcc_assert (type_decl != error_mark_node); + + tree mths = TYPE_METHODS (type_decl); + tree next; + for (next = mths; next != NULL_TREE; next = DECL_CHAIN (next)) + { + const char * mid = IDENTIFIER_POINTER (DECL_NAME (next)); + char * demangle = dot_pass_demangleImpl (mid); + if (strcmp (rlookup, demangle) == 0) + { + vec<tree,va_gc> * cargs; + vec_alloc (cargs, 0); + vec_safe_push (cargs, lookup); + + rdot pnext; + for (pnext = RDOT_rhs_TT (rhs); pnext != NULL_DOT; + pnext = RDOT_CHAIN (pnext)) + vec_safe_push (cargs, dot_pass_lowerExpr (pnext, block)); + + retval = dot_pass_genifyCall (next, cargs); + break; + } + } + } + break; + + case D_IDENTIFIER: + { + const char * rlookup = RDOT_IDENTIFIER_POINTER (rhs); + tree fields = TYPE_FIELDS (TREE_TYPE (lookup)); + tree next; + for (next = fields; next != NULL_TREE; next = DECL_CHAIN (next)) + { + const char * fid = IDENTIFIER_POINTER (DECL_NAME (next)); + if (strcmp (rlookup, fid) == 0) + { + /* no idea why we need build3 here but build2 fails... */ + retval = build3 (COMPONENT_REF, TREE_TYPE (next), + lookup, next, NULL_TREE); + break; + } + } + } + break; + + default: + fatal_error ("Really don't know what happened here!\n"); + break; + } + } + break; + + case D_MODIFY_EXPR: + { + tree assignment = dot_pass_lowerExpr (RDOT_rhs_TT (dot), block); + tree decl = dot_pass_lowerExpr (RDOT_lhs_TT (dot), block); + retval = build2 (MODIFY_EXPR, TREE_TYPE (decl), decl, assignment); + } + break; + + case D_ADD_EXPR: + { + rdot lhs = RDOT_lhs_TT (dot); + rdot rhs = RDOT_rhs_TT (dot); + + tree xlhs = dot_pass_lowerExpr (lhs, block); + tree xrhs = dot_pass_lowerExpr (rhs, block); + + retval = build2 (PLUS_EXPR, TREE_TYPE (xlhs), + xlhs, xrhs); + } + break; + + case D_MINUS_EXPR: + { + rdot lhs = RDOT_lhs_TT (dot); + rdot rhs = RDOT_rhs_TT (dot); + + tree xlhs = dot_pass_lowerExpr (lhs, block); + tree xrhs = dot_pass_lowerExpr (rhs, block); + + retval = build2 (MINUS_EXPR, TREE_TYPE (xlhs), + xlhs, xrhs); + } + break; + + case D_MULT_EXPR: + { + rdot lhs = RDOT_lhs_TT (dot); + rdot rhs = RDOT_rhs_TT (dot); + + tree xlhs = dot_pass_lowerExpr (lhs, block); + tree xrhs = dot_pass_lowerExpr (rhs, block); + + retval = build2 (MULT_EXPR, TREE_TYPE (xlhs), + xlhs, xrhs); + } + break; + + case D_LESS_EQ_EXPR: + { + rdot lhs = RDOT_lhs_TT (dot); + rdot rhs = RDOT_rhs_TT (dot); + + tree xlhs = dot_pass_lowerExpr (lhs, block); + tree xrhs = dot_pass_lowerExpr (rhs, block); + + retval = build2 (LE_EXPR, TREE_TYPE (xlhs), + xlhs, xrhs); + } + break; + + case D_EQ_EQ_EXPR: + { + rdot lhs = RDOT_lhs_TT (dot); + rdot rhs = RDOT_rhs_TT (dot); + + tree xlhs = dot_pass_lowerExpr (lhs, block); + tree xrhs = dot_pass_lowerExpr (rhs, block); + + retval = build2 (EQ_EXPR, TREE_TYPE (xlhs), + xlhs, xrhs); + } + break; + + case D_VAR_DECL: + { + const char * varID = RDOT_IDENTIFIER_POINTER (RDOT_lhs_TT (dot)); + bool consty = RDOT_qual (dot); + tree gcc_type = dot_pass_rustToGccType (RDOT_rhs_TT (dot), consty); + tree decl = build_decl (RDOT_LOCATION (dot), + VAR_DECL, get_identifier (varID), + gcc_type); + if (dot_pass_lookupCTU (varID) == error_mark_node) + dot_pass_pushDecl (varID, decl); + retval = decl; + } + break; + + case D_ACC_EXPR: + { + rdot impl = RDOT_lhs_TT (dot); + char * implid = RDOT_IDENTIFIER_POINTER (impl); + printf ("implid = %s\n", implid); + } + break; + + default: + error ("unhandled binary operation type [%s]!\n", RDOT_OPCODE_STR (dot)); + break; } - if (DOT_RETVAL(dot)) { - if (global_retDecl != error_mark_node) { - tree retass = fold_build2_loc(RDOT_LOCATION(dot), - MODIFY_EXPR, - TREE_TYPE(global_retDecl), - global_retDecl, - retval); - append_to_statement_list(retass, block); - global_retDecl_ = true; - retval = global_retDecl; + if (DOT_RETVAL (dot)) + { + if (global_retDecl != error_mark_node) + { + tree retass = fold_build2_loc (RDOT_LOCATION (dot), + MODIFY_EXPR, TREE_TYPE (global_retDecl), + global_retDecl, retval); + append_to_statement_list (retass, block); + global_retDecl_ = true; + retval = global_retDecl; } } - return retval; + return retval; } -// Seems to be an entry point for lowering conditionals (if stmnts) and adding them to the statement list -static void dot_pass_compileCond(rdot node, tree* block) { - rdot ifblock = RDOT_lhs_TT(node); - rdot elseblock = RDOT_rhs_TT(node); - - tree endif_label_decl = build_decl(BUILTINS_LOCATION, LABEL_DECL, create_tmp_var_name("ENDIF"), void_type_node); - tree endif_label_expr = fold_build1_loc(BUILTINS_LOCATION, LABEL_EXPR, void_type_node, endif_label_decl); - DECL_CONTEXT(endif_label_decl) = current_function_decl; - - tree else_label_expr = error_mark_node; - tree else_label_decl = error_mark_node; - if (elseblock != NULL_DOT) { - else_label_decl = build_decl(BUILTINS_LOCATION, LABEL_DECL, create_tmp_var_name("ELSE"), void_type_node); - else_label_expr = fold_build1_loc(BUILTINS_LOCATION, LABEL_EXPR, void_type_node, else_label_decl); - DECL_CONTEXT(else_label_decl) = current_function_decl; - } else { - else_label_expr = endif_label_expr; - else_label_decl = endif_label_decl; +static +void dot_pass_compileCond (rdot node, tree * block) +{ + rdot ifblock = RDOT_lhs_TT (node); + rdot elseblock = RDOT_rhs_TT (node); + + tree endif_label_decl = build_decl (BUILTINS_LOCATION, LABEL_DECL, + create_tmp_var_name ("ENDIF"), + void_type_node); + tree endif_label_expr = fold_build1_loc (BUILTINS_LOCATION, LABEL_EXPR, + void_type_node, endif_label_decl); + DECL_CONTEXT (endif_label_decl) = current_function_decl; + + tree else_label_expr = error_mark_node; + tree else_label_decl = error_mark_node; + if (elseblock != NULL_DOT) + { + else_label_decl = build_decl (BUILTINS_LOCATION, LABEL_DECL, + create_tmp_var_name ("ELSE"), + void_type_node); + else_label_expr = fold_build1_loc (BUILTINS_LOCATION, LABEL_EXPR, + void_type_node, else_label_decl); + DECL_CONTEXT (else_label_decl) = current_function_decl; + } + else + { + else_label_expr = endif_label_expr; + else_label_decl = endif_label_decl; } - tree cond = dot_pass_lowerExpr(RDOT_lhs_TT(ifblock), block); - tree conditional = build3_loc(RDOT_LOCATION(node), COND_EXPR, void_type_node, cond, NULL_TREE, build1(GOTO_EXPR, void_type_node, else_label_decl)); - - append_to_statement_list(conditional, block); - dot_pass_compileSuite(RDOT_rhs_TT(ifblock), block); - append_to_statement_list(build1(GOTO_EXPR, void_type_node, endif_label_decl), - block); - if (elseblock) { - append_to_statement_list(else_label_expr, block); - dot_pass_compileSuite(RDOT_lhs_TT(elseblock), block); - append_to_statement_list(endif_label_expr, block); - } else - append_to_statement_list(endif_label_expr, block); + tree cond = dot_pass_lowerExpr (RDOT_lhs_TT (ifblock), block); + tree conditional = build3_loc (RDOT_LOCATION (node), COND_EXPR, void_type_node, + cond, + NULL_TREE, + build1 (GOTO_EXPR, void_type_node, else_label_decl)); + + append_to_statement_list (conditional, block); + dot_pass_compileSuite (RDOT_rhs_TT (ifblock), block); + append_to_statement_list (build1 (GOTO_EXPR, void_type_node, endif_label_decl), + block); + if (elseblock) + { + append_to_statement_list (else_label_expr, block); + dot_pass_compileSuite (RDOT_lhs_TT (elseblock), block); + append_to_statement_list (endif_label_expr, block); + } + else + append_to_statement_list (endif_label_expr, block); } -// Seems to be an entry point for lowering breaks (as in loops) and adding them to a statement list -static void dot_pass_compileBreak(rdot node, tree* block) { - size_t lts = __loopContexts.size(); - if (lts > 0) - append_to_statement_list(fold_build1_loc(RDOT_LOCATION(node), GOTO_EXPR, void_type_node, __loopContexts.back()), - block); - else - error("break outside of loop context"); +static +void dot_pass_compileBreak (rdot node, tree * block) +{ + size_t lts = __loopContexts.size (); + if (lts > 0) + append_to_statement_list (fold_build1_loc (RDOT_LOCATION (node), GOTO_EXPR, + void_type_node, + __loopContexts.back ()), + block); + else + error ("break outside of loop context"); } -// Seems to be an entry point for lowering loops and appending them to statement list - possibly Rust type loop? -static void dot_pass_compileLoop(rdot node, tree* block) { - tree start_label_decl = build_decl(BUILTINS_LOCATION, LABEL_DECL, create_tmp_var_name("START"), void_type_node); - tree start_label_expr = fold_build1_loc(BUILTINS_LOCATION, LABEL_EXPR, void_type_node, start_label_decl); - DECL_CONTEXT(start_label_decl) = current_function_decl; - - tree end_label_decl = build_decl(BUILTINS_LOCATION, LABEL_DECL, create_tmp_var_name("END"), void_type_node); - tree end_label_expr = fold_build1_loc(BUILTINS_LOCATION, LABEL_EXPR, void_type_node, end_label_decl); - DECL_CONTEXT(end_label_decl) = current_function_decl; - __loopContexts.push_back(end_label_decl); - - /* -- -- -- */ - append_to_statement_list(start_label_expr, block); - - dot_pass_compileSuite(RDOT_lhs_TT(node), block); - append_to_statement_list(build1(GOTO_EXPR, void_type_node, start_label_decl), block); - append_to_statement_list(end_label_expr, block); - - __loopContexts.pop_back(); +static +void dot_pass_compileLoop (rdot node, tree * block) +{ + tree start_label_decl = build_decl (BUILTINS_LOCATION, LABEL_DECL, + create_tmp_var_name ("START"), + void_type_node); + tree start_label_expr = fold_build1_loc (BUILTINS_LOCATION, LABEL_EXPR, + void_type_node, start_label_decl); + DECL_CONTEXT (start_label_decl) = current_function_decl; + + tree end_label_decl = build_decl (BUILTINS_LOCATION, LABEL_DECL, + create_tmp_var_name ("END"), + void_type_node); + tree end_label_expr = fold_build1_loc (BUILTINS_LOCATION, LABEL_EXPR, + void_type_node, end_label_decl); + DECL_CONTEXT (end_label_decl) = current_function_decl; + __loopContexts.push_back (end_label_decl); + + /* -- -- -- */ + append_to_statement_list (start_label_expr, block); + + dot_pass_compileSuite (RDOT_lhs_TT (node), block); + append_to_statement_list (build1 (GOTO_EXPR, void_type_node, start_label_decl), block); + append_to_statement_list (end_label_expr, block); + + __loopContexts.pop_back (); + } -// Seems to be an entry point for lowering while loops and adding them to statement list -static void dot_pass_compileWhile(rdot node, tree* block) { - rdot condition = RDOT_lhs_TT(node); - rdot suite = RDOT_rhs_TT(node); - - tree start_label_decl = build_decl(BUILTINS_LOCATION, LABEL_DECL, create_tmp_var_name("START"), void_type_node); - tree start_label_expr = fold_build1_loc(BUILTINS_LOCATION, LABEL_EXPR, void_type_node, start_label_decl); - DECL_CONTEXT(start_label_decl) = current_function_decl; - - tree end_label_decl = build_decl(BUILTINS_LOCATION, LABEL_DECL, create_tmp_var_name("END"), void_type_node); - tree end_label_expr = fold_build1_loc(BUILTINS_LOCATION, LABEL_EXPR, void_type_node, end_label_decl); - DECL_CONTEXT(end_label_decl) = current_function_decl; - __loopContexts.push_back(end_label_decl); - - /* -- -- -- */ - append_to_statement_list(start_label_expr, block); - - tree cond = dot_pass_lowerExpr(condition, block); - tree conditional = build3_loc(RDOT_LOCATION(node), COND_EXPR, void_type_node, cond, NULL_TREE, build1(GOTO_EXPR, void_type_node, end_label_decl)); - append_to_statement_list(conditional, block); - dot_pass_compileSuite(suite, block); - append_to_statement_list(build1(GOTO_EXPR, void_type_node, start_label_decl), block); - append_to_statement_list(end_label_expr, block); - - __loopContexts.pop_back(); +static +void dot_pass_compileWhile (rdot node, tree * block) +{ + rdot condition = RDOT_lhs_TT (node); + rdot suite = RDOT_rhs_TT (node); + + tree start_label_decl = build_decl (BUILTINS_LOCATION, LABEL_DECL, + create_tmp_var_name ("START"), + void_type_node); + tree start_label_expr = fold_build1_loc (BUILTINS_LOCATION, LABEL_EXPR, + void_type_node, start_label_decl); + DECL_CONTEXT (start_label_decl) = current_function_decl; + + tree end_label_decl = build_decl (BUILTINS_LOCATION, LABEL_DECL, + create_tmp_var_name ("END"), + void_type_node); + tree end_label_expr = fold_build1_loc (BUILTINS_LOCATION, LABEL_EXPR, + void_type_node, end_label_decl); + DECL_CONTEXT (end_label_decl) = current_function_decl; + __loopContexts.push_back (end_label_decl); + + /* -- -- -- */ + append_to_statement_list (start_label_expr, block); + + tree cond = dot_pass_lowerExpr (condition, block); + tree conditional = build3_loc (RDOT_LOCATION (node), COND_EXPR, void_type_node, + cond, NULL_TREE, + build1 (GOTO_EXPR, void_type_node, end_label_decl)); + append_to_statement_list (conditional, block); + dot_pass_compileSuite (suite, block); + append_to_statement_list (build1 (GOTO_EXPR, void_type_node, start_label_decl), block); + append_to_statement_list (end_label_expr, block); + + __loopContexts.pop_back (); } -// Seems to be an entry point for lowering a series (suite?) of control statements and fields - usage suggests possibly lowering a block -static void dot_pass_compileSuite(rdot suite, tree* block) { - rdot node; - for (node = suite; node != NULL_DOT; node = RDOT_CHAIN(node)) { - if (RDOT_T_FIELD(node) == D_D_EXPR) - append_to_statement_list(dot_pass_lowerExpr(node, block), block); - else { - switch (RDOT_TYPE(node)) { - case D_STRUCT_IF: - dot_pass_compileCond(node, block); - break; - - case D_STRUCT_WHILE: - dot_pass_compileWhile(node, block); - break; - - case D_STRUCT_LOOP: - dot_pass_compileLoop(node, block); - break; - - case C_BREAK_STMT: - dot_pass_compileBreak(node, block); - break; - - default: - error("Unhandled statement [%s]\n", RDOT_OPCODE_STR(node)); - break; +static +void dot_pass_compileSuite (rdot suite, tree * block) +{ + rdot node; + for (node = suite; node != NULL_DOT; node = RDOT_CHAIN (node)) + { + if (RDOT_T_FIELD (node) == D_D_EXPR) + append_to_statement_list (dot_pass_lowerExpr (node, block), block); + else + { + switch (RDOT_TYPE (node)) + { + case D_STRUCT_IF: + dot_pass_compileCond (node, block); + break; + + case D_STRUCT_WHILE: + dot_pass_compileWhile (node, block); + break; + + case D_STRUCT_LOOP: + dot_pass_compileLoop (node, block); + break; + + case C_BREAK_STMT: + dot_pass_compileBreak (node, block); + break; + + default: + error ("Unhandled statement [%s]\n", RDOT_OPCODE_STR (node)); + break; } } } } -// Seems to be an entry point for generating method prototypes from an rdot node and adding them to list -static void dot_pass_genMethodProto(rdot node) { - const char* method_id = RDOT_IDENTIFIER_POINTER(RDOT_FIELD(node)); - if (dot_pass_lookupCTU(method_id) != error_mark_node) { - error("Duplicate declaration of function [%s]\n", method_id); - return; +static +void dot_pass_genMethodProto (rdot node) +{ + const char * method_id = RDOT_IDENTIFIER_POINTER (RDOT_FIELD (node)); + if (dot_pass_lookupCTU (method_id) != error_mark_node) + { + error ("Duplicate declaration of function [%s]\n", method_id); + return; } - tree rtype = void_type_node; - if (RDOT_FIELD2(node)) - rtype = dot_pass_rustToGccType(RDOT_FIELD2(node), false); - - rdot parameters = RDOT_lhs_TT(node); - tree fntype = error_mark_node; - if (parameters != NULL_DOT) { - size_t nparams = 0; - rdot prm; - for (prm = parameters; prm != NULL_DOT; prm = RDOT_CHAIN(prm)) - nparams++; - - tree* gccparams = XALLOCAVEC(tree, nparams); - size_t i = 0; - for (prm = parameters; prm != NULL_DOT; prm = RDOT_CHAIN(prm)) { - bool mut = false; - if (RDOT_qual(prm)) - mut = true; - gccparams[i] = dot_pass_rustToGccType(RDOT_rhs_TT(prm), mut); - i++; - } - fntype = build_function_type_array(rtype, nparams, gccparams); - } else - fntype = build_function_type_list(rtype, NULL_TREE); + tree rtype = void_type_node; + if (RDOT_FIELD2 (node)) + rtype = dot_pass_rustToGccType (RDOT_FIELD2 (node), false); + + rdot parameters = RDOT_lhs_TT (node); + tree fntype = error_mark_node; + if (parameters != NULL_DOT) + { + size_t nparams = 0; + rdot prm; + for (prm = parameters; prm != NULL_DOT; prm = RDOT_CHAIN (prm)) + nparams++; + + tree * gccparams = XALLOCAVEC (tree, nparams); + size_t i = 0; + for (prm = parameters; prm != NULL_DOT; prm = RDOT_CHAIN (prm)) + { + bool mut = false; + if (RDOT_qual (prm)) + mut = true; + gccparams [i] = dot_pass_rustToGccType (RDOT_rhs_TT (prm), mut); + i++; + } + fntype = build_function_type_array (rtype, nparams, gccparams); + } + else + fntype = build_function_type_list (rtype, NULL_TREE); - tree fndecl = dot_pass_genFndecl_Basic(RDOT_LOCATION(node), method_id, fntype); - SET_DECL_ASSEMBLER_NAME(fndecl, get_identifier(dot_pass_mangle(method_id))); - dot_pass_pushDecl(method_id, fndecl); + tree fndecl = dot_pass_genFndecl_Basic (RDOT_LOCATION (node), method_id, fntype); + SET_DECL_ASSEMBLER_NAME (fndecl, get_identifier (dot_pass_mangle (method_id))); + dot_pass_pushDecl (method_id, fndecl); } -// Seems to parse and then gimplify an rdot node corresponding to a function tree? - potentially the main entry point, as gcc docs indicate compilation is done on a function-level -static tree dot_pass_genifyTopFndecl(rdot node) { - const char* method_id; - if (__impl_type_decl != error_mark_node) { - char* mid = RDOT_IDENTIFIER_POINTER(RDOT_FIELD(node)); - tree spfx = TYPE_NAME(__impl_type_decl); - const char* pfx = IDENTIFIER_POINTER(spfx); - - size_t len = strlen(mid) + strlen(pfx) + 2; - size_t bsize = len * sizeof(char); - char* buffer = (char*)alloca(bsize); - gcc_assert(buffer); - memset(buffer, 0, bsize); - - snprintf(buffer, bsize, "%s.%s", pfx, mid); - method_id = buffer; - } else - method_id = RDOT_IDENTIFIER_POINTER(RDOT_FIELD(node)); - - tree rtype = void_type_node; - if (RDOT_FIELD2(node)) - rtype = dot_pass_rustToGccType(RDOT_FIELD2(node), false); - - rdot parameters = RDOT_lhs_TT(node); - tree fntype = error_mark_node; - if (parameters != NULL_DOT) { - size_t nparams = 0; - rdot prm; - for (prm = parameters; prm != NULL_DOT; prm = RDOT_CHAIN(prm)) - nparams++; - - tree* gccparams = XALLOCAVEC(tree, nparams); - size_t i = 0; - for (prm = parameters; prm != NULL_DOT; prm = RDOT_CHAIN(prm)) { - bool mut = false; - if (RDOT_qual(prm)) - mut = true; - - const char* pid = RDOT_IDENTIFIER_POINTER(RDOT_lhs_TT(prm)); - if (strcmp(pid, "self") == 0) { - fatal_error("unhandled self argument!"); - } else - gccparams[i] = dot_pass_rustToGccType(RDOT_rhs_TT(prm), mut); - i++; - } - fntype = build_function_type_array(rtype, nparams, gccparams); - } else - fntype = build_function_type_list(rtype, NULL_TREE); - - tree fndecl = dot_pass_genFndecl_Basic(RDOT_LOCATION(node), method_id, fntype); - SET_DECL_ASSEMBLER_NAME(fndecl, get_identifier(dot_pass_mangle(method_id))); - dot_pass_pushContext(); - - rdot rdot_params = RDOT_lhs_TT(node); - if (rdot_params != NULL_DOT) { - tree argslist = NULL_TREE; - rdot next; - for (next = rdot_params; next != NULL_DOT; next = RDOT_CHAIN(next)) { - const char* pid = RDOT_IDENTIFIER_POINTER(RDOT_lhs_TT(next)); - if (dot_pass_lookupCTU(pid) != error_mark_node) - error("paramater [%s] is already declared", pid); - - tree ptype = error_mark_node; - if (strcmp(pid, "self") == 0) { - fatal_error("unhandled self param!"); - } else - ptype = dot_pass_rustToGccType(RDOT_rhs_TT(next), false); - - tree param = build_decl(RDOT_LOCATION(node), PARM_DECL, get_identifier(pid), ptype); - DECL_CONTEXT(param) = fndecl; - DECL_ARG_TYPE(param) = ptype; - TREE_READONLY(param) = true; - TREE_USED(param) = true; - argslist = chainon(argslist, param); - - dot_pass_pushDecl(pid, param); - } - DECL_ARGUMENTS(fndecl) = argslist; +static +tree dot_pass_genifyTopFndecl (rdot node) +{ + const char * method_id; + if (__impl_type_decl != error_mark_node) + { + char * mid = RDOT_IDENTIFIER_POINTER (RDOT_FIELD (node)); + tree spfx = TYPE_NAME (__impl_type_decl); + const char *pfx = IDENTIFIER_POINTER (spfx); + + size_t len = strlen (mid) + strlen (pfx) + 2; + size_t bsize = len * sizeof (char); + char * buffer = (char *) alloca (bsize); + gcc_assert (buffer); + memset (buffer, 0, bsize); + + snprintf (buffer, bsize, "%s.%s", pfx, mid); + method_id = buffer; + } + else + method_id = RDOT_IDENTIFIER_POINTER (RDOT_FIELD (node)); + + tree rtype = void_type_node; + if (RDOT_FIELD2 (node)) + rtype = dot_pass_rustToGccType (RDOT_FIELD2 (node), false); + + rdot parameters = RDOT_lhs_TT (node); + tree fntype = error_mark_node; + if (parameters != NULL_DOT) + { + size_t nparams = 0; + rdot prm; + for (prm = parameters; prm != NULL_DOT; prm = RDOT_CHAIN (prm)) + nparams++; + + tree * gccparams = XALLOCAVEC (tree, nparams); + size_t i = 0; + for (prm = parameters; prm != NULL_DOT; prm = RDOT_CHAIN (prm)) + { + bool mut = false; + if (RDOT_qual (prm)) + mut = true; + + const char * pid = RDOT_IDENTIFIER_POINTER (RDOT_lhs_TT (prm)); + if (strcmp (pid, "self") == 0) + { + fatal_error ("unhandled self argument!"); + } + else + gccparams [i] = dot_pass_rustToGccType (RDOT_rhs_TT (prm), mut); + i++; + } + fntype = build_function_type_array (rtype, nparams, gccparams); + } + else + fntype = build_function_type_list (rtype, NULL_TREE); + + tree fndecl = dot_pass_genFndecl_Basic (RDOT_LOCATION (node), method_id, fntype); + SET_DECL_ASSEMBLER_NAME (fndecl, get_identifier (dot_pass_mangle (method_id))); + dot_pass_pushContext (); + + rdot rdot_params = RDOT_lhs_TT (node); + if (rdot_params != NULL_DOT) + { + tree argslist = NULL_TREE; + rdot next; + for (next = rdot_params; next != NULL_DOT; next = RDOT_CHAIN (next)) + { + const char * pid = RDOT_IDENTIFIER_POINTER (RDOT_lhs_TT (next)); + if (dot_pass_lookupCTU (pid) != error_mark_node) + error ("paramater [%s] is already declared", pid); + + tree ptype = error_mark_node; + if (strcmp (pid, "self") == 0) + { + fatal_error ("unhandled self param!"); + } + else + ptype = dot_pass_rustToGccType (RDOT_rhs_TT (next), false); + + tree param = build_decl (RDOT_LOCATION (node), PARM_DECL, + get_identifier (pid), ptype); + DECL_CONTEXT (param) = fndecl; + DECL_ARG_TYPE (param) = ptype; + TREE_READONLY (param) = true; + TREE_USED (param) = true; + argslist = chainon (argslist, param); + + dot_pass_pushDecl (pid, param); + } + DECL_ARGUMENTS (fndecl) = argslist; } - current_function_decl = fndecl; - tree block = alloc_stmt_list(); - current_function_block = █ - - global_retDecl_ = false; - if (rtype == void_type_node) - global_retDecl = error_mark_node; - else - global_retDecl = DECL_RESULT(fndecl); - - // compile the block... - dot_pass_compileSuite(RDOT_rhs_TT(node), &block); + current_function_decl = fndecl; + tree block = alloc_stmt_list (); + current_function_block = █ - // make sure it returns something!!! - if (rtype != void_type_node) { - if (global_retDecl_ == false) { - error("Function [%s] doesn't seem to return anything!!\n", method_id); - return error_mark_node; + global_retDecl_ = false; + if (rtype == void_type_node) + global_retDecl = error_mark_node; + else + global_retDecl = DECL_RESULT (fndecl); + + // compile the block... + dot_pass_compileSuite (RDOT_rhs_TT (node), &block); + + // make sure it returns something!!! + if (rtype != void_type_node) + { + if (global_retDecl_ == false) + { + error ("Function [%s] doesn't seem to return anything!!\n", method_id); + return error_mark_node; } - tree returnVal = build1(RETURN_EXPR, rtype, global_retDecl); - append_to_statement_list(returnVal, &block); + tree returnVal = build1 (RETURN_EXPR, rtype, global_retDecl); + append_to_statement_list (returnVal, &block); } - tree bind = NULL_TREE; - tree declare_vars = DECL_RESULT(fndecl); - - tree head = declare_vars; - std::vector<tree>* decl_vars = dot_pass_popContext(); - std::vector<tree>::iterator it; - for (it = decl_vars->begin(); it != decl_vars->end(); ++it) { - if (TREE_CODE(*it) != PARM_DECL) { - DECL_CHAIN(head) = *it; - head = *it; - } + tree bind = NULL_TREE; + tree declare_vars = DECL_RESULT (fndecl); + + tree head = declare_vars; + std::vector<tree> * decl_vars = dot_pass_popContext (); + std::vector<tree>::iterator it; + for (it = decl_vars->begin (); it != decl_vars->end (); ++it) + { + if (TREE_CODE (*it) != PARM_DECL) + { + DECL_CHAIN (head) = *it; + head = *it; + } } - delete decl_vars; + delete decl_vars; - tree bl = make_node(BLOCK); - BLOCK_SUPERCONTEXT(bl) = fndecl; - DECL_INITIAL(fndecl) = bl; - BLOCK_VARS(bl) = declare_vars; - TREE_USED(bl) = true; + tree bl = make_node (BLOCK); + BLOCK_SUPERCONTEXT (bl) = fndecl; + DECL_INITIAL (fndecl) = bl; + BLOCK_VARS(bl) = declare_vars; + TREE_USED (bl) = true; - bind = build3(BIND_EXPR, void_type_node, BLOCK_VARS(bl), NULL_TREE, bl); - TREE_SIDE_EFFECTS(bind) = 1; - /* Finalize the main function */ - BIND_EXPR_BODY(bind) = block; - block = bind; - DECL_SAVED_TREE(fndecl) = block; + bind = build3 (BIND_EXPR, void_type_node, BLOCK_VARS (bl), + NULL_TREE, bl); + TREE_SIDE_EFFECTS (bind) = 1; + /* Finalize the main function */ + BIND_EXPR_BODY (bind) = block; + block = bind; + DECL_SAVED_TREE (fndecl) = block; - gimplify_function_tree(fndecl); - cgraph_finalize_function(fndecl, false); + gimplify_function_tree (fndecl); + cgraph_finalize_function (fndecl, false); - pop_cfun(); + pop_cfun (); - // reset them - global_retDecl = error_mark_node; - global_retDecl_ = false; + // reset them + global_retDecl = error_mark_node; + global_retDecl_ = false; - return fndecl; + return fndecl; } -// Seems to lower a struct and add it to somewhere, and returns a tree declaration of it? -static tree dot_pass_genifyStruct(rdot node) { - rdot layout = RDOT_rhs_TT(node); - tree userStruct = make_node(RECORD_TYPE); - - bool first = true; - tree head_chain = NULL_TREE; - tree curr = head_chain; - - rdot next; - for (next = layout; next != NULL_DOT; next = RDOT_CHAIN(next)) { - gcc_assert(RDOT_TYPE(next) == D_PARAMETER); - tree name = get_identifier(RDOT_IDENTIFIER_POINTER(RDOT_lhs_TT(next))); - tree type = dot_pass_rustToGccType(RDOT_rhs_TT(next), false); - tree field = build_decl(RDOT_LOCATION(node), - FIELD_DECL, - name, - type); - DECL_CONTEXT(field) = userStruct; - if (first == true) { - head_chain = curr = field; - first = false; - } else { - DECL_CHAIN(curr) = field; - curr = field; +static +tree dot_pass_genifyStruct (rdot node) +{ + rdot layout = RDOT_rhs_TT (node); + tree userStruct = make_node (RECORD_TYPE); + + bool first = true; + tree head_chain = NULL_TREE; + tree curr = head_chain; + + rdot next; + for (next = layout; next != NULL_DOT; next = RDOT_CHAIN (next)) + { + gcc_assert (RDOT_TYPE (next) == D_PARAMETER); + tree name = get_identifier (RDOT_IDENTIFIER_POINTER (RDOT_lhs_TT (next))); + tree type = dot_pass_rustToGccType (RDOT_rhs_TT (next), false); + tree field = build_decl (RDOT_LOCATION (node), + FIELD_DECL, name, type); + DECL_CONTEXT (field) = userStruct; + if (first == true) + { + head_chain = curr = field; + first = false; + } + else + { + DECL_CHAIN (curr) = field; + curr = field; } } - TYPE_FIELDS(userStruct) = head_chain; - layout_type(userStruct); - - const char* struct_id = RDOT_IDENTIFIER_POINTER(RDOT_lhs_TT(node)); - tree type_decl = build_decl(RDOT_LOCATION(node), TYPE_DECL, get_identifier(struct_id), userStruct); - TYPE_NAME(userStruct) = get_identifier(struct_id); - grs_preserve_from_gc(type_decl); - rest_of_decl_compilation(type_decl, 1, 0); - dot_pass_pushDecl(struct_id, userStruct); - return type_decl; + TYPE_FIELDS (userStruct) = head_chain; + layout_type (userStruct); + + const char * struct_id = RDOT_IDENTIFIER_POINTER (RDOT_lhs_TT (node)); + tree type_decl = build_decl (RDOT_LOCATION (node), TYPE_DECL, + get_identifier (struct_id), userStruct); + TYPE_NAME (userStruct) = get_identifier (struct_id); + grs_preserve_from_gc (type_decl); + rest_of_decl_compilation (type_decl, 1, 0); + dot_pass_pushDecl (struct_id, userStruct); + return type_decl; } -// Seems to lower a struct impl block, returning a pointer to a vector of trees containing various statements from it, e.g. function declarations -static std::vector<tree>* dot_pass_genifyImplBlock(rdot node) { - std::vector<tree>* retval = new std::vector<tree>; - // look up the struct type to set TYPE_METHODS on it... - const char* implid = RDOT_IDENTIFIER_POINTER(RDOT_lhs_TT(node)); - tree type_decl = dot_pass_lookupCTU(implid); - if (type_decl == error_mark_node) - error("type [%s] does not exist for impl block", implid); - else { - __impl_type_decl = type_decl; - rdot decl; - tree fndecl_chain = error_mark_node, curr = error_mark_node; - bool first = true; - for (decl = RDOT_rhs_TT(node); decl != NULL_DOT; decl = RDOT_CHAIN(decl)) { - tree fndecl = dot_pass_genifyTopFndecl(decl); - retval->push_back(fndecl); - if (first == true) { - fndecl_chain = fndecl; - curr = fndecl_chain; - first = false; - } else { - DECL_CHAIN(curr) = fndecl; - curr = fndecl; - } - } - TYPE_METHODS(__impl_type_decl) = fndecl_chain; - __impl_type_decl = error_mark_node; +static +std::vector<tree> * dot_pass_genifyImplBlock (rdot node) +{ + std::vector<tree> * retval = new std::vector<tree>; + // look up the struct type to set TYPE_METHODS on it... + const char * implid = RDOT_IDENTIFIER_POINTER (RDOT_lhs_TT (node)); + tree type_decl = dot_pass_lookupCTU (implid); + if (type_decl == error_mark_node) + error ("type [%s] does not exist for impl block", implid); + else + { + __impl_type_decl = type_decl; + rdot decl; + tree fndecl_chain = error_mark_node, curr = error_mark_node; + bool first = true; + for (decl = RDOT_rhs_TT (node); decl != NULL_DOT; decl = RDOT_CHAIN (decl)) + { + tree fndecl = dot_pass_genifyTopFndecl (decl); + retval->push_back (fndecl); + if (first == true) + { + fndecl_chain = fndecl; + curr = fndecl_chain; + first = false; + } + else + { + DECL_CHAIN (curr) = fndecl; + curr = fndecl; + } + } + TYPE_METHODS (__impl_type_decl) = fndecl_chain; + __impl_type_decl = error_mark_node; } - return retval; + return retval; } -// Seems to be an entry point for lowering a top level declaration - handles struct methods? -static std::vector<tree>* dot_pass_genifyTopNode(rdot node) { - std::vector<tree>* retval = NULL; - switch (RDOT_TYPE(node)) { - case D_STRUCT_METHOD: { - retval = new std::vector<tree>; - retval->push_back(dot_pass_genifyTopFndecl(node)); - } break; - - // nothing to do here... - case D_STRUCT_TYPE: - case D_STRUCT_IMPL: - break; - - default: - error("Unhandled Toplevel declaration [%s]\n", RDOT_OPCODE_STR(node)); - break; +static +std::vector<tree> * dot_pass_genifyTopNode (rdot node) +{ + std::vector<tree> * retval = NULL; + switch (RDOT_TYPE (node)) + { + case D_STRUCT_METHOD: + { + retval = new std::vector<tree>; + retval->push_back (dot_pass_genifyTopFndecl (node)); + } + break; + + // nothing to do here... + case D_STRUCT_TYPE: + case D_STRUCT_IMPL: + break; + + default: + error ("Unhandled Toplevel declaration [%s]\n", RDOT_OPCODE_STR (node)); + break; } - return retval; + return retval; } -// Appends runtime decls to context -static void dot_pass_setupContext(void) { - std::map<std::string, tree>* lgrs = new std::map<std::string, tree>(); - rs_fill_runtime_decls(lgrs); - context.push_back(lgrs); +static +void dot_pass_setupContext (void) +{ + std::map<std::string, tree> * lgrs = new std::map<std::string, tree>(); + rs_fill_runtime_decls (lgrs); + context.push_back (lgrs); } -// Appends an empty map to context -static void dot_pass_pushContext(void) { - std::map<std::string, tree>* nctx = new std::map<std::string, tree>; - context.push_back(nctx); +static +void dot_pass_pushContext (void) +{ + std::map<std::string, tree> * nctx = new std::map<std::string, tree>; + context.push_back (nctx); } -// Removes last element in vector, seems to move stuff in vector around too? -static std::vector<tree>* dot_pass_popContext(void) { - std::vector<tree>* retval = new std::vector<tree>; - if (context.size() > 0) { - std::map<std::string, tree>* popd = context.back(); - context.pop_back(); +static +std::vector<tree> * dot_pass_popContext (void) +{ + std::vector<tree> * retval = new std::vector<tree>; + if (context.size () > 0) + { + std::map<std::string, tree> * popd = context.back (); + context.pop_back (); - std::map<std::string, tree>::iterator it; - for (it = popd->begin(); it != popd->end(); ++it) - retval->push_back(it->second); + std::map<std::string, tree>::iterator it; + for (it = popd->begin (); it != popd->end (); ++it) + retval->push_back (it->second); - delete popd; + delete popd; } - return retval; + return retval; } -// Seems to be the actual entry point of the entire logical unit - creates "context" and iterates through decls, lowering stuff -vec<tree, va_gc>* dot_pass_Genericify(vec<rdot, va_gc>* decls) { - vec<tree, va_gc>* retval; - vec_alloc(retval, 0); - - dot_pass_setupContext(); - dot_pass_pushContext(); - - size_t i; - rdot idtx = NULL_DOT; - - /* fill up the prototypes now ... */ - for (i = 0; decls->iterate(i, &idtx); ++i) { - rdot node = idtx; - switch (RDOT_TYPE(node)) { - case D_STRUCT_METHOD: - dot_pass_genMethodProto(node); - break; - - case D_STRUCT_TYPE: { - tree gen = dot_pass_genifyStruct(node); - vec_safe_push(retval, gen); - } break; +vec<tree,va_gc> * dot_pass_Genericify (vec<rdot,va_gc> * decls) +{ + vec<tree,va_gc> * retval; + vec_alloc (retval, 0); + + dot_pass_setupContext (); + dot_pass_pushContext (); + + size_t i; + rdot idtx = NULL_DOT; + + /* fill up the prototypes now ... */ + for (i = 0; decls->iterate (i, &idtx); ++i) + { + rdot node = idtx; + switch (RDOT_TYPE (node)) + { + case D_STRUCT_METHOD: + dot_pass_genMethodProto (node); + break; + + case D_STRUCT_TYPE: + { + tree gen = dot_pass_genifyStruct (node); + vec_safe_push (retval, gen); + } + break; - default: - break; - } + default: + break; + } } - if (seen_error()) - goto exit; - - for (i = 0; decls->iterate(i, &idtx); ++i) { - rdot node = idtx; - switch (RDOT_TYPE(node)) { - case D_STRUCT_IMPL: { - std::vector<tree>* gdecls = dot_pass_genifyImplBlock(node); - std::vector<tree>::iterator it; - for (it = gdecls->begin(); it != gdecls->end(); ++it) - vec_safe_push(retval, *it); - delete gdecls; - } break; + if (seen_error ()) + goto exit; + + for (i = 0; decls->iterate (i, &idtx); ++i) + { + rdot node = idtx; + switch (RDOT_TYPE (node)) + { + case D_STRUCT_IMPL: + { + std::vector<tree> * gdecls = dot_pass_genifyImplBlock (node); + std::vector<tree>::iterator it; + for (it = gdecls->begin (); it != gdecls->end (); ++it) + vec_safe_push (retval, *it); + delete gdecls; + } + break; - default: - break; - } + default: + break; + } } - if (seen_error()) - goto exit; - - __impl_type_decl = error_mark_node; - for (i = 0; decls->iterate(i, &idtx); ++i) { - std::vector<tree>* gdecls = dot_pass_genifyTopNode(idtx); - if (gdecls != NULL) { - std::vector<tree>::iterator it; - for (it = gdecls->begin(); it != gdecls->end(); ++it) - vec_safe_push(retval, *it); - delete gdecls; - } + if (seen_error ()) + goto exit; + + __impl_type_decl = error_mark_node; + for (i = 0; decls->iterate (i, &idtx); ++i) + { + std::vector<tree> * gdecls = dot_pass_genifyTopNode (idtx); + if (gdecls != NULL) + { + std::vector<tree>::iterator it; + for (it = gdecls->begin (); it != gdecls->end (); ++it) + vec_safe_push (retval, *it); + delete gdecls; + } } -exit: - dot_pass_popContext(); - return retval; + exit: + dot_pass_popContext (); + return retval; } diff --git a/gcc/rust/old/rdot-impl.cc b/gcc/rust/old/rdot-impl.cc index 553638d..be4421b 100644 --- a/gcc/rust/old/rdot-impl.cc +++ b/gcc/rust/old/rdot-impl.cc @@ -18,236 +18,250 @@ static bool initilized = false; -static const char* opcodeStrings[] = { - /* [D_IDENTIFIER] */ "identifier", - /* [D_T_INTEGER] */ "literal_integer", - /* [D_T_FLOAT] */ "literal_float", - /* [D_T_STRING] */ "literal_string", - /* [D_T_LIST] */ "liteal_list", - /* [D_VAR_DECL] */ "var_decl", - /* [D_MODIFY_EXPR] */ "modify_expr", - /* [D_MULT_EXPR] */ "multiply_expr", - /* [D_DIVD_EXPR] */ "divide_expr", - /* [D_ADD_EXPR] */ "plus_expr", - /* [D_MINUS_EXPR] */ "minus_expr", - /* [D_EQ_EQ_EXPR] */ "equivilant_expr", - /* [D_LESS_EXPR] */ "less_than_expr", - /* [D_LESS_EQ_EXPR] */ "less_eq_expr", - /* [D_GREATER_EXPR] */ "greater_expr", - /* [D_GREATER_EQ_EXPR] */ "greater_eq_expr", - /* [D_NOT_EQ_EXPR] */ "not_equal_expr", - /* [D_CALL_EXPR] */ "call_expr", - /* [D_ATTRIB_EXPR] */ "attribute_reference", - /* [D_ACC_EXPR] */ "accessor_reference", - /* [D_STRUCT_METHOD] */ "struct_method", - /* [D_STRUCT_WHILE] */ "struct_while", - /* [D_STRUCT_LOOP] */ "struct_loop", - /* [D_D_EXPR] */ "enc_expression", - /* [D_TD_COM] */ "TD_COM", - /* [D_TD_DOT] */ "TD_DOT", - /* [D_TD_NULL] */ "TD_NULL", - /* [D_PRIMITIVE] */ "primitive", - /* [D_STRUCT_IF] */ "struct_if", - /* [D_STRUCT_ELIF] */ "struct_elif", - /* [D_STRUCT_ELSE] */ "struct_else", - /* [D_STRUCT_CONDITIONAL] */ "struct_conditional", - /* [RTYPE_BOOL] */ "type_bool", - /* [RTYPE_INT] */ "type_int", - /* [RTYPE_FLOAT] */ "type_float", - /* [RTYPE_UINT] */ "type_uint", - /* [RTYPE_INFER] */ "type_infer", - /* [D_PARAMETER] */ "parameter", - /* [D_STRUCT_TYPE] */ "struct_definition", - /* [D_STRUCT_PARAM] */ "struct_init_param", - /* [D_STRUCT_INIT] */ "struct_initilization", - /* [RTYPE_USER_STRUCT] */ "user_struct_type", - /* [D_STRUCT_ENUM] */ "struct_enum", - /* [D_STRUCT_IMPL] */ "impl_block", - /* [D_BOOLEAN] */ "d_boolean", - /* [D_T_BOOL] */ "d_t_bool", - /* [C_BREAK_STMT] */ "break_stmt", - /* [C_CONT_STMT] */ "continue_stmt", - /* [C_RETURN_STMT] */ "return_stmt", +static const char * opcodeStrings [] = { + /* [D_IDENTIFIER] */ "identifier", + /* [D_T_INTEGER] */ "literal_integer", + /* [D_T_FLOAT] */ "literal_float", + /* [D_T_STRING] */ "literal_string", + /* [D_T_LIST] */ "liteal_list", + /* [D_VAR_DECL] */ "var_decl", + /* [D_MODIFY_EXPR] */ "modify_expr", + /* [D_MULT_EXPR] */ "multiply_expr", + /* [D_DIVD_EXPR] */ "divide_expr", + /* [D_ADD_EXPR] */ "plus_expr", + /* [D_MINUS_EXPR] */ "minus_expr", + /* [D_EQ_EQ_EXPR] */ "equivilant_expr", + /* [D_LESS_EXPR] */ "less_than_expr", + /* [D_LESS_EQ_EXPR] */ "less_eq_expr", + /* [D_GREATER_EXPR] */ "greater_expr", + /* [D_GREATER_EQ_EXPR] */ "greater_eq_expr", + /* [D_NOT_EQ_EXPR] */ "not_equal_expr", + /* [D_CALL_EXPR] */ "call_expr", + /* [D_ATTRIB_EXPR] */ "attribute_reference", + /* [D_ACC_EXPR] */ "accessor_reference", + /* [D_STRUCT_METHOD] */ "struct_method", + /* [D_STRUCT_WHILE] */ "struct_while", + /* [D_STRUCT_LOOP] */ "struct_loop", + /* [D_D_EXPR] */ "enc_expression", + /* [D_TD_COM] */ "TD_COM", + /* [D_TD_DOT] */ "TD_DOT", + /* [D_TD_NULL] */ "TD_NULL", + /* [D_PRIMITIVE] */ "primitive", + /* [D_STRUCT_IF] */ "struct_if", + /* [D_STRUCT_ELIF] */ "struct_elif", + /* [D_STRUCT_ELSE] */ "struct_else", + /* [D_STRUCT_CONDITIONAL] */ "struct_conditional", + /* [RTYPE_BOOL] */ "type_bool", + /* [RTYPE_INT] */ "type_int", + /* [RTYPE_FLOAT] */ "type_float", + /* [RTYPE_UINT] */ "type_uint", + /* [RTYPE_INFER] */ "type_infer", + /* [D_PARAMETER] */ "parameter", + /* [D_STRUCT_TYPE] */ "struct_definition", + /* [D_STRUCT_PARAM] */ "struct_init_param", + /* [D_STRUCT_INIT] */ "struct_initilization", + /* [RTYPE_USER_STRUCT] */ "user_struct_type", + /* [D_STRUCT_ENUM] */ "struct_enum", + /* [D_STRUCT_IMPL] */ "impl_block", + /* [D_BOOLEAN] */ "d_boolean", + /* [D_T_BOOL] */ "d_t_bool", + /* [C_BREAK_STMT] */ "break_stmt", + /* [C_CONT_STMT] */ "continue_stmt", + /* [C_RETURN_STMT] */ "return_stmt", }; -// Gets string representation of opcode_t instance (which defines possible types in a less strict sense that usual) -const char* rdot_getOpString_T(const opcode_t o) { - return opcodeStrings[o]; +const char * +rdot_getOpString_T (const opcode_t o) +{ + return opcodeStrings [o]; } -// Gets string representation of rdot's type -const char* rdot_getOpString(const rdot dot) { - return rdot_getOpString_T(RDOT_TYPE(dot)); +const char * +rdot_getOpString (const rdot dot) +{ + return rdot_getOpString_T (RDOT_TYPE (dot)); } -// Ensures "initilized" is true -void rdot_init(void) { - if (initilized) - return; - //... probably should get rid of this function ... - initilized = true; +void rdot_init (void) +{ + if (initilized) + return; + //... probably should get rid of this function ... + initilized = true; } -// Presumably parses a variable declaration -rdot rdot_build_varDecl(rdot type, bool final, rdot id) { - rdot decl = rdot_build_decl2(D_VAR_DECL, id, type); - RDOT_qual(decl) = final; - return decl; +rdot rdot_build_varDecl (rdot type, bool final, rdot id) +{ + rdot decl = rdot_build_decl2 (D_VAR_DECL, id, type); + RDOT_qual (decl) = final; + return decl; } -// Presumably allocates a new grs_tree_dot instance -rdot rdot_alloc(void) { - rdot retval = (struct grs_tree_dot*) - xmalloc(sizeof(struct grs_tree_dot)); - gcc_assert(retval); - memset(retval, 0, sizeof(struct grs_tree_dot)); - RDOT_LOCATION(retval) = UNKNOWN_LOCATION; - return retval; +rdot rdot_alloc (void) +{ + rdot retval = (struct grs_tree_dot *) + xmalloc (sizeof (struct grs_tree_dot)); + gcc_assert (retval); + memset (retval, 0, sizeof (struct grs_tree_dot)); + RDOT_LOCATION (retval) = UNKNOWN_LOCATION; + return retval; } -// Seems to parse a unary? declaration? -rdot rdot_build_decl1(opcode_t o, rdot t1) { - rdot decl = RDOT_alloc; +rdot rdot_build_decl1 (opcode_t o, rdot t1) +{ + rdot decl = RDOT_alloc; - RDOT_TYPE(decl) = o; - RDOT_T_FIELD(decl) = D_TD_NULL; - RDOT_FIELD(decl) = NULL_DOT; + RDOT_TYPE(decl) = o; + RDOT_T_FIELD(decl) = D_TD_NULL; + RDOT_FIELD(decl) = NULL_DOT; - decl->opaT = D_TD_DOT; - decl->opa.t = t1; - decl->opbT = D_TD_NULL; + decl->opaT = D_TD_DOT; + decl->opa.t = t1; + decl->opbT = D_TD_NULL; - RDOT_CHAIN(decl) = NULL_DOT; + RDOT_CHAIN(decl) = NULL_DOT; - return decl; + return decl; } -// Seems to parse a binary? expression? (misleading name, amirite?) -rdot rdot_build_decl2(opcode_t o, rdot t1, rdot t2) { - rdot decl = RDOT_alloc; - - RDOT_TYPE(decl) = o; - if ((o == D_VAR_DECL) || (o == D_MODIFY_EXPR) || (o == D_ADD_EXPR) || (o == D_MINUS_EXPR) - || (o == D_MULT_EXPR) || (o == D_DIVD_EXPR) || (o == D_CALL_EXPR) || (o == D_EQ_EQ_EXPR) - || (o == D_LESS_EXPR) || (o == D_LESS_EQ_EXPR) || (o == D_GREATER_EXPR) - || (o == D_GREATER_EQ_EXPR) || (o == D_NOT_EQ_EXPR) || (o == D_ATTRIB_REF) || (o == D_ACC_EXPR) - || (o == D_STRUCT_INIT)) - RDOT_T_FIELD(decl) = D_D_EXPR; - else - RDOT_T_FIELD(decl) = D_TD_NULL; +rdot rdot_build_decl2 (opcode_t o, rdot t1, rdot t2) +{ + rdot decl = RDOT_alloc; + + RDOT_TYPE (decl) = o; + if ((o == D_VAR_DECL) + || (o == D_MODIFY_EXPR) + || (o == D_ADD_EXPR) + || (o == D_MINUS_EXPR) + || (o == D_MULT_EXPR) + || (o == D_DIVD_EXPR) + || (o == D_CALL_EXPR) + || (o == D_EQ_EQ_EXPR) + || (o == D_LESS_EXPR) + || (o == D_LESS_EQ_EXPR) + || (o == D_GREATER_EXPR) + || (o == D_GREATER_EQ_EXPR) + || (o == D_NOT_EQ_EXPR) + || (o == D_ATTRIB_REF) + || (o == D_ACC_EXPR) + || (o == D_STRUCT_INIT) + ) + RDOT_T_FIELD(decl) = D_D_EXPR; + else + RDOT_T_FIELD(decl) = D_TD_NULL; - RDOT_FIELD(decl) = NULL_DOT; + RDOT_FIELD (decl) = NULL_DOT; - decl->opaT = D_TD_DOT; - decl->opa.t = t1; - decl->opbT = D_TD_DOT; - decl->opb.t = t2; + decl->opaT = D_TD_DOT; + decl->opa.t = t1; + decl->opbT = D_TD_DOT; + decl->opb.t = t2; - RDOT_CHAIN(decl) = NULL_DOT; + RDOT_CHAIN(decl) = NULL_DOT; - return decl; + return decl; } -// parse in function declaration? -rdot rdot_build_fndecl(rdot ident, bool pub, rdot params, rdot rtype, rdot suite) { - rdot decl = RDOT_alloc; +rdot rdot_build_fndecl (rdot ident, bool pub, rdot params, rdot rtype, rdot suite) +{ + rdot decl = RDOT_alloc; - RDOT_TYPE(decl) = D_STRUCT_METHOD; - RDOT_T_FIELD(decl) = D_TD_NULL; + RDOT_TYPE (decl) = D_STRUCT_METHOD; + RDOT_T_FIELD (decl) = D_TD_NULL; - RDOT_FIELD(decl) = ident; - RDOT_FIELD2(decl) = rtype; - DOT_RETVAL(decl) = pub; + RDOT_FIELD (decl) = ident; + RDOT_FIELD2 (decl) = rtype; + DOT_RETVAL (decl) = pub; - decl->opaT = D_TD_DOT; - decl->opa.t = params; - decl->opbT = D_TD_DOT; - decl->opb.t = suite; + decl->opaT = D_TD_DOT; + decl->opa.t = params; + decl->opbT = D_TD_DOT; + decl->opb.t = suite; - RDOT_CHAIN(decl) = NULL_DOT; + RDOT_CHAIN(decl) = NULL_DOT; - return decl; + return decl; } -// parse in int literal? -rdot rdot_build_integer(const int i) { - rdot decl = RDOT_alloc; - RDOT_TYPE(decl) = D_PRIMITIVE; +rdot rdot_build_integer (const int i) +{ + rdot decl = RDOT_alloc; + RDOT_TYPE(decl) = D_PRIMITIVE; - RDOT_FIELD(decl) = NULL_DOT; - RDOT_T_FIELD(decl) = D_D_EXPR; + RDOT_FIELD(decl) = NULL_DOT; + RDOT_T_FIELD(decl) = D_D_EXPR; - decl->opaT = D_TD_COM; - decl->opa.tc.T = D_T_INTEGER; - decl->opa.tc.o.integer = i; + decl->opaT = D_TD_COM; + decl->opa.tc.T = D_T_INTEGER; + decl->opa.tc.o.integer = i; - return decl; + return decl; } -// parse in float literal? -rdot rdot_build_float(const float f) { - rdot decl = RDOT_alloc; - RDOT_TYPE(decl) = D_PRIMITIVE; +rdot rdot_build_float (const float f) +{ + rdot decl = RDOT_alloc; + RDOT_TYPE(decl) = D_PRIMITIVE; - RDOT_FIELD(decl) = NULL_DOT; - RDOT_T_FIELD(decl) = D_D_EXPR; + RDOT_FIELD(decl) = NULL_DOT; + RDOT_T_FIELD(decl) = D_D_EXPR; - decl->opaT = D_TD_COM; - decl->opa.tc.T = D_T_FLOAT; - decl->opa.tc.o.ffloat = f; + decl->opaT = D_TD_COM; + decl->opa.tc.T = D_T_FLOAT; + decl->opa.tc.o.ffloat = f; - return decl; + return decl; } -// parse in string literal? -rdot rdot_build_string(const char* s) { - rdot decl = RDOT_alloc; - RDOT_TYPE(decl) = D_PRIMITIVE; +rdot rdot_build_string (const char * s) +{ + rdot decl = RDOT_alloc; + RDOT_TYPE (decl) = D_PRIMITIVE; - RDOT_FIELD(decl) = NULL_DOT; - RDOT_T_FIELD(decl) = D_D_EXPR; + RDOT_FIELD (decl) = NULL_DOT; + RDOT_T_FIELD (decl) = D_D_EXPR; - decl->opaT = D_TD_COM; - decl->opa.tc.T = D_T_STRING; - decl->opa.tc.o.string = xstrdup(s); + decl->opaT = D_TD_COM; + decl->opa.tc.T = D_T_STRING; + decl->opa.tc.o.string = xstrdup (s); - return decl; + return decl; } -// May parse in identifier -rdot rdot_build_identifier(const char* s) { - rdot decl = RDOT_alloc; +rdot rdot_build_identifier (const char * s) +{ + rdot decl = RDOT_alloc; - RDOT_TYPE(decl) = D_IDENTIFIER; - RDOT_FIELD(decl) = NULL_DOT; - RDOT_T_FIELD(decl) = D_D_EXPR; + RDOT_TYPE(decl) = D_IDENTIFIER; + RDOT_FIELD(decl) = NULL_DOT; + RDOT_T_FIELD(decl) = D_D_EXPR; - decl->opaT = D_TD_COM; - decl->opa.tc.T = D_T_STRING; - decl->opa.tc.o.string = xstrdup(s); + decl->opaT = D_TD_COM; + decl->opa.tc.T = D_T_STRING; + decl->opa.tc.o.string = xstrdup (s); - decl->opbT = D_TD_NULL; + decl->opbT = D_TD_NULL; - RDOT_CHAIN(decl) = NULL_DOT; + RDOT_CHAIN(decl) = NULL_DOT; - return decl; + return decl; } -// parse in boolean literal? -rdot rdot_build_bool(bool val) { - rdot decl = RDOT_alloc; +rdot rdot_build_bool (bool val) +{ + rdot decl = RDOT_alloc; - RDOT_TYPE(decl) = D_BOOLEAN; - RDOT_FIELD(decl) = NULL_DOT; - RDOT_T_FIELD(decl) = D_D_EXPR; + RDOT_TYPE(decl) = D_BOOLEAN; + RDOT_FIELD(decl) = NULL_DOT; + RDOT_T_FIELD(decl) = D_D_EXPR; - decl->opaT = D_TD_COM; - decl->opa.tc.T = D_T_BOOL; - decl->opa.tc.o.boolean = val; + decl->opaT = D_TD_COM; + decl->opa.tc.T = D_T_BOOL; + decl->opa.tc.o.boolean = val; - decl->opbT = D_TD_NULL; + decl->opbT = D_TD_NULL; - RDOT_CHAIN(decl) = NULL_DOT; + RDOT_CHAIN(decl) = NULL_DOT; - return decl; + return decl; } diff --git a/gcc/rust/old/rdot-impl.h b/gcc/rust/old/rdot-impl.h index a3291aa..8f7d71d1 100644 --- a/gcc/rust/old/rdot-impl.h +++ b/gcc/rust/old/rdot-impl.h @@ -18,155 +18,149 @@ #define __GCC_RDOT_IMPL_H__ typedef enum { - D_IDENTIFIER = 0, - D_T_INTEGER, - D_T_FLOAT, - D_T_STRING, - D_T_LIST, - - D_VAR_DECL, - D_MODIFY_EXPR, - D_MULT_EXPR, - D_DIVD_EXPR, - D_ADD_EXPR, - D_MINUS_EXPR, - - D_EQ_EQ_EXPR, - D_LESS_EXPR, - D_LESS_EQ_EXPR, - D_GREATER_EXPR, - D_GREATER_EQ_EXPR, - D_NOT_EQ_EXPR, - - D_CALL_EXPR, - D_ATTRIB_REF, - D_ACC_EXPR, - - D_STRUCT_METHOD, - D_STRUCT_WHILE, - D_STRUCT_LOOP, - - D_D_EXPR, - D_TD_COM, - D_TD_DOT, - D_TD_NULL, - - D_PRIMITIVE, - - D_STRUCT_IF, - D_STRUCT_ELIF, - D_STRUCT_ELSE, - D_STRUCT_CONDITIONAL, - - RTYPE_BOOL, - RTYPE_INT, - RTYPE_FLOAT, - RTYPE_UINT, - RTYPE_INFER, - - D_PARAMETER, - D_STRUCT_TYPE, - D_STRUCT_PARAM, - D_STRUCT_INIT, - - RTYPE_USER_STRUCT, - - D_STRUCT_ENUM, - D_STRUCT_IMPL, - - D_BOOLEAN, - D_T_BOOL, - - C_BREAK_STMT, - C_CONT_STMT, - C_RETURN_STMT -} opcode_t; + D_IDENTIFIER = 0, + D_T_INTEGER, + D_T_FLOAT, + D_T_STRING, + D_T_LIST, + + D_VAR_DECL, + D_MODIFY_EXPR, + D_MULT_EXPR, + D_DIVD_EXPR, + D_ADD_EXPR, + D_MINUS_EXPR, + + D_EQ_EQ_EXPR, + D_LESS_EXPR, + D_LESS_EQ_EXPR, + D_GREATER_EXPR, + D_GREATER_EQ_EXPR, + D_NOT_EQ_EXPR, + + D_CALL_EXPR, + D_ATTRIB_REF, + D_ACC_EXPR, + + D_STRUCT_METHOD, + D_STRUCT_WHILE, + D_STRUCT_LOOP, + + D_D_EXPR, + D_TD_COM, + D_TD_DOT, + D_TD_NULL, + + D_PRIMITIVE, + + D_STRUCT_IF, + D_STRUCT_ELIF, + D_STRUCT_ELSE, + D_STRUCT_CONDITIONAL, + + RTYPE_BOOL, + RTYPE_INT, + RTYPE_FLOAT, + RTYPE_UINT, + RTYPE_INFER, + + D_PARAMETER, + D_STRUCT_TYPE, + D_STRUCT_PARAM, + D_STRUCT_INIT, + + RTYPE_USER_STRUCT, + + D_STRUCT_ENUM, + D_STRUCT_IMPL, + + D_BOOLEAN, + D_T_BOOL, + + C_BREAK_STMT, + C_CONT_STMT, + C_RETURN_STMT +} opcode_t ; typedef enum { - ALLOC_HEAP, - ALLOC_REF, - ALLOC_DEREF + ALLOC_HEAP, + ALLOC_REF, + ALLOC_DEREF } ALLOCA_; -// Seems to be primitive literals typedef struct grs_rdot_tree_common { - // probably actual type used (tag for tagged union) - opcode_t T; - // possible values - union { - int integer; - float ffloat; - unsigned char c; - char* string; - bool boolean; - } o; -} rdot_tree_common; + opcode_t T; + union { + int integer; + float ffloat; + unsigned char c; + char * string; + bool boolean; + } o; +} rdot_tree_common ; typedef struct GTY(()) grs_tree_dot { - opcode_t T, FT, opaT, opbT; - bool retval, qual; - std::vector<ALLOCA_> alloca_modifier; - location_t loc; - struct grs_tree_dot* field1; - struct grs_tree_dot* field2; - union { - rdot_tree_common tc; - struct grs_tree_dot* t; - } opa; - union { - rdot_tree_common tc; - struct grs_tree_dot* t; - } opb; - struct grs_tree_dot* next; + opcode_t T, FT, opaT, opbT; + bool retval, qual; + std::vector<ALLOCA_> alloca_modifier; + location_t loc; + struct grs_tree_dot * field1; + struct grs_tree_dot * field2; + union { + rdot_tree_common tc; + struct grs_tree_dot * t; + } opa; + union { + rdot_tree_common tc; + struct grs_tree_dot * t; + } opb; + struct grs_tree_dot * next; } * rdot; -// A null rdot instance -#define NULL_DOT ((rdot)0) -#define RDOT_alloc rdot_alloc() -// Gets type of rdot instance -#define RDOT_TYPE(x_) x_->T -// Seems to get location_t for rdot -#define RDOT_LOCATION(x_) x_->loc -#define RDOT_T_FIELD(x_) x_->FT -#define RDOT_CHAIN(x_) x_->next -#define RDOT_FIELD(x_) x_->field1 -#define RDOT_FIELD2(x_) x_->field2 -#define RDOT_lhs_T(x_) x_->opaT -#define RDOT_rhs_T(x_) x_->opbT -#define RDOT_lhs_TT(x_) x_->opa.t -#define RDOT_rhs_TT(x_) x_->opb.t -#define RDOT_lhs_TC(x_) x_->opa.tc -#define RDOT_rhs_TC(x_) x_->opb.tc -#define RDOT_qual(x_) x_->qual -#define DOT_RETVAL(x_) x_->retval -#define RDOT_MEM_MODIFIER(x_) (&(x_->alloca_modifier)) -#define RDOT_IDENTIFIER_POINTER(x_) RDOT_lhs_TC(x_).o.string -#define RDOT_BOOLEAN_VAL(x_) RDOT_lhs_TC(x_).o.boolean -#define RDOT_CODE_STR(x_) rdot_getOpString_T(x_) -#define RDOT_OPCODE_STR(x_) rdot_getOpString(x_) +#define NULL_DOT ((rdot) 0) +#define RDOT_alloc rdot_alloc () +#define RDOT_TYPE(x_) x_->T +#define RDOT_LOCATION(x_) x_->loc +#define RDOT_T_FIELD(x_) x_->FT +#define RDOT_CHAIN(x_) x_->next +#define RDOT_FIELD(x_) x_->field1 +#define RDOT_FIELD2(x_) x_->field2 +#define RDOT_lhs_T(x_) x_->opaT +#define RDOT_rhs_T(x_) x_->opbT +#define RDOT_lhs_TT(x_) x_->opa.t +#define RDOT_rhs_TT(x_) x_->opb.t +#define RDOT_lhs_TC(x_) x_->opa.tc +#define RDOT_rhs_TC(x_) x_->opb.tc +#define RDOT_qual(x_) x_->qual +#define DOT_RETVAL(x_) x_->retval +#define RDOT_MEM_MODIFIER(x_) (&(x_->alloca_modifier)) +#define RDOT_IDENTIFIER_POINTER(x_) RDOT_lhs_TC (x_).o.string +#define RDOT_BOOLEAN_VAL(x_) RDOT_lhs_TC (x_).o.boolean +#define RDOT_CODE_STR(x_) rdot_getOpString_T (x_) +#define RDOT_OPCODE_STR(x_) rdot_getOpString (x_) // destination is cleared before copy // copy a vector (source, destination) -#define RDOT_MMEM_COPY(x_, y_) \ - do { \ - y_->clear(); \ - std::vector<ALLOCA_>::iterator __it; \ - for (__it = x_->begin(); __it != x_->end(); ++__it) \ - y_->push_back(*__it); \ - } while (0) - -extern rdot rdot_alloc(void); -extern void rdot_init(void); -extern rdot rdot_build_decl1(opcode_t, rdot); -extern rdot rdot_build_decl2(opcode_t, rdot, rdot); -extern rdot rdot_build_fndecl(rdot, bool, rdot, rdot, rdot); -extern rdot rdot_build_float(const float); -extern rdot rdot_build_integer(const int); -extern rdot rdot_build_string(const char*); -extern rdot rdot_build_identifier(const char*); -extern rdot rdot_build_bool(bool); -extern rdot rdot_build_varDecl(rdot, bool, rdot); -extern const char* rdot_getOpString(const rdot); -extern const char* rdot_getOpString_T(const opcode_t); +#define RDOT_MMEM_COPY(x_, y_) \ + do { \ + y_->clear (); \ + std::vector<ALLOCA_>::iterator __it; \ + for (__it = x_->begin (); __it != x_->end (); ++__it) \ + y_->push_back (*__it); \ + } while (0) + +extern rdot rdot_alloc (void); +extern void rdot_init (void); +extern rdot rdot_build_decl1 (opcode_t, rdot); +extern rdot rdot_build_decl2 (opcode_t, rdot, rdot); +extern rdot rdot_build_fndecl (rdot, bool, rdot, rdot, rdot); +extern rdot rdot_build_float (const float); +extern rdot rdot_build_integer (const int); +extern rdot rdot_build_string (const char *); +extern rdot rdot_build_identifier (const char *); +extern rdot rdot_build_bool (bool); +extern rdot rdot_build_varDecl (rdot, bool, rdot); +extern const char * rdot_getOpString (const rdot); +extern const char * rdot_getOpString_T (const opcode_t); #endif //__GCC_RDOT_IMPL_H__ diff --git a/gcc/rust/old/rdot-pretty-print.cc b/gcc/rust/old/rdot-pretty-print.cc index 2df5773..51330e3 100644 --- a/gcc/rust/old/rdot-pretty-print.cc +++ b/gcc/rust/old/rdot-pretty-print.cc @@ -19,581 +19,646 @@ static bool _no_infer = false; static bool first = true; -#define RDOT_PREFIX_PRE ".pre-rdot" -#define RDOT_PREFIX_POST ".pst-rdot" - -// Array of type strings? Seems incomplete if it is. Perhaps just parser "primitives"? -static const char* typeStrings[] = { - "bool", - "int", - "float", - "unsigned_int", - "__infer_me", - "__user_struct", - "void" +#define RDOT_PREFIX_PRE ".pre-rdot" +#define RDOT_PREFIX_POST ".pst-rdot" + +static const char * typeStrings [] = { + "bool", + "int", + "float", + "unsigned_int", + "__infer_me", + "__user_struct", + "void" }; -// Seems to determine type of node as per typeStrings array -static char* typeStringNode(const rdot node) { - char buffer[128]; - size_t offset = 0; - if (RDOT_MEM_MODIFIER(node)) { - std::vector<ALLOCA_>::iterator it; - for (it = RDOT_MEM_MODIFIER(node)->begin(); - it != RDOT_MEM_MODIFIER(node)->end(); - ++it) { - switch (*it) { - case ALLOC_HEAP: { - buffer[offset] = '~'; - offset++; - } break; - case ALLOC_REF: { - buffer[offset] = '&'; - offset++; - } break; - case ALLOC_DEREF: { - buffer[offset] = '*'; - offset++; - } break; +static char * +typeStringNode (const rdot node) +{ + char buffer [128]; + size_t offset = 0; + if (RDOT_MEM_MODIFIER (node)) + { + std::vector<ALLOCA_>::iterator it; + for (it = RDOT_MEM_MODIFIER (node)->begin (); + it != RDOT_MEM_MODIFIER (node)->end (); ++it ) + { + switch (*it) + { + case ALLOC_HEAP: + { + buffer [offset] = '~'; + offset++; + } + break; + case ALLOC_REF: + { + buffer [offset] = '&'; + offset++; + } + break; + case ALLOC_DEREF: + { + buffer [offset] = '*'; + offset++; + } + break; } } } - if (node != NULL_DOT) { - switch (RDOT_TYPE(node)) { - case RTYPE_BOOL: - strcpy(buffer + offset, typeStrings[0]); - break; - - case RTYPE_INT: - strcpy(buffer + offset, typeStrings[1]); - break; - - case RTYPE_FLOAT: - strcpy(buffer + offset, typeStrings[2]); - break; - - case RTYPE_UINT: - strcpy(buffer + offset, typeStrings[3]); - break; - - case RTYPE_INFER: { - if (_no_infer) - fatal_error("gcc-rust has failed to infer a type and cannot continue"); - else - strcpy(buffer + offset, typeStrings[4]); - } break; - - case RTYPE_USER_STRUCT: - strcpy(buffer + offset, RDOT_IDENTIFIER_POINTER(RDOT_lhs_TT(node))); - break; - - default: - fatal_error("unhandled type [%s]", RDOT_OPCODE_STR(node)); - break; + if (node != NULL_DOT) + { + switch (RDOT_TYPE (node)) + { + case RTYPE_BOOL: + strcpy (buffer+offset, typeStrings [0]); + break; + + case RTYPE_INT: + strcpy (buffer+offset, typeStrings [1]); + break; + + case RTYPE_FLOAT: + strcpy (buffer+offset, typeStrings [2]); + break; + + case RTYPE_UINT: + strcpy (buffer+offset, typeStrings [3]); + break; + + case RTYPE_INFER: + { + if (_no_infer) + fatal_error ("gcc-rust has failed to infer a type and cannot continue"); + else + strcpy (buffer+offset, typeStrings [4]); + } + break; + + case RTYPE_USER_STRUCT: + strcpy (buffer+offset, RDOT_IDENTIFIER_POINTER (RDOT_lhs_TT (node))); + break; + + default: + fatal_error ("unhandled type [%s]", RDOT_OPCODE_STR (node)); + break; } } - return xstrdup(buffer); + return xstrdup (buffer); } -static void dot_pass_dump_node(FILE*, rdot, size_t); -static void dot_pass_dump_method(FILE*, rdot, size_t); -static void dot_pass_dump_struct(FILE*, rdot, size_t); - -static void dot_pass_dumpPrimitive(FILE*, rdot); -static void dot_pass_dumpExprNode(FILE*, rdot); -static void dot_pass_dump_expr(FILE*, rdot); - -// Seems to dump struct at node to file fd -static void dot_pass_dump_struct(FILE* fd, rdot node, size_t indents) { - size_t i; - for (i = 0; i < indents; ++i) - fprintf(fd, " "); - - rdot ident = RDOT_lhs_TT(node); - rdot layout = RDOT_rhs_TT(node); - - fprintf(fd, "struct %s {\n", RDOT_IDENTIFIER_POINTER(ident)); - rdot next; - for (next = layout; next != NULL_DOT; next = RDOT_CHAIN(next)) { - gcc_assert(RDOT_TYPE(next) = D_PARAMETER); - const char* id = RDOT_IDENTIFIER_POINTER(RDOT_lhs_TT(next)); - const char* typestr = typeStringNode(RDOT_rhs_TT(next)); - - for (i = 0; i < (indents + 1); ++i) - fprintf(fd, " "); - fprintf(fd, "%s %s;\n", typestr, id); +static void dot_pass_dump_node (FILE *, rdot, size_t); +static void dot_pass_dump_method (FILE *, rdot, size_t); +static void dot_pass_dump_struct (FILE *, rdot, size_t); + +static void dot_pass_dumpPrimitive (FILE *, rdot); +static void dot_pass_dumpExprNode (FILE *, rdot); +static void dot_pass_dump_expr (FILE *, rdot); + +static +void dot_pass_dump_struct (FILE * fd, rdot node, size_t indents) +{ + size_t i; + for (i = 0; i < indents; ++i) + fprintf (fd, " "); + + rdot ident = RDOT_lhs_TT (node); + rdot layout = RDOT_rhs_TT (node); + + fprintf (fd, "struct %s {\n", RDOT_IDENTIFIER_POINTER (ident)); + rdot next; + for (next = layout; next != NULL_DOT; next = RDOT_CHAIN (next)) + { + gcc_assert (RDOT_TYPE (next) = D_PARAMETER); + const char * id = RDOT_IDENTIFIER_POINTER (RDOT_lhs_TT (next)); + const char * typestr = typeStringNode (RDOT_rhs_TT (next)); + + for (i = 0; i < (indents + 1); ++i) + fprintf (fd, " "); + fprintf (fd, "%s %s;\n", typestr, id); } - for (i = 0; i < indents; ++i) - fprintf(fd, " "); - fprintf(fd, "}\n"); + for (i = 0; i < indents; ++i) + fprintf (fd, " "); + fprintf (fd, "}\n"); } -// Seems to dump method at node to file fd -static void dot_pass_dump_method(FILE* fd, rdot node, size_t indents) { - size_t i; - for (i = 0; i < indents; ++i) - fprintf(fd, " "); - - const char* method_id = RDOT_IDENTIFIER_POINTER(RDOT_FIELD(node)); - char* rtype = NULL; - if (RDOT_FIELD2(node)) - rtype = typeStringNode(RDOT_FIELD2(node)); - else - rtype = xstrdup("void"); - rdot parameters = RDOT_lhs_TT(node); - - if (DOT_RETVAL(node)) - fprintf(fd, "pub fn %s ( ", method_id); - else - fprintf(fd, "fn %s ( ", method_id); - - if (parameters == NULL_DOT) - fprintf(fd, "void"); - else { - rdot next; - for (next = parameters; next != NULL_DOT; next = RDOT_CHAIN(next)) { - gcc_assert(RDOT_TYPE(next) = D_PARAMETER); - bool iself = false; - bool muta = RDOT_qual(next); - const char* id = RDOT_IDENTIFIER_POINTER(RDOT_lhs_TT(next)); - - if (strcmp(id, "self") == 0) - iself = true; - - const char* smuta; - if (muta) { - smuta = "mut"; - } else { - smuta = "final"; - } - - if (iself) - fprintf(fd, "[%s] _self_", smuta); - else { - const char* typestr = typeStringNode(RDOT_rhs_TT(next)); - fprintf(fd, "[%s] %s:%s", smuta, typestr, id); - } - if (RDOT_CHAIN(next) != NULL_DOT) - fprintf(fd, ", "); +static +void dot_pass_dump_method (FILE * fd, rdot node, size_t indents) +{ + size_t i; + for (i = 0; i < indents; ++i) + fprintf (fd, " "); + + const char * method_id = RDOT_IDENTIFIER_POINTER (RDOT_FIELD (node)); + char * rtype = NULL; + if (RDOT_FIELD2 (node)) + rtype = typeStringNode (RDOT_FIELD2 (node)); + else + rtype = xstrdup ("void"); + rdot parameters = RDOT_lhs_TT (node); + + if (DOT_RETVAL (node)) + fprintf (fd, "pub fn %s ( ", method_id); + else + fprintf (fd, "fn %s ( ", method_id); + + if (parameters == NULL_DOT) + fprintf (fd, "void"); + else + { + rdot next; + for (next = parameters; next != NULL_DOT; next = RDOT_CHAIN (next)) + { + gcc_assert (RDOT_TYPE (next) = D_PARAMETER); + bool iself = false; + bool muta = RDOT_qual (next); + const char * id = RDOT_IDENTIFIER_POINTER (RDOT_lhs_TT (next)); + + if (strcmp (id, "self") == 0) + iself = true; + + const char *smuta; + if (muta) { + smuta = "mut"; + } + else { + smuta = "final"; + } + + if (iself) + fprintf (fd, "[%s] _self_", smuta); + else + { + const char * typestr = typeStringNode (RDOT_rhs_TT (next)); + fprintf (fd, "[%s] %s:%s", smuta, typestr, id); + } + if (RDOT_CHAIN (next) != NULL_DOT) + fprintf (fd, ", "); } } - fprintf(fd, " ) -> %s {\n", rtype); - free(rtype); - - rdot suite; - for (suite = RDOT_rhs_TT(node); suite != NULL_DOT; suite = RDOT_CHAIN(suite)) { - dot_pass_dump_node(fd, suite, indents + 1); - fprintf(fd, "\n"); + fprintf (fd, " ) -> %s {\n", rtype); + free (rtype); + + rdot suite; + for (suite = RDOT_rhs_TT (node); suite != NULL_DOT; suite = RDOT_CHAIN (suite)) + { + dot_pass_dump_node (fd, suite, indents + 1); + fprintf (fd, "\n"); } - for (i = 0; i < indents; ++i) - fprintf(fd, " "); - fprintf(fd, "}\n"); + for (i = 0; i < indents; ++i) + fprintf (fd, " "); + fprintf (fd, "}\n"); } -// Dumps primitive at RDOT_lhs_TC(node) to inputted file -static void dot_pass_dumpPrimitive(FILE* fd, rdot node) { - /* Handle other primitive literal types here ... */ - switch (RDOT_lhs_TC(node).T) { - case D_T_INTEGER: - fprintf(fd, "%i", RDOT_lhs_TC(node).o.integer); - break; - - case D_T_FLOAT: - fprintf(fd, "%f", RDOT_lhs_TC(node).o.ffloat); - break; - - case D_T_STRING: - fprintf(fd, "\"%s\"", RDOT_lhs_TC(node).o.string); - break; - - default: - fatal_error("Unable to dump primitive [%s]", - rdot_getOpString_T(RDOT_lhs_TC(node).T)); - break; +static +void dot_pass_dumpPrimitive (FILE * fd, rdot node) +{ + /* Handle other primitive literal types here ... */ + switch (RDOT_lhs_TC (node).T) + { + case D_T_INTEGER: + fprintf (fd, "%i", RDOT_lhs_TC (node).o.integer); + break; + + case D_T_FLOAT: + fprintf (fd, "%f", RDOT_lhs_TC (node).o.ffloat); + break; + + case D_T_STRING: + fprintf (fd, "\"%s\"", RDOT_lhs_TC (node).o.string); + break; + + default: + fatal_error ("Unable to dump primitive [%s]", + rdot_getOpString_T (RDOT_lhs_TC (node).T)); + break; } } -// Dumps expression node to file fd. (this includes a lot of stuff, such as dumping expression itself) -static void dot_pass_dumpExprNode(FILE* fd, rdot node) { - if (RDOT_MEM_MODIFIER(node)) { - std::vector<ALLOCA_>::iterator it; - for (it = RDOT_MEM_MODIFIER(node)->begin(); - it != RDOT_MEM_MODIFIER(node)->end(); - ++it) { - switch (*it) { - case ALLOC_DEREF: - fprintf(fd, "*"); - break; - case ALLOC_HEAP: - fprintf(fd, "~"); - break; - case ALLOC_REF: - fprintf(fd, "&"); - break; +static +void dot_pass_dumpExprNode (FILE * fd, rdot node) +{ + if (RDOT_MEM_MODIFIER (node)) + { + std::vector<ALLOCA_>::iterator it; + for (it = RDOT_MEM_MODIFIER (node)->begin (); + it != RDOT_MEM_MODIFIER (node)->end (); ++it ) + { + switch (*it) + { + case ALLOC_DEREF: + fprintf (fd, "*"); + break; + case ALLOC_HEAP: + fprintf (fd, "~"); + break; + case ALLOC_REF: + fprintf (fd, "&"); + break; } } } - switch (RDOT_TYPE(node)) { - case D_PRIMITIVE: - dot_pass_dumpPrimitive(fd, node); - break; - - case D_IDENTIFIER: - fprintf(fd, "%s", RDOT_IDENTIFIER_POINTER(node)); - break; - - case D_BOOLEAN: { - bool val = RDOT_BOOLEAN_VAL(node); - if (val) - fprintf(fd, "true"); - else - fprintf(fd, "false"); - } break; - - case D_CALL_EXPR: { - rdot id = RDOT_lhs_TT(node); - dot_pass_dump_expr(fd, id); - fprintf(fd, " ("); - - rdot p; - for (p = RDOT_rhs_TT(node); p != NULL_DOT; p = RDOT_CHAIN(p)) { - dot_pass_dump_expr(fd, p); - if (RDOT_CHAIN(p) != NULL_DOT) - fprintf(fd, ", "); - } - fprintf(fd, ")"); - } break; - - case D_VAR_DECL: { - const char* mut; - if (RDOT_qual(node)) - mut = "_final_"; - else - mut = "_mut_"; - - fprintf(fd, "let [%s] ", mut); - dot_pass_dumpExprNode(fd, RDOT_lhs_TT(node)); - fprintf(fd, " -> [%s]", typeStringNode(RDOT_rhs_TT(node))); - } break; - - case D_STRUCT_INIT: { - rdot ident = RDOT_lhs_TT(node); - rdot init = RDOT_rhs_TT(node); - - fprintf(fd, "%s { ", RDOT_IDENTIFIER_POINTER(ident)); - rdot next; - for (next = init; next != NULL_DOT; next = RDOT_CHAIN(next)) { - gcc_assert(RDOT_TYPE(next) == D_STRUCT_PARAM); - const char* name = RDOT_IDENTIFIER_POINTER(RDOT_lhs_TT(next)); - - fprintf(fd, "%s:(", name); - dot_pass_dump_expr(fd, RDOT_rhs_TT(next)); - fprintf(fd, ")"); - if (RDOT_CHAIN(next) != NULL_DOT) - fprintf(fd, ", "); - } - fprintf(fd, " }"); - } break; - - default: - error("unhandled dumpExprNode [%s]\n", RDOT_OPCODE_STR(node)); - break; + switch (RDOT_TYPE (node)) + { + case D_PRIMITIVE: + dot_pass_dumpPrimitive (fd, node); + break; + + case D_IDENTIFIER: + fprintf (fd, "%s", RDOT_IDENTIFIER_POINTER (node)); + break; + + case D_BOOLEAN: + { + bool val = RDOT_BOOLEAN_VAL (node); + if (val) + fprintf (fd, "true"); + else + fprintf (fd, "false"); + } + break; + + case D_CALL_EXPR: + { + rdot id = RDOT_lhs_TT (node); + dot_pass_dump_expr (fd, id); + fprintf (fd, " ("); + + rdot p; + for (p = RDOT_rhs_TT (node); p != NULL_DOT; p = RDOT_CHAIN (p)) + { + dot_pass_dump_expr (fd, p); + if (RDOT_CHAIN (p) != NULL_DOT) + fprintf (fd, ", "); + } + fprintf (fd, ")"); + } + break; + + case D_VAR_DECL: + { + const char * mut; + if (RDOT_qual (node)) + mut = "_final_"; + else + mut = "_mut_"; + + fprintf (fd, "let [%s] ", mut); + dot_pass_dumpExprNode (fd, RDOT_lhs_TT (node)); + fprintf (fd, " -> [%s]", typeStringNode (RDOT_rhs_TT (node))); + } + break; + + case D_STRUCT_INIT: + { + rdot ident = RDOT_lhs_TT (node); + rdot init = RDOT_rhs_TT (node); + + fprintf (fd, "%s { ", RDOT_IDENTIFIER_POINTER (ident)); + rdot next; + for (next = init; next != NULL_DOT; next = RDOT_CHAIN (next)) + { + gcc_assert (RDOT_TYPE (next) == D_STRUCT_PARAM); + const char * name = RDOT_IDENTIFIER_POINTER (RDOT_lhs_TT (next)); + + fprintf (fd, "%s:(", name); + dot_pass_dump_expr (fd, RDOT_rhs_TT (next)); + fprintf (fd, ")"); + if (RDOT_CHAIN (next) != NULL_DOT) + fprintf (fd, ", "); + } + fprintf (fd, " }"); + } + break; + + default: + error ("unhandled dumpExprNode [%s]\n", RDOT_OPCODE_STR (node)); + break; } } -// Seems to dump expression to file fd -static void dot_pass_dump_expr(FILE* fd, rdot node) { - if (DOT_RETVAL(node)) { - fprintf(fd, "[_rust_retval]: "); - } - - switch (RDOT_TYPE(node)) { - case D_PRIMITIVE: - case D_IDENTIFIER: - case D_CALL_EXPR: - case D_BOOLEAN: - case D_VAR_DECL: - case D_STRUCT_INIT: - dot_pass_dumpExprNode(fd, node); +static +void dot_pass_dump_expr (FILE * fd, rdot node) +{ + if (DOT_RETVAL (node)) { + fprintf (fd, "[_rust_retval]: "); + } + + switch (RDOT_TYPE (node)) + { + case D_PRIMITIVE: + case D_IDENTIFIER: + case D_CALL_EXPR: + case D_BOOLEAN: + case D_VAR_DECL: + case D_STRUCT_INIT: + dot_pass_dumpExprNode (fd, node); + break; + + default: + { + /* print expr tree ... */ + rdot lhs = RDOT_lhs_TT (node); + rdot rhs = RDOT_rhs_TT (node); + + dot_pass_dump_expr (fd, lhs); + switch (RDOT_TYPE (node)) + { + case D_MODIFY_EXPR: + fprintf (fd, " = "); break; - default: { - /* print expr tree ... */ - rdot lhs = RDOT_lhs_TT(node); - rdot rhs = RDOT_rhs_TT(node); - - dot_pass_dump_expr(fd, lhs); - switch (RDOT_TYPE(node)) { - case D_MODIFY_EXPR: - fprintf(fd, " = "); - break; - - case D_ADD_EXPR: - fprintf(fd, " + "); - break; - - case D_MINUS_EXPR: - fprintf(fd, " - "); - break; - - case D_MULT_EXPR: - fprintf(fd, " * "); - break; + case D_ADD_EXPR: + fprintf (fd, " + "); + break; - case D_LESS_EXPR: - fprintf(fd, " < "); - break; + case D_MINUS_EXPR: + fprintf (fd, " - "); + break; - case D_LESS_EQ_EXPR: - fprintf(fd, " <= "); - break; + case D_MULT_EXPR: + fprintf (fd, " * "); + break; - case D_GREATER_EXPR: - fprintf(fd, " > "); - break; + case D_LESS_EXPR: + fprintf (fd, " < "); + break; - case D_GREATER_EQ_EXPR: - fprintf(fd, " >= "); - break; + case D_LESS_EQ_EXPR: + fprintf (fd, " <= "); + break; + + case D_GREATER_EXPR: + fprintf (fd, " > "); + break; - case D_EQ_EQ_EXPR: - fprintf(fd, " == "); - break; + case D_GREATER_EQ_EXPR: + fprintf (fd, " >= "); + break; - case D_NOT_EQ_EXPR: - fprintf(fd, " != "); - break; + case D_EQ_EQ_EXPR: + fprintf (fd, " == "); + break; - case D_ATTRIB_REF: - fprintf(fd, "."); - break; + case D_NOT_EQ_EXPR: + fprintf (fd, " != "); + break; + + case D_ATTRIB_REF: + fprintf (fd, "."); + break; - case D_ACC_EXPR: - fprintf(fd, "::"); - break; + case D_ACC_EXPR: + fprintf (fd, "::"); + break; - default: - fatal_error("unhandled dump [%s]!\n", RDOT_OPCODE_STR(node)); - break; - } - dot_pass_dump_expr(fd, rhs); - } break; + default: + fatal_error ("unhandled dump [%s]!\n", RDOT_OPCODE_STR (node)); + break; + } + dot_pass_dump_expr (fd, rhs); + } + break; } } -// Seems to dump rust "enum" to file fd -static void dot_pass_dump_enum(FILE* fd, rdot node, size_t indents) { - rdot enum_id = RDOT_lhs_TT(node); - rdot enum_layout = RDOT_rhs_TT(node); - - size_t i; - for (i = 0; i < indents; ++i) - fprintf(fd, " "); - const char* id = RDOT_IDENTIFIER_POINTER(enum_id); - fprintf(fd, "enum %s {\n", id); - - indents++; - rdot next; - for (next = enum_layout; next != NULL_DOT; next = RDOT_CHAIN(next)) { - for (i = 0; i < indents; ++i) - fprintf(fd, " "); - const char* enumit = RDOT_IDENTIFIER_POINTER(next); - fprintf(fd, "[%s],\n", enumit); +static +void dot_pass_dump_enum (FILE * fd, rdot node, size_t indents) +{ + rdot enum_id = RDOT_lhs_TT (node); + rdot enum_layout = RDOT_rhs_TT (node); + + size_t i; + for (i = 0; i < indents; ++i) + fprintf (fd, " "); + const char * id = RDOT_IDENTIFIER_POINTER (enum_id); + fprintf (fd, "enum %s {\n", id); + + indents++; + rdot next; + for (next = enum_layout; next != NULL_DOT; next = RDOT_CHAIN (next)) + { + for (i = 0; i < indents; ++i) + fprintf (fd, " "); + const char *enumit = RDOT_IDENTIFIER_POINTER (next); + fprintf (fd, "[%s],\n", enumit); } - indents--; + indents--; - for (i = 0; i < indents; ++i) - fprintf(fd, " "); - fprintf(fd, "}\n"); + for (i = 0; i < indents; ++i) + fprintf (fd, " "); + fprintf (fd, "}\n"); } -// Seems to dump conditional to file fd -static void dot_pass_dump_cond(FILE* fd, rdot node, size_t indents) { - size_t i; - rdot ifb = RDOT_lhs_TT(node); - rdot elb = RDOT_rhs_TT(node); - - gcc_assert(RDOT_TYPE(ifb) == D_STRUCT_IF); - - for (i = 0; i < indents; ++i) - fprintf(fd, " "); - - fprintf(fd, "if ("); - dot_pass_dump_expr(fd, RDOT_lhs_TT(ifb)); - fprintf(fd, ") {\n"); - - rdot next; - for (next = RDOT_rhs_TT(ifb); next != NULL_DOT; next = RDOT_CHAIN(next)) { - dot_pass_dump_node(fd, next, indents + 1); - fprintf(fd, "\n"); +static +void dot_pass_dump_cond (FILE * fd, rdot node, size_t indents) +{ + size_t i; + rdot ifb = RDOT_lhs_TT (node); + rdot elb = RDOT_rhs_TT (node); + + gcc_assert (RDOT_TYPE (ifb) == D_STRUCT_IF); + + for (i = 0; i < indents; ++i) + fprintf (fd, " "); + + fprintf (fd, "if ("); + dot_pass_dump_expr (fd, RDOT_lhs_TT (ifb)); + fprintf (fd, ") {\n"); + + rdot next; + for (next = RDOT_rhs_TT (ifb) ; next != NULL_DOT; next = RDOT_CHAIN (next)) + { + dot_pass_dump_node (fd, next, indents + 1); + fprintf (fd, "\n"); } - for (i = 0; i < indents; ++i) - fprintf(fd, " "); - fprintf(fd, "}"); - - if (elb != NULL_DOT) { - fprintf(fd, " else {\n"); - for (next = RDOT_lhs_TT(elb); next != NULL_DOT; next = RDOT_CHAIN(next)) { - dot_pass_dump_node(fd, next, indents + 1); - fprintf(fd, "\n"); - } - for (i = 0; i < indents; ++i) - fprintf(fd, " "); - fprintf(fd, "}\n"); + for (i = 0; i < indents; ++i) + fprintf (fd, " "); + fprintf (fd, "}"); + + if (elb != NULL_DOT) + { + fprintf (fd, " else {\n"); + for (next = RDOT_lhs_TT (elb); next != NULL_DOT; next = RDOT_CHAIN (next)) + { + dot_pass_dump_node (fd, next, indents + 1); + fprintf (fd, "\n"); + } + for (i = 0; i < indents; ++i) + fprintf (fd, " "); + fprintf (fd, "}\n"); } } -// Seems to dump break to file fd -static void dot_pass_dump_break(FILE* fd, const rdot node, size_t indents) { - size_t i; - for (i = 0; i < indents; ++i) - fprintf(fd, " "); - fprintf(fd, "break;"); +static +void dot_pass_dump_break (FILE * fd, const rdot node, size_t indents) +{ + size_t i; + for (i = 0; i < indents; ++i) + fprintf (fd, " "); + fprintf (fd, "break;"); } -// Seems to dump loop construct to file fd -static void dot_pass_dump_loop(FILE* fd, const rdot node, size_t indents) { - const rdot suite = RDOT_lhs_TT(node); - size_t i; - for (i = 0; i < indents; ++i) - fprintf(fd, " "); - fprintf(fd, "loop {\n"); - - rdot next; - for (next = suite; next != NULL_DOT; next = RDOT_CHAIN(next)) { - dot_pass_dump_node(fd, next, indents + 1); - fprintf(fd, "\n"); +static +void dot_pass_dump_loop (FILE * fd, const rdot node, size_t indents) +{ + const rdot suite = RDOT_lhs_TT (node); + size_t i; + for (i = 0; i < indents; ++i) + fprintf (fd, " "); + fprintf (fd, "loop {\n"); + + rdot next; + for (next = suite; next != NULL_DOT; next = RDOT_CHAIN (next)) + { + dot_pass_dump_node (fd, next, indents + 1); + fprintf (fd, "\n"); } - - for (i = 0; i < indents; ++i) - fprintf(fd, " "); - fprintf(fd, "}\n"); + + for (i = 0; i < indents; ++i) + fprintf (fd, " "); + fprintf (fd, "}\n"); } -// Seems to dump while to file fd -static void dot_pass_dump_while(FILE* fd, const rdot node, size_t indents) { - size_t i; - rdot expr = RDOT_lhs_TT(node); - rdot suite = RDOT_rhs_TT(node); - - for (i = 0; i < indents; ++i) - fprintf(fd, " "); - fprintf(fd, "while ("); - dot_pass_dump_expr(fd, expr); - fprintf(fd, ") {\n"); - - rdot next; - for (next = suite; next != NULL_DOT; next = RDOT_CHAIN(next)) { - dot_pass_dump_node(fd, next, indents + 1); - fprintf(fd, "\n"); +static +void dot_pass_dump_while (FILE * fd, const rdot node, size_t indents) +{ + size_t i; + rdot expr = RDOT_lhs_TT (node); + rdot suite = RDOT_rhs_TT (node); + + for (i = 0; i < indents; ++i) + fprintf (fd, " "); + fprintf (fd, "while ("); + dot_pass_dump_expr (fd, expr); + fprintf (fd, ") {\n"); + + rdot next; + for (next = suite; next != NULL_DOT; next = RDOT_CHAIN (next)) + { + dot_pass_dump_node (fd, next, indents + 1); + fprintf (fd, "\n"); } - for (i = 0; i < indents; ++i) - fprintf(fd, " "); - fprintf(fd, "}"); + for (i = 0; i < indents; ++i) + fprintf (fd, " "); + fprintf (fd, "}"); } -// Seems to dump impl block to file fd -static void dot_pass_dump_impl(FILE* fd, rdot node, size_t indents) { - const char* implid = RDOT_IDENTIFIER_POINTER(RDOT_lhs_TT(node)); - fprintf(fd, "impl %s {\n", implid); - - rdot next; - for (next = RDOT_rhs_TT(node); next != NULL_DOT; next = RDOT_CHAIN(next)) { - dot_pass_dump_node(fd, next, indents + 1); - fprintf(fd, "\n"); +static +void dot_pass_dump_impl (FILE * fd, rdot node, size_t indents) +{ + const char * implid = RDOT_IDENTIFIER_POINTER (RDOT_lhs_TT (node)); + fprintf (fd, "impl %s {\n", implid); + + rdot next; + for (next = RDOT_rhs_TT (node); next != NULL_DOT; next = RDOT_CHAIN (next)) + { + dot_pass_dump_node (fd, next, indents + 1); + fprintf (fd, "\n"); } - fprintf(fd, "}\n"); + fprintf (fd, "}\n"); } -// Seems to be a selector that dumps a node of a given type to file fd - switches between them -static void dot_pass_dump_node(FILE* fd, rdot node, size_t indents) { - if (RDOT_T_FIELD(node) == D_D_EXPR) { - size_t i; - for (i = 0; i < indents; ++i) - fprintf(fd, " "); - dot_pass_dump_expr(fd, node); - fprintf(fd, ";"); - } else { - switch (RDOT_TYPE(node)) { - case D_PRIMITIVE: - dot_pass_dump_expr(fd, node); - break; - - case D_STRUCT_IMPL: - dot_pass_dump_impl(fd, node, indents); - break; - - case D_STRUCT_METHOD: - dot_pass_dump_method(fd, node, indents); - break; - - case D_STRUCT_TYPE: - dot_pass_dump_struct(fd, node, indents); - break; - - case D_STRUCT_ENUM: - dot_pass_dump_enum(fd, node, indents); - break; - - case D_STRUCT_IF: - dot_pass_dump_cond(fd, node, indents); - break; - - case D_STRUCT_WHILE: - dot_pass_dump_while(fd, node, indents); - break; - - case D_STRUCT_LOOP: - dot_pass_dump_loop(fd, node, indents); - break; - - case C_BREAK_STMT: - dot_pass_dump_break(fd, node, indents); - break; - - default: - error("unhandled node [%s]\n", RDOT_OPCODE_STR(node)); - break; +static +void dot_pass_dump_node (FILE * fd, rdot node, size_t indents) +{ + if (RDOT_T_FIELD (node) == D_D_EXPR) + { + size_t i; + for (i = 0; i < indents; ++i) + fprintf (fd, " "); + dot_pass_dump_expr (fd, node); + fprintf (fd, ";"); + } + else + { + switch (RDOT_TYPE (node)) + { + case D_PRIMITIVE: + dot_pass_dump_expr (fd, node); + break; + + case D_STRUCT_IMPL: + dot_pass_dump_impl (fd, node, indents); + break; + + case D_STRUCT_METHOD: + dot_pass_dump_method (fd, node, indents); + break; + + case D_STRUCT_TYPE: + dot_pass_dump_struct (fd, node, indents); + break; + + case D_STRUCT_ENUM: + dot_pass_dump_enum (fd, node, indents); + break; + + case D_STRUCT_IF: + dot_pass_dump_cond (fd, node, indents); + break; + + case D_STRUCT_WHILE: + dot_pass_dump_while (fd, node, indents); + break; + + case D_STRUCT_LOOP: + dot_pass_dump_loop (fd, node, indents); + break; + + case C_BREAK_STMT: + dot_pass_dump_break (fd, node, indents); + break; + + default: + error ("unhandled node [%s]\n", RDOT_OPCODE_STR (node)); + break; } } } -// Seems to be main entry point into dumping - dumps all decls to file -vec<rdot, va_gc>* dot_pass_PrettyPrint(vec<rdot, va_gc>* decls) { - if (GRS_OPT_dump_dot) { - size_t bsize = 128; - char* outfile = (char*)alloca(bsize); - gcc_assert(outfile); - memset(outfile, 0, bsize); - - strncpy(outfile, GRS_current_infile, strlen(GRS_current_infile)); - if (first == true) { - strncat(outfile, RDOT_PREFIX_PRE, sizeof(RDOT_PREFIX_PRE)); - first = false; - } else { - strncat(outfile, RDOT_PREFIX_POST, sizeof(RDOT_PREFIX_POST)); - _no_infer = true; +vec<rdot,va_gc> * dot_pass_PrettyPrint (vec<rdot,va_gc> * decls) +{ + if (GRS_OPT_dump_dot) + { + size_t bsize = 128; + char * outfile = (char *) alloca (bsize); + gcc_assert (outfile); + memset (outfile, 0, bsize); + + strncpy (outfile, GRS_current_infile, strlen (GRS_current_infile)); + if (first == true) + { + strncat (outfile, RDOT_PREFIX_PRE, sizeof (RDOT_PREFIX_PRE)); + first = false; + } + else + { + strncat (outfile, RDOT_PREFIX_POST, sizeof (RDOT_PREFIX_POST)); + _no_infer = true; } - FILE* fd = fopen(outfile, "w"); - if (!fd) { - error("Unable to open %s for write\n", outfile); - goto exit; + FILE * fd = fopen (outfile, "w"); + if (!fd) + { + error ("Unable to open %s for write\n", outfile); + goto exit; } - rdot idtx = NULL_DOT; - size_t i; - for (i = 0; decls->iterate(i, &idtx); ++i) { - dot_pass_dump_node(fd, idtx, 0); - fprintf(fd, "\n"); + rdot idtx = NULL_DOT; + size_t i; + for (i = 0; decls->iterate (i, &idtx); ++i) + { + dot_pass_dump_node (fd, idtx, 0); + fprintf (fd, "\n"); } - fclose(fd); + fclose (fd); } -exit: - return decls; + exit: + return decls; } diff --git a/gcc/rust/old/rs-lexer.l b/gcc/rust/old/rs-lexer.l index 6ad4515..b45f931 100644 --- a/gcc/rust/old/rs-lexer.l +++ b/gcc/rust/old/rs-lexer.l @@ -137,24 +137,25 @@ for { return FOR; } %% -bool grs_do_compile(const char * in) { +bool grs_do_compile (const char * in) +{ bool retval = true; - FILE * fd = fopen(in, "rb"); - - if (fd) { - yyin = fd; - + FILE * fd = fopen (in, "rb"); + if (fd) + { + yyin = fd; // yydebug = 1; - linemap_add(line_table, LC_ENTER, 0, in, 0); - retval = yyparse(); - fclose (fd); - linemap_add(line_table, LC_LEAVE, 0, NULL, 0); - yylex_destroy(); - } else { - fprintf(stderr, "error opening file %s\n", in); - retval = false; + linemap_add (line_table, LC_ENTER, 0, in, 0); + retval = yyparse (); + fclose (fd); + linemap_add (line_table, LC_LEAVE, 0, NULL, 0); + yylex_destroy (); + } + else + { + fprintf (stderr, "error opening file %s\n", in); + retval = false; } - return retval; } diff --git a/gcc/rust/old/rs-parser.cc b/gcc/rust/old/rs-parser.cc index 5a7a08c..c3c8c2c 100644 --- a/gcc/rust/old/rs-parser.cc +++ b/gcc/rust/old/rs-parser.cc @@ -6,751 +6,833 @@ static int sym; static int __yyerror; extern int yylineno; -static void yyerror(const char*, ...); -extern int yylex(void); -static bool __yyaccept__(int, bool); -static bool yyexpect(int); +static void yyerror (const char *, ...); +extern int yylex (void); +static bool __yyaccept__ (int, bool); +static bool yyexpect (int); #ifdef _DEBUG -#define yylex_() \ - yylex(); \ - do { \ - char* __token = yytoken_string(sym); \ - printf("[%i:%s]\n", sym, __token); \ - free(__token); \ - } while (0) +# define yylex_() \ + yylex (); \ + do { \ + char *__token = yytoken_string (sym); \ + printf ("[%i:%s]\n", sym, __token); \ + free (__token); \ + } while (0) #else -#define yylex_() yylex() +# define yylex_() yylex () #endif -static std::vector<ALLOCA_>* alloca_modifiers(void); - -static rdot type(void); -static rdot target(void); -static rdot suite(void); -static rdot else_block(void); -static rdot elif_block(void); -static rdot if_block(void); -static rdot struct_conditional(void); -static rdot primary(void); -static rdot factor1(void); -static rdot factor2(void); -static rdot expression(void); - -static vec<rdot, va_gc>* symStack; -static const char* token_strings[] = { - "impl", - "as", - "break", - "continue", - "do", - "fn", - "let", - "mut", - "loop", - "static", - "->", - "bool", - "int", - "uint", - "float", - "::", - "enum", - "==", - "!=", - "<", - ">", - "<=", - ">=", - "struct", - "while", - "if", - "else", - "self", - "match", - "=>", - "true", - "false", - "string_literal", - "identifier", - "integer", - "pub", - "for", - "trait", - "else if", - "float", - "unknown" +static std::vector<ALLOCA_> * alloca_modifiers (void); + +static rdot type (void); +static rdot target (void); +static rdot suite (void); +static rdot else_block (void); +static rdot elif_block (void); +static rdot if_block (void); +static rdot struct_conditional (void); +static rdot primary (void); +static rdot factor1 (void); +static rdot factor2 (void); +static rdot expression (void); + +static vec<rdot, va_gc> * symStack; +static const char * token_strings [] = { + "impl", + "as", + "break", + "continue", + "do", + "fn", + "let", + "mut", + "loop", + "static", + "->", + "bool", + "int", + "uint", + "float", + "::", + "enum", + "==", + "!=", + "<", + ">", + "<=", + ">=", + "struct", + "while", + "if", + "else", + "self", + "match", + "=>", + "true", + "false", + "string_literal", + "identifier", + "integer", + "pub", + "for", + "trait", + "else if", + "float", + "unknown" }; -static char* -yytoken_string(int token) { - char retval[128]; - memset(retval, 0, 128); - if (token >= 258 && token <= 298) - strncpy(retval, token_strings[token - 258 - 1], 128); - else - retval[0] = (char)token; - return xstrdup(retval); -} - -#define yyaccept(_X) __yyaccept__(_X, true) -#define yyaccept_(_X) __yyaccept__(_X, false) -static bool __yyaccept__(int s, bool forward) { - if (sym == s) { - if (forward) { - sym = yylex_(); +static char * +yytoken_string (int token) +{ + char retval [128]; + memset (retval, 0, 128); + if (token >= 258 && token <= 298) + strncpy (retval, token_strings [token-258-1], 128); + else + retval [0] = (char) token; + return xstrdup (retval); +} + +#define yyaccept(_X) __yyaccept__ (_X, true) +#define yyaccept_(_X) __yyaccept__ (_X, false) +static +bool __yyaccept__ (int s, bool forward) +{ + if (sym == s) + { + if (forward) + { + sym = yylex_ (); } - return true; + return true; } - return false; -} - -static bool yyexpect(int s) { - bool retval = false; - if (yyaccept(s) == true) - retval = true; - else { - char* e1 = yytoken_string(s); - char* e2 = yytoken_string(sym); - yyerror("expected [%s] got [%s]", e1, e2); - free(e1); - free(e2); + return false; +} + +static +bool yyexpect (int s) +{ + bool retval = false; + if (yyaccept (s) == true) + retval = true; + else + { + char * e1 = yytoken_string (s); + char * e2 = yytoken_string (sym); + yyerror ("expected [%s] got [%s]", e1, e2); + free (e1); + free (e2); } - return retval; + return retval; } /* Also realy need to make use of location_t and gcc diagnostics .. */ /* this is really hacky but its ok for now really need to fix this though */ -static void __attribute__((format(printf, 1, 2))) -yyerror(const char* fmt, ...) { - __yyerror += 1; - char* buffer = (char*)alloca(512); - memset(buffer, 0, 512); - - va_list vl; - va_start(vl, fmt); - vsprintf(buffer, fmt, vl); - va_end(vl); - - char* buffer_message = (char*)alloca(512); - memset(buffer_message, 0, 512); - snprintf(buffer_message, 512, "syntax error at %i: [%s]", yylineno, buffer); - - fatal_error("%s", buffer_message); -} - -std::vector<ALLOCA_>* alloca_modifiers(void) { - std::vector<ALLOCA_>* allocas = new std::vector<ALLOCA_>; - while (sym == '~' || sym == '&' || sym == '*') { - ALLOCA_ mod; - switch (sym) { - case '~': - mod = ALLOC_HEAP; - break; - case '&': - mod = ALLOC_REF; - break; - case '*': - mod = ALLOC_DEREF; - break; - default: - break; +static void __attribute__ ((format (printf, 1, 2))) +yyerror (const char * fmt, ...) +{ + __yyerror += 1; + char * buffer = (char *) alloca (512); + memset (buffer, 0, 512); + + va_list vl; + va_start (vl, fmt); + vsprintf (buffer, fmt, vl); + va_end (vl); + + char * buffer_message = (char *) alloca (512); + memset (buffer_message, 0, 512); + snprintf (buffer_message, 512, "syntax error at %i: [%s]", yylineno, buffer); + + fatal_error ("%s", buffer_message); +} + +std::vector<ALLOCA_> * alloca_modifiers (void) +{ + std::vector<ALLOCA_> * allocas = new std::vector<ALLOCA_>; + while (sym == '~' || sym == '&' || sym == '*') + { + ALLOCA_ mod; + switch (sym) + { + case '~': + mod = ALLOC_HEAP; + break; + case '&': + mod = ALLOC_REF; + break; + case '*': + mod = ALLOC_DEREF; + break; + default: + break; + } + yyexpect (sym); + allocas->push_back (mod); + } + return allocas; +} + +rdot type (void) +{ + std::vector<ALLOCA_> * mem = alloca_modifiers (); + rdot retval = NULL_DOT; + if (yyaccept (TYPE_INT)) + retval = rdot_build_decl1 (RTYPE_INT, NULL_DOT); + else if (yyaccept (TYPE_UINT)) + retval = rdot_build_decl1 (RTYPE_UINT, NULL_DOT); + else if (yyaccept (TYPE_FLOAT)) + retval = rdot_build_decl1 (RTYPE_FLOAT, NULL_DOT); + else if (yyaccept (TYPE_BOOL)) + retval = rdot_build_decl1 (RTYPE_BOOL, NULL_DOT); + else if (yyaccept (IDENTIFIER)) + { + char * sid = yylval.string; + retval = rdot_build_decl1 (RTYPE_USER_STRUCT, + rdot_build_identifier (sid)); + free (sid); + } + else + yyerror ("expected a type got [%s]", yytoken_string (sym)); + + RDOT_MMEM_COPY (mem, RDOT_MEM_MODIFIER (retval)); + delete mem; + + return retval; +} + +rdot target (void) +{ + yyexpect (LET); + bool qual = true; + if (yyaccept (MUT)) + qual = false; + + yyexpect (IDENTIFIER); + char * tid = yylval.string; + + rdot ltype = NULL_DOT; + if (yyaccept (':')) + ltype = type (); + if (ltype == NULL_DOT) + ltype = rdot_build_decl1 (RTYPE_INFER, NULL_DOT); + + rdot retval = rdot_build_varDecl (ltype, qual, + rdot_build_identifier (tid)); + free (tid); + return retval; +} + +void argument_list_ (rdot head) +{ + if (yyaccept_ (')')) + return; + + rdot p = expression (); + if (head == NULL_DOT) + vec_safe_push (symStack, p); + else + RDOT_CHAIN (head) = p; + + if (yyaccept (',')) + argument_list_ (p); +} + +rdot argument_list () +{ + rdot retval = NULL_DOT; + size_t prev = symStack->length (); + argument_list_ (NULL_DOT); + size_t next = symStack->length (); + + if (next > prev) + retval = symStack->pop (); + return retval; +} + +rdot struct_elem () +{ + yyexpect (IDENTIFIER); + char * selem = yylval.string; + yyexpect (':'); + rdot expr = expression (); + rdot retval = rdot_build_decl2 (D_STRUCT_PARAM, + rdot_build_identifier (selem), + expr); + free (selem); + return retval; +} + +void struct_init_list_ (rdot head) +{ + if (yyaccept_ ('}')) + return; + rdot e = struct_elem (); + if (head == NULL_DOT) + vec_safe_push (symStack, e); + else + RDOT_CHAIN (head) = e; + if (yyaccept (',')) + struct_init_list_ (e); +} + +rdot struct_init_list (void) +{ + rdot retval = NULL_DOT; + size_t prev = symStack->length (); + struct_init_list_ (NULL_DOT); + size_t next = symStack->length (); + + if (next > prev) + retval = symStack->pop (); + return retval; +} + +rdot primary (void) +{ + rdot retval = NULL_DOT; + std::vector<ALLOCA_> * mem = alloca_modifiers (); + if (yyaccept (IDENTIFIER)) + { + // maybe call... + char * pid = yylval.string; + if (yyaccept_ ('(')) + { + yyexpect ('('); + rdot alist = argument_list (); + yyexpect (')'); + retval = rdot_build_decl2 (D_CALL_EXPR, + rdot_build_identifier (pid), + alist); } - yyexpect(sym); - allocas->push_back(mod); + // struct init + else if (yyaccept_ ('{')) + { + yyexpect ('{'); + rdot sls = struct_init_list (); + yyexpect ('}'); + retval = rdot_build_decl2 (D_STRUCT_INIT, + rdot_build_identifier (pid), + sls); + } + // just a simple identifier... + else + retval = rdot_build_identifier (pid); + free (pid); } - return allocas; -} - -rdot type(void) { - std::vector<ALLOCA_>* mem = alloca_modifiers(); - rdot retval = NULL_DOT; - if (yyaccept(TYPE_INT)) - retval = rdot_build_decl1(RTYPE_INT, NULL_DOT); - else if (yyaccept(TYPE_UINT)) - retval = rdot_build_decl1(RTYPE_UINT, NULL_DOT); - else if (yyaccept(TYPE_FLOAT)) - retval = rdot_build_decl1(RTYPE_FLOAT, NULL_DOT); - else if (yyaccept(TYPE_BOOL)) - retval = rdot_build_decl1(RTYPE_BOOL, NULL_DOT); - else if (yyaccept(IDENTIFIER)) { - char* sid = yylval.string; - retval = rdot_build_decl1(RTYPE_USER_STRUCT, - rdot_build_identifier(sid)); - free(sid); - } else - yyerror("expected a type got [%s]", yytoken_string(sym)); - - RDOT_MMEM_COPY(mem, RDOT_MEM_MODIFIER(retval)); - delete mem; - - return retval; -} - -rdot target(void) { - yyexpect(LET); - bool qual = true; - if (yyaccept(MUT)) - qual = false; - - yyexpect(IDENTIFIER); - char* tid = yylval.string; - - rdot ltype = NULL_DOT; - if (yyaccept(':')) - ltype = type(); - if (ltype == NULL_DOT) - ltype = rdot_build_decl1(RTYPE_INFER, NULL_DOT); - - rdot retval = rdot_build_varDecl(ltype, qual, rdot_build_identifier(tid)); - free(tid); - return retval; -} - -void argument_list_(rdot head) { - if (yyaccept_(')')) - return; - - rdot p = expression(); - if (head == NULL_DOT) - vec_safe_push(symStack, p); - else - RDOT_CHAIN(head) = p; - - if (yyaccept(',')) - argument_list_(p); -} - -rdot argument_list() { - rdot retval = NULL_DOT; - size_t prev = symStack->length(); - argument_list_(NULL_DOT); - size_t next = symStack->length(); - - if (next > prev) - retval = symStack->pop(); - return retval; -} - -rdot struct_elem() { - yyexpect(IDENTIFIER); - char* selem = yylval.string; - yyexpect(':'); - rdot expr = expression(); - rdot retval = rdot_build_decl2(D_STRUCT_PARAM, - rdot_build_identifier(selem), - expr); - free(selem); - return retval; -} - -void struct_init_list_(rdot head) { - if (yyaccept_('}')) - return; - rdot e = struct_elem(); - if (head == NULL_DOT) - vec_safe_push(symStack, e); - else - RDOT_CHAIN(head) = e; - if (yyaccept(',')) - struct_init_list_(e); -} - -rdot struct_init_list(void) { - rdot retval = NULL_DOT; - size_t prev = symStack->length(); - struct_init_list_(NULL_DOT); - size_t next = symStack->length(); - - if (next > prev) - retval = symStack->pop(); - return retval; -} - -rdot primary(void) { - rdot retval = NULL_DOT; - std::vector<ALLOCA_>* mem = alloca_modifiers(); - if (yyaccept(IDENTIFIER)) { - // maybe call... - char* pid = yylval.string; - if (yyaccept_('(')) { - yyexpect('('); - rdot alist = argument_list(); - yyexpect(')'); - retval = rdot_build_decl2(D_CALL_EXPR, - rdot_build_identifier(pid), - alist); + else if (yyaccept (INTEGER)) + retval = rdot_build_integer (yylval.integer); + else if (yyaccept (FLOAT)) + retval = rdot_build_float (yylval.ffloat); + else if (yyaccept (STRING)) + retval = rdot_build_string (yylval.string); + else if (yyaccept (XFALSE)) + retval = rdot_build_bool (false); + else if (yyaccept (XTRUE)) + retval = rdot_build_bool (true); + else + yyerror ("expected a primary got [%s]", yytoken_string (sym)); + + RDOT_MMEM_COPY (mem, RDOT_MEM_MODIFIER (retval)); + delete mem; + return retval; +} + +rdot factor1 (void) +{ + rdot retval = NULL_DOT; + if (yyaccept (IDENTIFIER)) + { + char * pid = yylval.string; + if (yyaccept ('=')) + { + rdot rhs = expression (); + retval = rdot_build_decl2 (D_MODIFY_EXPR, rdot_build_identifier (pid), rhs); } - // struct init - else if (yyaccept_('{')) { - yyexpect('{'); - rdot sls = struct_init_list(); - yyexpect('}'); - retval = rdot_build_decl2(D_STRUCT_INIT, - rdot_build_identifier(pid), - sls); + else if (yyaccept_ ('(')) + { + yyexpect ('('); + rdot alist = argument_list (); + yyexpect (')'); + retval = rdot_build_decl2 (D_CALL_EXPR, + rdot_build_identifier (pid), + alist); } - // just a simple identifier... - else - retval = rdot_build_identifier(pid); - free(pid); - } else if (yyaccept(INTEGER)) - retval = rdot_build_integer(yylval.integer); - else if (yyaccept(FLOAT)) - retval = rdot_build_float(yylval.ffloat); - else if (yyaccept(STRING)) - retval = rdot_build_string(yylval.string); - else if (yyaccept(XFALSE)) - retval = rdot_build_bool(false); - else if (yyaccept(XTRUE)) - retval = rdot_build_bool(true); - else - yyerror("expected a primary got [%s]", yytoken_string(sym)); - - RDOT_MMEM_COPY(mem, RDOT_MEM_MODIFIER(retval)); - delete mem; - return retval; -} - -rdot factor1(void) { - rdot retval = NULL_DOT; - if (yyaccept(IDENTIFIER)) { - char* pid = yylval.string; - if (yyaccept('=')) { - rdot rhs = expression(); - retval = rdot_build_decl2(D_MODIFY_EXPR, rdot_build_identifier(pid), rhs); - } else if (yyaccept_('(')) { - yyexpect('('); - rdot alist = argument_list(); - yyexpect(')'); - retval = rdot_build_decl2(D_CALL_EXPR, - rdot_build_identifier(pid), - alist); + // struct init + else if (yyaccept_ ('{')) + { + yyexpect ('{'); + rdot sls = struct_init_list (); + yyexpect ('}'); + retval = rdot_build_decl2 (D_STRUCT_INIT, + rdot_build_identifier (pid), + sls); } - // struct init - else if (yyaccept_('{')) { - yyexpect('{'); - rdot sls = struct_init_list(); - yyexpect('}'); - retval = rdot_build_decl2(D_STRUCT_INIT, - rdot_build_identifier(pid), - sls); - } else if (yyaccept_(ACC)) { - yyexpect(ACC); - rdot node = factor1(); - retval = rdot_build_decl2(D_ACC_EXPR, rdot_build_identifier(pid), node); - } else { - retval = rdot_build_identifier(yylval.string); - if (yyaccept('.')) { - rdot rhs = factor2(); - retval = rdot_build_decl2(D_ATTRIB_REF, retval, rhs); + else if (yyaccept_ (ACC)) + { + yyexpect (ACC); + rdot node = factor1 (); + retval = rdot_build_decl2 (D_ACC_EXPR, rdot_build_identifier (pid), node); + } + else + { + retval = rdot_build_identifier (yylval.string); + if (yyaccept ('.')) + { + rdot rhs = factor2 (); + retval = rdot_build_decl2 (D_ATTRIB_REF, retval, rhs); } } - free(pid); - } else - retval = factor2(); - return retval; -} - -rdot factor2(void) { - rdot retval = NULL_DOT; - if (yyaccept('(')) { - retval = expression(); - yyexpect(')'); - } else { - retval = primary(); - if (RDOT_TYPE(retval) == D_IDENTIFIER || RDOT_TYPE(retval) == D_CALL_EXPR) { - if (yyaccept('.')) { - rdot rhs = factor2(); - retval = rdot_build_decl2(D_ATTRIB_REF, retval, rhs); + free (pid); + } + else + retval = factor2 (); + return retval; +} + +rdot factor2 (void) +{ + rdot retval = NULL_DOT; + if (yyaccept ('(')) + { + retval = expression (); + yyexpect (')'); + } + else + { + retval = primary (); + if (RDOT_TYPE (retval) == D_IDENTIFIER + || RDOT_TYPE (retval) == D_CALL_EXPR) + { + if (yyaccept ('.')) + { + rdot rhs = factor2 (); + retval = rdot_build_decl2 (D_ATTRIB_REF, retval, rhs); } } } - return retval; + return retval; +} + +opcode_t symToDeclType (int sym) +{ + opcode_t retval = D_D_EXPR; + switch (sym) + { + case '=': + retval = D_MODIFY_EXPR; + break; + + case '+': + retval = D_ADD_EXPR; + break; + + case '-': + retval = D_MINUS_EXPR; + break; + + case '*': + retval = D_MULT_EXPR; + break; + + case '/': + retval = D_DIVD_EXPR; + break; + + case '.': + retval = D_ATTRIB_REF; + break; + + case EQUAL_EQUAL: + retval = D_EQ_EQ_EXPR; + break; + + case NOT_EQUAL: + retval = D_NOT_EQ_EXPR; + break; + + case '<': + retval = D_LESS_EXPR; + break; + + case LESS_EQUAL: + retval = D_LESS_EQ_EXPR; + break; + + case '>': + retval = D_GREATER_EXPR; + break; + + case GREATER_EQUAL: + retval = D_GREATER_EQ_EXPR; + break; + + default: + yyerror ("invalid symbol [%i:%s]", + sym, yytoken_string (sym)); + break; + } + return retval; +} + +rdot expression (void) +{ + bool head = false; + rdot retval = factor1 (); + rdot next = NULL_DOT; + while (sym == '+' || sym == '-' || + sym == '*' || sym == '/' || + sym == '<' || sym == '>' || + sym == EQUAL_EQUAL || sym == NOT_EQUAL || + sym == LESS_EQUAL || sym == GREATER_EQUAL) + { + opcode_t o = symToDeclType (sym); + yyexpect (sym); + rdot rhs = factor2 (); + if (head == false) + { + retval = next = rdot_build_decl2 (o, retval, rhs); + head = true; + } + else + { + rdot prev = RDOT_rhs_TT (next); + rdot rhs_expr = rdot_build_decl2 (o, prev, rhs); + RDOT_rhs_TT (next) = rhs_expr; + next = rhs_expr; + } + } + return retval; } -opcode_t symToDeclType(int sym) { - opcode_t retval = D_D_EXPR; - switch (sym) { - case '=': - retval = D_MODIFY_EXPR; - break; - - case '+': - retval = D_ADD_EXPR; - break; - - case '-': - retval = D_MINUS_EXPR; - break; - - case '*': - retval = D_MULT_EXPR; - break; - - case '/': - retval = D_DIVD_EXPR; - break; - - case '.': - retval = D_ATTRIB_REF; - break; - - case EQUAL_EQUAL: - retval = D_EQ_EQ_EXPR; - break; - - case NOT_EQUAL: - retval = D_NOT_EQ_EXPR; - break; - - case '<': - retval = D_LESS_EXPR; - break; - - case LESS_EQUAL: - retval = D_LESS_EQ_EXPR; - break; - - case '>': - retval = D_GREATER_EXPR; - break; - - case GREATER_EQUAL: - retval = D_GREATER_EQ_EXPR; - break; - - default: - yyerror("invalid symbol [%i:%s]", - sym, - yytoken_string(sym)); - break; +rdot statement () +{ + rdot retval = NULL_DOT; + if (yyaccept_ (BREAK)) + { + yyexpect (BREAK); + retval = rdot_build_decl1 (C_BREAK_STMT, NULL_DOT); + } + else if (yyaccept_ (CONTINUE)) + { + yyexpect (CONTINUE); + retval = rdot_build_decl1 (C_CONT_STMT, NULL_DOT); + } + else if (yyaccept_ (RETURN)) + { + yyexpect (RETURN); + retval = rdot_build_decl1 (C_RETURN_STMT, expression ()); } - return retval; -} - -rdot expression(void) { - bool head = false; - rdot retval = factor1(); - rdot next = NULL_DOT; - while (sym == '+' || sym == '-' || - sym == '*' || sym == '/' || - sym == '<' || sym == '>' || - sym == EQUAL_EQUAL || sym == NOT_EQUAL || - sym == LESS_EQUAL || sym == GREATER_EQUAL) { - opcode_t o = symToDeclType(sym); - yyexpect(sym); - rdot rhs = factor2(); - if (head == false) { - retval = next = rdot_build_decl2(o, retval, rhs); - head = true; - } else { - rdot prev = RDOT_rhs_TT(next); - rdot rhs_expr = rdot_build_decl2(o, prev, rhs); - RDOT_rhs_TT(next) = rhs_expr; - next = rhs_expr; + else if (yyaccept_ (LET)) + { + // simple vardecl [let x;] + rdot tg = target (); + if (yyaccept ('=')) + { + retval = rdot_build_decl2 (D_MODIFY_EXPR, + tg, expression ()); } + else + retval = tg; } - return retval; -} - -rdot statement() { - rdot retval = NULL_DOT; - if (yyaccept_(BREAK)) { - yyexpect(BREAK); - retval = rdot_build_decl1(C_BREAK_STMT, NULL_DOT); - } else if (yyaccept_(CONTINUE)) { - yyexpect(CONTINUE); - retval = rdot_build_decl1(C_CONT_STMT, NULL_DOT); - } else if (yyaccept_(RETURN)) { - yyexpect(RETURN); - retval = rdot_build_decl1(C_RETURN_STMT, expression()); - } else if (yyaccept_(LET)) { - // simple vardecl [let x;] - rdot tg = target(); - if (yyaccept('=')) { - retval = rdot_build_decl2(D_MODIFY_EXPR, - tg, - expression()); - } else - retval = tg; - } else - retval = expression(); - return retval; -} - -rdot struct_while_loop() { - yyexpect(WHILE); - rdot expr = expression(); - yyexpect('{'); - rdot sb = suite(); - yyexpect('}'); - return rdot_build_decl2(D_STRUCT_WHILE, expr, sb); -} - -rdot struct_loop() { - yyexpect(LOOP); - yyexpect('{'); - rdot sb = suite(); - yyexpect('}'); - return rdot_build_decl1(D_STRUCT_LOOP, sb); -} - -rdot if_block(void) { - yyexpect(IF); - rdot expr = expression(); - yyexpect('{'); - rdot sb = suite(); - yyexpect('}'); - return rdot_build_decl2(D_STRUCT_IF, expr, sb); -} - -rdot elif_block(void) { - yyexpect(ELIF); - rdot expr = expression(); - yyexpect('{'); - rdot sb = suite(); - yyexpect('}'); - return rdot_build_decl2(D_STRUCT_IF, expr, sb); -} - -rdot else_block(void) { - yyexpect(ELSE); - yyexpect('{'); - rdot block = suite(); - yyexpect('}'); - return rdot_build_decl1(D_STRUCT_ELSE, block); -} - -rdot struct_conditional() { - rdot iblock = if_block(); - rdot eblock = NULL_DOT; - rdot elblock = NULL_DOT; - rdot curr = NULL_DOT; - rdot prev = NULL_DOT; - while (yyaccept_(ELIF)) { - curr = elif_block(); - if (elblock == NULL_DOT) - elblock = prev = curr; - else { - RDOT_CHAIN(prev) = curr; - prev = curr; + else + retval = expression (); + return retval; +} + +rdot struct_while_loop () +{ + yyexpect (WHILE); + rdot expr = expression (); + yyexpect ('{'); + rdot sb = suite (); + yyexpect ('}'); + return rdot_build_decl2 (D_STRUCT_WHILE, expr, sb); +} + +rdot struct_loop () +{ + yyexpect (LOOP); + yyexpect ('{'); + rdot sb = suite (); + yyexpect ('}'); + return rdot_build_decl1 (D_STRUCT_LOOP, sb); +} + +rdot if_block (void) +{ + yyexpect (IF); + rdot expr = expression (); + yyexpect ('{'); + rdot sb = suite (); + yyexpect ('}'); + return rdot_build_decl2 (D_STRUCT_IF, expr, sb); +} + +rdot elif_block (void) +{ + yyexpect (ELIF); + rdot expr = expression (); + yyexpect ('{'); + rdot sb = suite (); + yyexpect ('}'); + return rdot_build_decl2 (D_STRUCT_IF, expr, sb); +} + +rdot else_block (void) +{ + yyexpect (ELSE); + yyexpect ('{'); + rdot block = suite (); + yyexpect ('}'); + return rdot_build_decl1 (D_STRUCT_ELSE, block); +} + +rdot struct_conditional () +{ + rdot iblock = if_block (); + rdot eblock = NULL_DOT; + rdot elblock = NULL_DOT; + rdot curr = NULL_DOT; + rdot prev = NULL_DOT; + while (yyaccept_ (ELIF)) + { + curr = elif_block (); + if (elblock == NULL_DOT) + elblock = prev = curr; + else + { + RDOT_CHAIN (prev) = curr; + prev = curr; } } - if (yyaccept_(ELSE)) - eblock = else_block(); - rdot retval = rdot_build_decl2(D_STRUCT_IF, iblock, eblock); - RDOT_FIELD(retval) = elblock; - return retval; -} - -void statement_list(rdot head) { - if (yyaccept_('}')) - return; - - rdot st = NULL_DOT; - if (yyaccept_(LOOP)) - st = struct_loop(); - else if (yyaccept_(WHILE)) - st = struct_while_loop(); - else if (yyaccept_(IF)) - st = struct_conditional(); - else { - st = statement(); - if (!yyaccept(';')) - DOT_RETVAL(st) = true; + if (yyaccept_ (ELSE)) + eblock = else_block (); + rdot retval = rdot_build_decl2 (D_STRUCT_IF, iblock, eblock); + RDOT_FIELD (retval)= elblock; + return retval; +} + +void statement_list (rdot head) +{ + if (yyaccept_ ('}')) + return; + + rdot st = NULL_DOT; + if (yyaccept_ (LOOP)) + st = struct_loop (); + else if (yyaccept_ (WHILE)) + st = struct_while_loop (); + else if (yyaccept_ (IF)) + st = struct_conditional (); + else + { + st = statement (); + if (!yyaccept (';')) + DOT_RETVAL (st) = true; } - gcc_assert(st != NULL_DOT); - if (head == NULL_DOT) - vec_safe_push(symStack, st); - else - RDOT_CHAIN(head) = st; - statement_list(st); -} - -rdot suite() { - rdot retval = NULL_DOT; - size_t prev = symStack->length(); - statement_list(NULL); - size_t next = symStack->length(); - - if (next > prev) - retval = symStack->pop(); - return retval; -} - -rdot param(void) { - yyexpect(IDENTIFIER); - char* pid = yylval.string; - yyexpect(':'); - rdot pit = type(); - rdot retval = rdot_build_decl2(D_PARAMETER, - rdot_build_identifier(pid), - pit); - free(pid); - return retval; -} - -void param_list_(rdot head) { - if (yyaccept_(')')) - return; - - rdot p = param(); - if (head == NULL_DOT) - vec_safe_push(symStack, p); - else - RDOT_CHAIN(head) = p; - - if (yyaccept(',')) - param_list_(p); -} - -rdot param_list() { - rdot retval = NULL_DOT; - size_t prev = symStack->length(); - param_list_(NULL_DOT); - size_t next = symStack->length(); - - if (next > prev) - retval = symStack->pop(); - return retval; + gcc_assert (st != NULL_DOT); + if (head == NULL_DOT) + vec_safe_push (symStack, st); + else + RDOT_CHAIN (head) = st; + statement_list (st); +} + +rdot suite () +{ + rdot retval = NULL_DOT; + size_t prev = symStack->length (); + statement_list (NULL); + size_t next = symStack->length (); + + if (next > prev) + retval = symStack->pop (); + return retval; +} + +rdot param (void) +{ + yyexpect (IDENTIFIER); + char * pid = yylval.string; + yyexpect (':'); + rdot pit = type (); + rdot retval = rdot_build_decl2 (D_PARAMETER, + rdot_build_identifier (pid), + pit); + free (pid); + return retval; +} + +void param_list_ (rdot head) +{ + if (yyaccept_ (')')) + return; + + rdot p = param (); + if (head == NULL_DOT) + vec_safe_push (symStack, p); + else + RDOT_CHAIN (head) = p; + + if (yyaccept (',')) + param_list_ (p); +} + +rdot param_list () +{ + rdot retval = NULL_DOT; + size_t prev = symStack->length (); + param_list_ (NULL_DOT); + size_t next = symStack->length (); + + if (next > prev) + retval = symStack->pop (); + return retval; } /* fndecl := [pub] fn IDENTIFIER ([param_list]) [-> type] { stmt_list } */ -rdot fndecl() { - bool pub = false; - if (yyaccept(PUB)) - pub = true; - yyexpect(DEFUN); - yyexpect(IDENTIFIER); - char* fid = yylval.string; - yyexpect('('); - rdot plist = param_list(); - yyexpect(')'); - rdot rtype = NULL_DOT; - if (yyaccept(RTYPE)) - rtype = type(); - yyexpect('{'); - rdot block = suite(); - yyexpect('}'); - rdot retval = rdot_build_fndecl(rdot_build_identifier(fid), - pub, - plist, - rtype, - block); - free(fid); - return retval; -} - -void struct_layout_(rdot head) { - if (yyaccept_('}')) - return; - - rdot p = param(); - if (head == NULL_DOT) - vec_safe_push(symStack, p); - else - RDOT_CHAIN(head) = p; - - if (yyaccept(',')) - struct_layout_(p); -} - -rdot struct_layout() { - rdot retval = NULL_DOT; - size_t prev = symStack->length(); - struct_layout_(NULL_DOT); - size_t next = symStack->length(); - - if (next > prev) - retval = symStack->pop(); - return retval; -} - -rdot struct_decl() { - yyexpect(STRUCT); - yyexpect(IDENTIFIER); - char* sid = yylval.string; - - yyexpect('{'); - rdot layout = struct_layout(); - yyexpect('}'); - rdot retval = rdot_build_decl2(D_STRUCT_TYPE, - rdot_build_identifier(sid), - layout); - free(sid); - return retval; -} - -void fndecl_block_(rdot head) { - if (yyaccept_('}')) - return; - - rdot f = fndecl(); - if (head == NULL_DOT) - vec_safe_push(symStack, f); - else - RDOT_CHAIN(head) = f; - - fndecl_block_(f); -} - -rdot fndecl_block(void) { - rdot retval = NULL_DOT; - size_t prev = symStack->length(); - fndecl_block_(NULL_DOT); - size_t next = symStack->length(); - - if (next > prev) - retval = symStack->pop(); - return retval; -} - -rdot impl_block() { - rdot retval = NULL_DOT; - yyexpect(IMPL); - yyexpect(IDENTIFIER); - char* iid = yylval.string; - rdot rid = rdot_build_identifier(iid); - free(iid); - if (yyaccept(FOR)) - yyexpect(IDENTIFIER); - yyexpect('{'); - rdot fb = fndecl_block(); - yyexpect('}'); - retval = rdot_build_decl2(D_STRUCT_IMPL, rid, fb); - return retval; +rdot fndecl () +{ + bool pub = false; + if (yyaccept (PUB)) + pub = true; + yyexpect (DEFUN); + yyexpect (IDENTIFIER); + char * fid = yylval.string; + yyexpect ('('); + rdot plist = param_list (); + yyexpect (')'); + rdot rtype = NULL_DOT; + if (yyaccept (RTYPE)) + rtype = type (); + yyexpect ('{'); + rdot block = suite (); + yyexpect ('}'); + rdot retval = rdot_build_fndecl (rdot_build_identifier (fid), + pub, plist, rtype, block); + free (fid); + return retval; +} + +void struct_layout_ (rdot head) +{ + if (yyaccept_ ('}')) + return; + + rdot p = param (); + if (head == NULL_DOT) + vec_safe_push (symStack, p); + else + RDOT_CHAIN (head) = p; + + if (yyaccept (',')) + struct_layout_ (p); +} + +rdot struct_layout () +{ + rdot retval = NULL_DOT; + size_t prev = symStack->length (); + struct_layout_ (NULL_DOT); + size_t next = symStack->length (); + + if (next > prev) + retval = symStack->pop (); + return retval; +} + +rdot struct_decl () +{ + yyexpect (STRUCT); + yyexpect (IDENTIFIER); + char * sid = yylval.string; + + yyexpect ('{'); + rdot layout = struct_layout (); + yyexpect ('}'); + rdot retval = rdot_build_decl2 (D_STRUCT_TYPE, + rdot_build_identifier (sid), + layout); + free (sid); + return retval; +} + +void fndecl_block_ (rdot head) +{ + if (yyaccept_ ('}')) + return; + + rdot f = fndecl (); + if (head == NULL_DOT) + vec_safe_push (symStack, f); + else + RDOT_CHAIN (head) = f; + + fndecl_block_ (f); +} + +rdot fndecl_block (void) +{ + rdot retval = NULL_DOT; + size_t prev = symStack->length (); + fndecl_block_ (NULL_DOT); + size_t next = symStack->length (); + + if (next > prev) + retval = symStack->pop (); + return retval; +} + +rdot impl_block () +{ + rdot retval = NULL_DOT; + yyexpect (IMPL); + yyexpect (IDENTIFIER); + char * iid = yylval.string; + rdot rid = rdot_build_identifier (iid); + free (iid); + if (yyaccept (FOR)) + yyexpect (IDENTIFIER); + yyexpect ('{'); + rdot fb = fndecl_block (); + yyexpect ('}'); + retval = rdot_build_decl2 (D_STRUCT_IMPL, rid, fb); + return retval; } /* decl := fndecl | structdecl | impldecl | enumdecl */ -void decl(void) { - rdot rdecl = NULL_DOT; - if (yyaccept_(STRUCT)) - rdecl = struct_decl(); - else if (yyaccept_(IMPL)) - rdecl = impl_block(); - else - rdecl = fndecl(); - if (rdecl != NULL_DOT) - dot_pass_pushDecl(rdecl); -} - -int yyparse(void) { - // kick things off with the first token - __yyerror = 0; - sym = yylex_(); - - vec_alloc(symStack, 0); - vec_safe_push(symStack, NULL_DOT); - - while (sym != 0) - decl(); - - if (symStack->length() > 1) - yyerror("some unpoped symbols on the parse stack!"); - - vec_free(symStack); - return __yyerror; +void decl (void) +{ + rdot rdecl = NULL_DOT; + if (yyaccept_ (STRUCT)) + rdecl = struct_decl (); + else if (yyaccept_ (IMPL)) + rdecl = impl_block (); + else + rdecl = fndecl (); + if (rdecl != NULL_DOT) + dot_pass_pushDecl (rdecl); +} + +int yyparse (void) +{ + // kick things off with the first token + __yyerror = 0; + sym = yylex_ (); + + vec_alloc (symStack, 0); + vec_safe_push (symStack, NULL_DOT); + + while (sym != 0) + decl (); + + if (symStack->length() > 1) + yyerror ("some unpoped symbols on the parse stack!"); + + vec_free (symStack); + return __yyerror; } diff --git a/gcc/rust/old/rs-pass-manager.cc b/gcc/rust/old/rs-pass-manager.cc index ec07c65..9ffac6e 100644 --- a/gcc/rust/old/rs-pass-manager.cc +++ b/gcc/rust/old/rs-pass-manager.cc @@ -18,97 +18,101 @@ tree cstring_type_node; static bool empty = true; -#define MAYBE_BOMB_OUT \ - do \ - if (seen_error()) \ - return; \ - while (0); - -static vec<rdot, va_gc>* rust_decls; -typedef vec<rdot, va_gc>* (*dot_pass)(vec<rdot, va_gc>*); -static dot_pass dot_pass_mngr[] = { - &dot_pass_PrettyPrint, // pretty print if -fdump-dot pre and post infereance */ - &dot_pass_inferTypes, // This ensures there are no longer any D_MAYBE_TYPES */ +#define MAYBE_BOMB_OUT \ + do \ + if (seen_error ()) return; \ + while (0); + +static vec<rdot,va_gc> * rust_decls; +typedef vec<rdot,va_gc> * (*dot_pass)(vec<rdot,va_gc> *); +static dot_pass dot_pass_mngr[] = + { + &dot_pass_PrettyPrint, /* pretty print if -fdump-dot pre and post infereance */ + &dot_pass_inferTypes, /* This ensures there are no longer any D_MAYBE_TYPES */ &dot_pass_PrettyPrint, - NULL // sentinal */ -}; - -// Pushes each decl from the parser onto the current translation unit -void dot_pass_pushDecl(rdot decl) { - if (empty) - empty = false; - - if (RDOT_TYPE(decl) == D_STRUCT_TYPE) { - // look for duplicate fields - std::map<std::string, bool> layout; - rdot next; - for (next = RDOT_rhs_TT(decl); next != NULL_DOT; - next = RDOT_CHAIN(next)) { - const char* pid = RDOT_IDENTIFIER_POINTER(RDOT_lhs_TT(next)); - if (layout.count(pid) > 0) - error("structure [%s] already contains element [%s]", - RDOT_IDENTIFIER_POINTER(RDOT_lhs_TT(decl)), - pid); - else - layout[pid] = true; + NULL /* sentinal */ + }; + +/* Pushes each decl from the parser onto the current translation unit */ +void dot_pass_pushDecl (rdot decl) +{ + if (empty) + empty = false; + + if (RDOT_TYPE (decl) == D_STRUCT_TYPE) + { + // look for duplicate fields + std::map<std::string, bool> layout; + rdot next; + for (next = RDOT_rhs_TT (decl); next != NULL_DOT; + next = RDOT_CHAIN (next)) + { + const char * pid = RDOT_IDENTIFIER_POINTER (RDOT_lhs_TT (next)); + if (layout.count (pid) > 0) + error ("structure [%s] already contains element [%s]", + RDOT_IDENTIFIER_POINTER (RDOT_lhs_TT (decl)), pid); + else + layout [pid] = true; } } - vec_safe_push(rust_decls, decl); + vec_safe_push (rust_decls, decl); } /* Function to run over the pass manager hooks and generate the generic code to pass to gcc middle-end */ -void dot_pass_WriteGlobals(void) { - // if the rdot translation unit is empty there is nothing to compile.. - if (empty == true) - return; - - tree cptr = build_pointer_type(char_type_node); - cstring_type_node = build_qualified_type(cptr, TYPE_QUAL_CONST); - - dot_pass* p = NULL; - vec<rdot, va_gc>* dot_decls = rust_decls; - - /* walk the passes */ - for (p = dot_pass_mngr; *p != NULL; ++p) { - MAYBE_BOMB_OUT; - dot_decls = (*p)(dot_decls); +void dot_pass_WriteGlobals (void) +{ + // if the rdot translation unit is empty there is nothing to compile.. + if (empty == true) + return; + + tree cptr = build_pointer_type (char_type_node); + cstring_type_node = build_qualified_type (cptr, TYPE_QUAL_CONST); + + dot_pass *p = NULL; + vec<rdot,va_gc> * dot_decls = rust_decls; + + /* walk the passes */ + for (p = dot_pass_mngr; *p != NULL; ++p) + { + MAYBE_BOMB_OUT; + dot_decls = (*p)(dot_decls); } + + /* check errors */ + MAYBE_BOMB_OUT; - /* check errors */ - MAYBE_BOMB_OUT; - - /* lower the decls from DOT -> GENERIC */ - vec<tree, va_gc>* globals = dot_pass_Genericify(dot_decls); + /* lower the decls from DOT -> GENERIC */ + vec<tree,va_gc> * globals = dot_pass_Genericify (dot_decls); - int global_vec_len = vec_safe_length(globals); - tree* global_vec = new tree[global_vec_len]; - tree itx = NULL_TREE; - int idx, idy = 0; - /* + int global_vec_len = vec_safe_length (globals); + tree * global_vec = new tree[global_vec_len]; + tree itx = NULL_TREE; + int idx, idy = 0; + /* Lets make sure to dump the Translation Unit this isn't that useful to read over but can help to make sure certain tree's are being generated... We also fill up the vector of tree's to be passed to the middle-end */ - FILE* tu_stream = dump_begin(TDI_tu, NULL); - for (idx = 0; vec_safe_iterate(globals, idx, &itx); ++idx) { - if (tu_stream) - dump_node(itx, 0, tu_stream); - global_vec[idy] = itx; - idy++; + FILE * tu_stream = dump_begin (TDI_tu, NULL); + for (idx = 0; vec_safe_iterate (globals, idx, &itx); ++idx) + { + if (tu_stream) + dump_node (itx, 0, tu_stream); + global_vec [idy] = itx; + idy++; } - - if (tu_stream) - dump_end(TDI_tu, tu_stream); - - /* Passing control to GCC middle-end */ - wrapup_global_declarations(global_vec, global_vec_len); - finalize_compilation_unit(); - check_global_declarations(global_vec, global_vec_len); - emit_debug_global_declarations(global_vec, global_vec_len); - - delete[] global_vec; + if (tu_stream) + dump_end(TDI_tu, tu_stream); + + /* Passing control to GCC middle-end */ + wrapup_global_declarations (global_vec, global_vec_len); + finalize_compilation_unit (); + check_global_declarations (global_vec, global_vec_len); + emit_debug_global_declarations (global_vec, global_vec_len); + + delete [] global_vec; } diff --git a/gcc/rust/old/rs-runtime-hooks.cc b/gcc/rust/old/rs-runtime-hooks.cc index 1cd2b30..7e7c868 100644 --- a/gcc/rust/old/rs-runtime-hooks.cc +++ b/gcc/rust/old/rs-runtime-hooks.cc @@ -16,46 +16,42 @@ #include "rust.h" -#define nitems(_a) (sizeof(_a)) / sizeof((_a)[0]) -#define LANG_HOOK(name_) "__GRUST_" name_, name_ +#define nitems(_a) (sizeof (_a)) / sizeof ((_a)[0]) +#define LANG_HOOK(name_) "__GRUST_"name_, name_ -// Seems to be a way of storing info about a runtime hook function struct rust_runtime { - const char* mangled_name; - const char* rust_symbol; + const char * mangled_name; + const char * rust_symbol; const size_t nargs; - const tree** paramater_types; + const tree ** paramater_types; }; -// Maybe an array of hooks? Doesn't have anything useful in it right now. -static struct rust_runtime hooks[] = { - /* sentinel (meaning "dummy data", basically) */ +static struct rust_runtime hooks [] = { + /* sentinal */ { NULL, NULL, 0, NULL } }; -/* Seems to build functions, results, and their return types into some tree, which is put into dict - * - * Presumably actually does something if hooks is changed to something other than default values. */ -void rs_fill_runtime_decls(std::map<std::string, tree>* dict) { - struct rust_runtime* hk; - - for (hk = hooks; hk->mangled_name != NULL; ++hk) { - tree* args = XALLOCAVEC(tree, hk->nargs); - size_t i; - - for (i = 0; i < hk->nargs; ++i) - args[i] = *(hk->paramater_types[i]); - - tree fntype = build_function_type_array(void_type_node, hk->nargs, args); - tree fndecl = build_decl(BUILTINS_LOCATION, FUNCTION_DECL, get_identifier(hk->mangled_name), - fntype); - tree restype = TREE_TYPE(fndecl); - tree resdecl = build_decl(BUILTINS_LOCATION, RESULT_DECL, NULL_TREE, restype); - DECL_CONTEXT(resdecl) = fndecl; - DECL_RESULT(fndecl) = resdecl; - DECL_EXTERNAL(fndecl) = 1; - TREE_PUBLIC(fndecl) = 1; - - (*dict)[std::string(hk->rust_symbol)] = fndecl; +void rs_fill_runtime_decls (std::map<std::string, tree> * dict) +{ + struct rust_runtime * hk; + for (hk = hooks; hk->mangled_name != NULL; ++hk) + { + tree * args = XALLOCAVEC (tree, hk->nargs); + size_t i; + for (i = 0; i < hk->nargs; ++i) + args[i] = *(hk->paramater_types [i]); + + tree fntype = build_function_type_array (void_type_node, hk->nargs, args); + tree fndecl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL, + get_identifier (hk->mangled_name), fntype); + tree restype = TREE_TYPE (fndecl); + tree resdecl = build_decl (BUILTINS_LOCATION, RESULT_DECL, + NULL_TREE, restype); + DECL_CONTEXT (resdecl) = fndecl; + DECL_RESULT (fndecl) = resdecl; + DECL_EXTERNAL (fndecl) = 1; + TREE_PUBLIC (fndecl) = 1; + + (*dict)[std::string (hk->rust_symbol)] = fndecl; } } diff --git a/gcc/rust/old/rsspec.cc b/gcc/rust/old/rsspec.cc index 7a6a83f..c5dde9b 100644 --- a/gcc/rust/old/rsspec.cc +++ b/gcc/rust/old/rsspec.cc @@ -1,4 +1,3 @@ -// rsspec.cc - File used for compiler driver creation or something related to that. /* This file is part of GCC. GNU CC is free software; you can redistribute it and/or modify @@ -16,336 +15,387 @@ along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ #include "config.h" +#include "system.h" #include "coretypes.h" #include "gcc.h" #include "opts.h" -#include "system.h" -#include "intl.h" #include "tm.h" +#include "intl.h" #ifndef MATH_LIBRARY -#define MATH_LIBRARY "m" +# define MATH_LIBRARY "m" #endif #ifndef RUST_LIBRARY -#define RUST_LIBRARY "grust" +# define RUST_LIBRARY "grust" #endif /* The original argument list and related info is copied here. */ static unsigned int grs_xargc; -static const struct cl_decoded_option* grs_x_decoded_options; -static void append_arg(const struct cl_decoded_option*); +static const struct cl_decoded_option *grs_x_decoded_options; +static void append_arg (const struct cl_decoded_option *); /* The new argument list will be built here. */ static unsigned int grs_newargc; -static struct cl_decoded_option* grs_new_decoded_options; +static struct cl_decoded_option *grs_new_decoded_options; /* Return whether strings S1 and S2 are both NULL or both the same - * string. - * */ -static bool strings_same(const char* s1, const char* s2) { - return s1 == s2 || (s1 != NULL && s2 != NULL && strcmp(s1, s2) == 0); + string. */ + +static bool +strings_same (const char *s1, const char *s2) +{ + return s1 == s2 || (s1 != NULL && s2 != NULL && strcmp (s1, s2) == 0); } /* Return whether decoded option structures OPT1 and OPT2 are the - * same. - * */ -static bool options_same(const struct cl_decoded_option* opt1, const struct cl_decoded_option* opt2) { - return (opt1->opt_index == opt2->opt_index && strings_same(opt1->arg, opt2->arg) && strings_same(opt1->orig_option_with_args_text, opt2->orig_option_with_args_text) && strings_same(opt1->canonical_option[0], opt2->canonical_option[0]) && strings_same(opt1->canonical_option[1], opt2->canonical_option[1]) && strings_same(opt1->canonical_option[2], opt2->canonical_option[2]) && strings_same(opt1->canonical_option[3], opt2->canonical_option[3]) && (opt1->canonical_option_num_elements == opt2->canonical_option_num_elements) && opt1->value == opt2->value && opt1->errors == opt2->errors); + same. */ + +static bool +options_same (const struct cl_decoded_option *opt1, + const struct cl_decoded_option *opt2) +{ + return (opt1->opt_index == opt2->opt_index + && strings_same (opt1->arg, opt2->arg) + && strings_same (opt1->orig_option_with_args_text, + opt2->orig_option_with_args_text) + && strings_same (opt1->canonical_option[0], + opt2->canonical_option[0]) + && strings_same (opt1->canonical_option[1], + opt2->canonical_option[1]) + && strings_same (opt1->canonical_option[2], + opt2->canonical_option[2]) + && strings_same (opt1->canonical_option[3], + opt2->canonical_option[3]) + && (opt1->canonical_option_num_elements + == opt2->canonical_option_num_elements) + && opt1->value == opt2->value + && opt1->errors == opt2->errors); } /* Append another argument to the list being built. As long as it is - * identical to the corresponding arg in the original list, just increment - * the new arg count. Otherwise allocate a new list, etc. - * */ -static void append_arg(const struct cl_decoded_option* arg) { - static unsigned int newargsize; + identical to the corresponding arg in the original list, just increment + the new arg count. Otherwise allocate a new list, etc. */ + +static void +append_arg (const struct cl_decoded_option *arg) +{ + static unsigned int newargsize; #if 0 - fprintf (stderr, "`%s'\n", arg); + fprintf (stderr, "`%s'\n", arg); #endif - if (grs_new_decoded_options == grs_x_decoded_options && grs_newargc < grs_xargc && options_same(arg, &grs_x_decoded_options[grs_newargc])) { - ++grs_newargc; - return; /* Nothing new here. */ + if (grs_new_decoded_options == grs_x_decoded_options + && grs_newargc < grs_xargc + && options_same (arg, &grs_x_decoded_options[grs_newargc])) + { + ++grs_newargc; + return; /* Nothing new here. */ } - if (grs_new_decoded_options == grs_x_decoded_options) { /* Make new arglist. */ - unsigned int i; + if (grs_new_decoded_options == grs_x_decoded_options) + { /* Make new arglist. */ + unsigned int i; - newargsize = (grs_xargc << 2) + 20; /* This should handle all. */ - grs_new_decoded_options = XNEWVEC(struct cl_decoded_option, newargsize); + newargsize = (grs_xargc << 2) + 20; /* This should handle all. */ + grs_new_decoded_options = XNEWVEC (struct cl_decoded_option, newargsize); - /* Copy what has been done so far. */ - for (i = 0; i < grs_newargc; ++i) - grs_new_decoded_options[i] = grs_x_decoded_options[i]; + /* Copy what has been done so far. */ + for (i = 0; i < grs_newargc; ++i) + grs_new_decoded_options[i] = grs_x_decoded_options[i]; } - if (grs_newargc == newargsize) - fatal_error("overflowed output arg list for %qs", - arg->orig_option_with_args_text); + if (grs_newargc == newargsize) + fatal_error ("overflowed output arg list for %qs", + arg->orig_option_with_args_text); - grs_new_decoded_options[grs_newargc++] = *arg; + grs_new_decoded_options[grs_newargc++] = *arg; } /* Append an option described by OPT_INDEX, ARG and VALUE to the list - * being built. - * */ -static void append_option(size_t opt_index, const char* arg, int value) { - struct cl_decoded_option decoded; - - generate_option(opt_index, arg, value, CL_DRIVER, &decoded); - append_arg(&decoded); + being built. */ +static void +append_option (size_t opt_index, const char *arg, int value) +{ + struct cl_decoded_option decoded; + + generate_option (opt_index, arg, value, CL_DRIVER, &decoded); + append_arg (&decoded); } /* Append a librust argument to the list being built. If - * FORCE_STATIC, ensure the library is linked statically. - * */ -static void add_arg_libgrust(bool force_static ATTRIBUTE_UNUSED) { + FORCE_STATIC, ensure the library is linked statically. */ + +static void +add_arg_libgrust (bool force_static ATTRIBUTE_UNUSED) +{ #ifdef HAVE_LD_STATIC_DYNAMIC - if (force_static) - append_option(OPT_Wl_, "-Bstatic", 1); + if (force_static) + append_option (OPT_Wl_, "-Bstatic", 1); #endif - append_option(OPT_l, RUST_LIBRARY, 1); + append_option (OPT_l, RUST_LIBRARY, 1); #ifdef HAVE_LD_STATIC_DYNAMIC - if (force_static) - append_option(OPT_Wl_, "-Bdynamic", 1); + if (force_static) + append_option (OPT_Wl_, "-Bdynamic", 1); #endif } -/* Modeled closely of gcc/fortran/gfortranspec.c - * Called before processing to change/add/remove arguments. - * */ -void lang_specific_driver(struct cl_decoded_option** in_decoded_options, - unsigned int* in_decoded_options_count, - int* in_added_libraries ATTRIBUTE_UNUSED) { - unsigned int i = 0; - unsigned int argc = *in_decoded_options_count; - // Argument list - struct cl_decoded_option* decoded_options = *in_decoded_options; +/* Modeled closely of gcc/fortran/gfortranspec.c */ + +void lang_specific_driver( struct cl_decoded_option **in_decoded_options, + unsigned int *in_decoded_options_count, + int *in_added_libraries ATTRIBUTE_UNUSED ) +{ + unsigned int i = 0; + unsigned int argc = *in_decoded_options_count; + struct cl_decoded_option *decoded_options = *in_decoded_options; - int verbose = 0; + int verbose = 0; - /* This will be NULL if we encounter a situation where we should not - * link in libf2c. - * */ - const char* library = RUST_LIBRARY; + /* This will be NULL if we encounter a situation where we should not + link in libf2c. */ + const char *library = RUST_LIBRARY; - /* 0 => -xnone in effect. - * 1 => -xfoo in effect. - * */ - int saw_speclang = 0; + /* 0 => -xnone in effect. + 1 => -xfoo in effect. */ + int saw_speclang = 0; - /* 0 => initial/reset state - * 1 => last arg was -l<library> - * 2 => last two args were -l<library> -lm. - * */ - int saw_library = 0; + /* 0 => initial/reset state + 1 => last arg was -l<library> + 2 => last two args were -l<library> -lm. */ + int saw_library = 0; - /* By default, we throw on the math library if we have one. */ - int need_math = (MATH_LIBRARY[0] != '\0'); + /* By default, we throw on the math library if we have one. */ + int need_math = (MATH_LIBRARY[0] != '\0'); - /* Whether we should link a static libgrsthon. */ - int static_lib = 0; + /* Whether we should link a static libgrsthon. */ + int static_lib = 0; - /* Whether we need to link statically. */ - int static_linking = 0; + /* Whether we need to link statically. */ + int static_linking = 0; - /* The number of input and output files in the incoming arg list. */ - int n_infiles = 0; - int n_outfiles = 0; + /* The number of input and output files in the incoming arg list. */ + int n_infiles = 0; + int n_outfiles = 0; #if 0 - fprintf (stderr, "Incoming:"); - for( i=0; i<argc; ++i ) - fprintf (stderr, " %s", decoded_options[i].orig_option_with_args_text); - fprintf (stderr, "\n"); + fprintf (stderr, "Incoming:"); + for( i=0; i<argc; ++i ) + fprintf (stderr, " %s", decoded_options[i].orig_option_with_args_text); + fprintf (stderr, "\n"); #endif - grs_xargc = argc; - grs_x_decoded_options = decoded_options; - grs_newargc = 0; - grs_new_decoded_options = decoded_options; - - for (i = 1; i < argc; ++i) { - switch (decoded_options[i].opt_index) { - case OPT_SPECIAL_input_file: - ++n_infiles; - continue; - - case OPT_nostdlib: - case OPT_nodefaultlibs: - case OPT_c: - case OPT_S: - case OPT_fsyntax_only: - case OPT_E: - /* These options disable linking entirely or linking of the - * standard libraries. - * */ - library = 0; - break; - - /* - case OPT_static_librust: + grs_xargc = argc; + grs_x_decoded_options = decoded_options; + grs_newargc = 0; + grs_new_decoded_options = decoded_options; + + for( i=1; i<argc; ++i ) + { + switch( decoded_options[i].opt_index ) + { + case OPT_SPECIAL_input_file: + ++n_infiles; + continue; + + case OPT_nostdlib: + case OPT_nodefaultlibs: + case OPT_c: + case OPT_S: + case OPT_fsyntax_only: + case OPT_E: + /* These options disable linking entirely or linking of the + standard libraries. */ + library = 0; + break; + +/* + case OPT_static_librust: #ifdef HAVE_LD_STATIC_DYNAMIC - static_lib = 1; + static_lib = 1; #endif - break; + break; */ - case OPT_static: + case OPT_static: #ifdef HAVE_LD_STATIC_DYNAMIC - static_linking = 1; + static_linking = 1; #endif - break; + break; - case OPT_l: - ++n_infiles; - break; + case OPT_l: + ++n_infiles; + break; - case OPT_o: - ++n_outfiles; - break; + case OPT_o: + ++n_outfiles; + break; - case OPT_v: - verbose = 1; - break; + case OPT_v: + verbose = 1; + break; - case OPT_version: - printf("GNU Rust %s%s\n", pkgversion_string, version_string); - printf("Copyright %s 2013 Free Software Foundation, Inc.\n\n", - _("(C)")); - printf(_("GNU Rust comes with NO WARRANTY, to the extent permitted by law.\n\ + case OPT_version: + printf ("GNU Rust %s%s\n", pkgversion_string, version_string); + printf ("Copyright %s 2013 Free Software Foundation, Inc.\n\n", + _("(C)")); + printf (_("GNU Rust comes with NO WARRANTY, to the extent permitted by law.\n\ You may redistribute copies of GNU Rust\n\ under the terms of the GNU General Public License.\n\ For more information about these matters, see the file named COPYING\n\n")); - exit(0); - break; - - case OPT__help: - /* Let gcc.c handle this, as it has a really - * cool facility for handling --help and --verbose --help. - * */ - return; - - default: - break; - } + exit (0); + break; + + case OPT__help: + /* Let gcc.c handle this, as it has a really + cool facility for handling --help and --verbose --help. */ + return; + + default: + break; + } } - if ((n_outfiles != 0) && (n_infiles == 0)) - fatal_error("no input files; unwilling to write output files"); + if( (n_outfiles != 0) && (n_infiles == 0) ) + fatal_error ("no input files; unwilling to write output files"); /* If there are no input files, no need for the library. */ - if (n_infiles == 0) - library = 0; - - /* Second pass through arglist, transforming arguments as appropriate. */ - append_arg(&decoded_options[0]); /* Start with command name, of course. */ - - for (i = 1; i < argc; ++i) { - if (decoded_options[i].errors & CL_ERR_MISSING_ARG) { - append_arg(&decoded_options[i]); - continue; - } - - if (decoded_options[i].opt_index == OPT_SPECIAL_input_file && decoded_options[i].arg[0] == '\0') { - /* Interesting. Just append as is. */ - append_arg(&decoded_options[i]); - continue; - } - - if (decoded_options[i].opt_index != OPT_l && (decoded_options[i].opt_index != OPT_SPECIAL_input_file || strcmp(decoded_options[i].arg, "-") == 0)) { - /* Not a filename or library. */ - - if (saw_library == 1 && need_math) /* -l<library>. */ - append_option(OPT_l, MATH_LIBRARY, 1); - - saw_library = 0; - - if (decoded_options[i].opt_index == OPT_SPECIAL_input_file) { - append_arg(&decoded_options[i]); /* "-" == Standard input. */ - continue; - } - - if (decoded_options[i].opt_index == OPT_x) { - /* Track input language. */ - const char* lang = decoded_options[i].arg; - saw_speclang = (strcmp(lang, "none") != 0); - } - append_arg(&decoded_options[i]); - continue; - } - - /* A filename/library, not an option. */ - if (saw_speclang) - saw_library = 0; /* -xfoo currently active. */ - else { /* -lfoo or filename. */ - if (decoded_options[i].opt_index == OPT_l && strcmp(decoded_options[i].arg, MATH_LIBRARY) == 0) { - if (saw_library == 1) - saw_library = 2; /* -l<library> -lm. */ - else - add_arg_libgrust(static_lib && !static_linking); - } else if (decoded_options[i].opt_index == OPT_l && strcmp(decoded_options[i].arg, RUST_LIBRARY) == 0) { - saw_library = 1; /* -l<library>. */ - add_arg_libgrust(static_lib && !static_linking); - continue; - } else { /* Other library, or filename. */ - if (saw_library == 1 && need_math) - append_option(OPT_l, MATH_LIBRARY, 1); - saw_library = 0; - } - } - append_arg(&decoded_options[i]); + if (n_infiles == 0) + library = 0; + + /* Second pass through arglist, transforming arguments as appropriate. */ + append_arg (&decoded_options[0]); /* Start with command name, of course. */ + + for (i = 1; i < argc; ++i) + { + if (decoded_options[i].errors & CL_ERR_MISSING_ARG) + { + append_arg (&decoded_options[i]); + continue; + } + + if (decoded_options[i].opt_index == OPT_SPECIAL_input_file + && decoded_options[i].arg[0] == '\0') + { + /* Interesting. Just append as is. */ + append_arg (&decoded_options[i]); + continue; + } + + if (decoded_options[i].opt_index != OPT_l + && (decoded_options[i].opt_index != OPT_SPECIAL_input_file + || strcmp (decoded_options[i].arg, "-") == 0)) + { + /* Not a filename or library. */ + + if (saw_library == 1 && need_math) /* -l<library>. */ + append_option (OPT_l, MATH_LIBRARY, 1); + + saw_library = 0; + + if (decoded_options[i].opt_index == OPT_SPECIAL_input_file) + { + append_arg (&decoded_options[i]); /* "-" == Standard input. */ + continue; + } + + if (decoded_options[i].opt_index == OPT_x) + { + /* Track input language. */ + const char *lang = decoded_options[i].arg; + saw_speclang = (strcmp (lang, "none") != 0); + } + append_arg (&decoded_options[i]); + continue; + } + + /* A filename/library, not an option. */ + + if (saw_speclang) + saw_library = 0; /* -xfoo currently active. */ + else + { /* -lfoo or filename. */ + if (decoded_options[i].opt_index == OPT_l + && strcmp (decoded_options[i].arg, MATH_LIBRARY) == 0) + { + if (saw_library == 1) + saw_library = 2; /* -l<library> -lm. */ + else + add_arg_libgrust (static_lib && !static_linking); + } + else if (decoded_options[i].opt_index == OPT_l + && strcmp (decoded_options[i].arg, RUST_LIBRARY) == 0) + { + saw_library = 1; /* -l<library>. */ + add_arg_libgrust (static_lib && !static_linking); + continue; + } + else + { /* Other library, or filename. */ + if (saw_library == 1 && need_math) + append_option (OPT_l, MATH_LIBRARY, 1); + saw_library = 0; + } + } + append_arg (&decoded_options[i]); } - /* Append `-lrust -lm' as necessary. */ - if (library) { /* Doing a link and no -nostdlib. */ - if (saw_speclang) - append_option(OPT_x, "none", 1); - - switch (saw_library) { - case 0: - add_arg_libgrust(static_lib && !static_linking); - /* Fall through. */ - case 1: - if (need_math) - append_option(OPT_l, MATH_LIBRARY, 1); - default: - break; - } + /* Append `-lrust -lm' as necessary. */ + + if (library) + { /* Doing a link and no -nostdlib. */ + if (saw_speclang) + append_option (OPT_x, "none", 1); + + switch (saw_library) + { + case 0: + add_arg_libgrust (static_lib && !static_linking); + /* Fall through. */ + case 1: + if (need_math) + append_option (OPT_l, MATH_LIBRARY, 1); + default: + break; + } } #ifdef ENABLE_SHARED_LIBGCC - if (library) { - unsigned int i; + if (library) + { + unsigned int i; - for (i = 1; i < grs_newargc; i++) - if (grs_new_decoded_options[i].opt_index == OPT_static_libgcc || grs_new_decoded_options[i].opt_index == OPT_static) - break; + for (i = 1; i < grs_newargc; i++) + if (grs_new_decoded_options[i].opt_index == OPT_static_libgcc + || grs_new_decoded_options[i].opt_index == OPT_static) + break; - if (i == grs_newargc) - append_option(OPT_shared_libgcc, NULL, 1); + if (i == grs_newargc) + append_option (OPT_shared_libgcc, NULL, 1); } #endif - if (verbose && grs_new_decoded_options != grs_x_decoded_options) { - fprintf(stderr, _("Driving:")); - for (i = 0; i < grs_newargc; i++) - fprintf(stderr, " %s", grs_new_decoded_options[i].orig_option_with_args_text); - fprintf(stderr, "\n"); + if (verbose && grs_new_decoded_options != grs_x_decoded_options) + { + fprintf (stderr, _("Driving:")); + for (i = 0; i < grs_newargc; i++) + fprintf (stderr, " %s", + grs_new_decoded_options[i].orig_option_with_args_text); + fprintf (stderr, "\n"); } - *in_decoded_options_count = grs_newargc; - *in_decoded_options = grs_new_decoded_options; + *in_decoded_options_count = grs_newargc; + *in_decoded_options = grs_new_decoded_options; } /* Called before linking. Returns 0 on success and -1 on failure. */ -int lang_specific_pre_link(void) { // Not used - return 0; +int lang_specific_pre_link (void) +{ + return 0; } /* Number of extra output files that lang_specific_pre_link may generate. */ -int lang_specific_extra_outfiles = 0; // Not used +int lang_specific_extra_outfiles = 0; diff --git a/gcc/rust/old/rust.h b/gcc/rust/old/rust.h index 10b2a13..4a1a6d1 100644 --- a/gcc/rust/old/rust.h +++ b/gcc/rust/old/rust.h @@ -21,41 +21,41 @@ along with GCC; see the file COPYING3. If not see // These must be included before the #poison declarations in system.h. #include <algorithm> +#include <string> #include <list> #include <map> #include <set> -#include <string> #include <vector> +#include "system.h" #include "ansidecl.h" -#include "basic-block.h" -#include "cgraph.h" -#include "common/common-target.h" -#include "convert.h" #include "coretypes.h" -#include "debug.h" -#include "diagnostic-core.h" -#include "diagnostic.h" -#include "flags.h" +#include "opts.h" +#include "tree.h" +#include "tree-iterator.h" +#include "tree-pass.h" +#include "basic-block.h" #include "gimple-expr.h" #include "gimplify.h" -#include "input.h" -#include "langhooks-def.h" -#include "langhooks.h" -#include "options.h" -#include "opts.h" -#include "print-tree.h" #include "stor-layout.h" -#include "stringpool.h" -#include "system.h" -#include "target.h" #include "toplev.h" -#include "tree-iterator.h" -#include "tree-pass.h" -#include "tree.h" +#include "debug.h" +#include "options.h" +#include "flags.h" +#include "convert.h" +#include "diagnostic.h" +#include "langhooks.h" +#include "langhooks-def.h" +#include "target.h" +#include "common/common-target.h" +#include "diagnostic-core.h" +#include "cgraph.h" #include "varasm.h" -#include <hashtab.h> +#include "stringpool.h" +#include "print-tree.h" #include <vec.h> +#include <hashtab.h> +#include "input.h" #include <gmp.h> #include <mpfr.h> @@ -63,40 +63,37 @@ along with GCC; see the file COPYING3. If not see #include "rdot-impl.h" #if !defined(YYLTYPE) -// Location as used in grs - line and column numbers typedef struct grs_location { - int line; - int column; + int line; + int column; } grs_location_t; -// The location of a type? typedef grs_location_t YYLTYPE; -// The location of a type? #define YYLTYPE YYLTYPE #endif -extern char* GRS_current_infile; -extern char* GRS_current_infname; +extern char * GRS_current_infile; +extern char * GRS_current_infname; /* important langhook prototypes */ -extern void grs_set_prefix(const char*); -extern void grs_preserve_from_gc(tree); -extern void grs_add_search_path(const char*); -extern void grs_parse_input_files(const char**, unsigned int); -extern tree grs_type_for_size(unsigned int, int); -extern tree grs_type_for_mode(enum machine_mode, int); +extern void grs_set_prefix (const char *); +extern void grs_preserve_from_gc (tree); +extern void grs_add_search_path (const char *); +extern void grs_parse_input_files (const char **, unsigned int); +extern tree grs_type_for_size (unsigned int, int); +extern tree grs_type_for_mode (enum machine_mode, int); -extern bool grs_do_compile(const char*); +extern bool grs_do_compile (const char *); /* rdot pass manager */ extern tree cstring_type_node; -extern vec<rdot, va_gc>* dot_pass_inferTypes(vec<rdot, va_gc>*); -extern vec<rdot, va_gc>* dot_pass_PrettyPrint(vec<rdot, va_gc>*); -extern vec<tree, va_gc>* dot_pass_Genericify(vec<rdot, va_gc>*); -extern void dot_pass_pushDecl(rdot); -extern void dot_pass_WriteGlobals(void); +extern vec<rdot,va_gc> * dot_pass_inferTypes (vec<rdot,va_gc> *); +extern vec<rdot,va_gc> * dot_pass_PrettyPrint (vec<rdot,va_gc> *); +extern vec<tree,va_gc> * dot_pass_Genericify (vec<rdot,va_gc> *); +extern void dot_pass_pushDecl (rdot); +extern void dot_pass_WriteGlobals (void); /* hooks */ -extern void rs_fill_runtime_decls(std::map<std::string, tree>*); +extern void rs_fill_runtime_decls (std::map<std::string, tree> *); #endif //__GCC_RUST_H__ diff --git a/gcc/rust/old/y.rs.h b/gcc/rust/old/y.rs.h index 1ce15a4..d0246a2 100644 --- a/gcc/rust/old/y.rs.h +++ b/gcc/rust/old/y.rs.h @@ -1,7 +1,6 @@ #ifndef __Y_RS_H__ #define __Y_RS_H__ -// Enum containing tokens for lexer enum yytokentype { IMPL = 258, AS = 259, @@ -46,16 +45,14 @@ enum yytokentype { FLOAT = 298 }; -// Maybe type of character or whatever comes out of the lexer? union yystype { rdot symbol; char * string; int integer; float ffloat; bool boolean; -}; +} ; -// L-val of whatever comes out of lexer? extern yystype yylval; #endif //__Y_RS_H__ diff --git a/gcc/rust/rust-c.h b/gcc/rust/rust-c.h index aba7d38..d75d9e7 100644 --- a/gcc/rust/rust-c.h +++ b/gcc/rust/rust-c.h @@ -22,27 +22,24 @@ along with GCC; see the file COPYING3. If not see #define RUST_EXTERN_C -/* Functions defined in the Rust frontend proper called by the GCC - interface. */ -extern void rust_add_search_path (const char*); +class Linemap; -extern void rust_parse_input_files (const char**, unsigned int, - bool only_check_syntax); -extern void rust_write_globals (void); +extern Linemap* rust_get_linemap(); + +extern void rust_create_rustly(bool only_check_syntax, Linemap* linemap); + +extern void rust_parse_input_files (const char**, unsigned int); + +extern unsigned int rust_field_alignment (tree); -/* Functions defined in the GCC interface called by the Rust frontend - proper. */ +extern void rust_write_globals (void); extern void rust_preserve_from_gc (tree); extern bool saw_errors (void); -extern const char *rust_localize_identifier (const char*); - extern unsigned int rust_field_alignment (tree); -extern void rust_imported_unsafe (void); - -extern GTY(()) tree rust_non_zero_struct; +extern void rust_write_export_data (const char *, unsigned int); #endif /* !defined(RUST_RUST_C_H) */ diff --git a/gcc/rust/rust-gcc-diagnostics.cc b/gcc/rust/rust-gcc-diagnostics.cc index fbbd7a8..fd9c63d 100644 --- a/gcc/rust/rust-gcc-diagnostics.cc +++ b/gcc/rust/rust-gcc-diagnostics.cc @@ -10,10 +10,9 @@ rust_be_error_at(const Location location, const std::string& errmsg) error_at(gcc_loc, "%s", errmsg.c_str()); } - void rust_be_warning_at(const Location location, - int opt, const std::string& warningmsg) + int opt, const std::string& warningmsg) { location_t gcc_loc = location.gcc_location(); warning_at(gcc_loc, opt, "%s", warningmsg.c_str()); @@ -21,7 +20,7 @@ rust_be_warning_at(const Location location, void rust_be_fatal_error(const Location location, - const std::string& fatalmsg) + const std::string& fatalmsg) { location_t gcc_loc = location.gcc_location(); fatal_error(gcc_loc, "%s", fatalmsg.c_str()); @@ -29,7 +28,7 @@ rust_be_fatal_error(const Location location, void rust_be_inform(const Location location, - const std::string& infomsg) + const std::string& infomsg) { location_t gcc_loc = location.gcc_location(); inform(gcc_loc, "%s", infomsg.c_str()); diff --git a/gcc/rust/rust-gcc.cc b/gcc/rust/rust-gcc.cc new file mode 100644 index 0000000..8580f09 --- /dev/null +++ b/gcc/rust/rust-gcc.cc @@ -0,0 +1,3513 @@ +// go-gcc.cc -- Go frontend to gcc IR. +// Copyright (C) 2011-2019 Free Software Foundation, Inc. +// Contributed by Ian Lance Taylor, Google. + +// This file is part of GCC. + +// GCC 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 3, or (at your option) any later +// version. + +// GCC 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 GCC; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include "rust-system.h" + +// This has to be included outside of extern "C", so we have to +// include it here before tree.h includes it later. +#include <gmp.h> + +#include "tree.h" +#include "opts.h" +#include "fold-const.h" +#include "stringpool.h" +#include "stor-layout.h" +#include "varasm.h" +#include "tree-iterator.h" +#include "tm.h" +#include "function.h" +#include "cgraph.h" +#include "convert.h" +#include "gimple-expr.h" +#include "gimplify.h" +#include "langhooks.h" +#include "toplev.h" +#include "output.h" +#include "realmpfr.h" +#include "builtins.h" + +#include "rust-c.h" +#include "rust-location.h" +#include "rust-linemap.h" +#include "backend.h" + +// A class wrapping a tree. + +class Gcc_tree +{ + public: + Gcc_tree(tree t) + : t_(t) + { } + + tree + get_tree() const + { return this->t_; } + + void + set_tree(tree t) + { this->t_ = t; } + + private: + tree t_; +}; + +// In gcc, types, expressions, and statements are all trees. +class Btype : public Gcc_tree +{ + public: + Btype(tree t) + : Gcc_tree(t) + { } +}; + +class Bexpression : public Gcc_tree +{ + public: + Bexpression(tree t) + : Gcc_tree(t) + { } +}; + +class Bstatement : public Gcc_tree +{ + public: + Bstatement(tree t) + : Gcc_tree(t) + { } +}; + +class Bfunction : public Gcc_tree +{ + public: + Bfunction(tree t) + : Gcc_tree(t) + { } +}; + +class Bblock : public Gcc_tree +{ + public: + Bblock(tree t) + : Gcc_tree(t) + { } +}; + +class Blabel : public Gcc_tree +{ + public: + Blabel(tree t) + : Gcc_tree(t) + { } +}; + +// Bvariable is a bit more complicated, because of zero-sized types. +// The GNU linker does not permit dynamic variables with zero size. +// When we see such a variable, we generate a version of the type with +// non-zero size. However, when referring to the global variable, we +// want an expression of zero size; otherwise, if, say, the global +// variable is passed to a function, we will be passing a +// non-zero-sized value to a zero-sized value, which can lead to a +// miscompilation. + +class Bvariable +{ + public: + Bvariable(tree t) + : t_(t), orig_type_(NULL) + { } + + Bvariable(tree t, tree orig_type) + : t_(t), orig_type_(orig_type) + { } + + // Get the tree for use as an expression. + tree + get_tree(Location) const; + + // Get the actual decl; + tree + get_decl() const + { return this->t_; } + + private: + tree t_; + tree orig_type_; +}; + +// Get the tree of a variable for use as an expression. If this is a +// zero-sized global, create an expression that refers to the decl but +// has zero size. +tree +Bvariable::get_tree(Location location) const +{ + if (this->orig_type_ == NULL + || this->t_ == error_mark_node + || TREE_TYPE(this->t_) == this->orig_type_) + return this->t_; + // Return *(orig_type*)&decl. */ + tree t = build_fold_addr_expr_loc(location.gcc_location(), this->t_); + t = fold_build1_loc(location.gcc_location(), NOP_EXPR, + build_pointer_type(this->orig_type_), t); + return build_fold_indirect_ref_loc(location.gcc_location(), t); +} + +// This file implements the interface between the Go frontend proper +// and the gcc IR. This implements specific instantiations of +// abstract classes defined by the Go frontend proper. The Go +// frontend proper class methods of these classes to generate the +// backend representation. + +class Gcc_backend : public Backend +{ + public: + Gcc_backend(); + + // Types. + + Btype* + error_type() + { return this->make_type(error_mark_node); } + + Btype* + void_type() + { return this->make_type(void_type_node); } + + Btype* + bool_type() + { return this->make_type(boolean_type_node); } + + Btype* + integer_type(bool, int); + + Btype* + float_type(int); + + Btype* + complex_type(int); + + Btype* + pointer_type(Btype*); + + Btype* + function_type(const Btyped_identifier&, + const std::vector<Btyped_identifier>&, + const std::vector<Btyped_identifier>&, + Btype*, + const Location); + + Btype* + struct_type(const std::vector<Btyped_identifier>&); + + Btype* + array_type(Btype*, Bexpression*); + + Btype* + placeholder_pointer_type(const std::string&, Location, bool); + + bool + set_placeholder_pointer_type(Btype*, Btype*); + + bool + set_placeholder_function_type(Btype*, Btype*); + + Btype* + placeholder_struct_type(const std::string&, Location); + + bool + set_placeholder_struct_type(Btype* placeholder, + const std::vector<Btyped_identifier>&); + + Btype* + placeholder_array_type(const std::string&, Location); + + bool + set_placeholder_array_type(Btype*, Btype*, Bexpression*); + + Btype* + named_type(const std::string&, Btype*, Location); + + Btype* + circular_pointer_type(Btype*, bool); + + bool + is_circular_pointer_type(Btype*); + + int64_t + type_size(Btype*); + + int64_t + type_alignment(Btype*); + + int64_t + type_field_alignment(Btype*); + + int64_t + type_field_offset(Btype*, size_t index); + + // Expressions. + + Bexpression* + zero_expression(Btype*); + + Bexpression* + error_expression() + { return this->make_expression(error_mark_node); } + + Bexpression* + nil_pointer_expression() + { return this->make_expression(null_pointer_node); } + + Bexpression* + var_expression(Bvariable* var, Location); + + Bexpression* + indirect_expression(Btype*, Bexpression* expr, bool known_valid, Location); + + Bexpression* + named_constant_expression(Btype* btype, const std::string& name, + Bexpression* val, Location); + + Bexpression* + integer_constant_expression(Btype* btype, mpz_t val); + + Bexpression* + float_constant_expression(Btype* btype, mpfr_t val); + + Bexpression* + complex_constant_expression(Btype* btype, mpc_t val); + + Bexpression* + string_constant_expression(const std::string& val); + + Bexpression* + boolean_constant_expression(bool val); + + Bexpression* + real_part_expression(Bexpression* bcomplex, Location); + + Bexpression* + imag_part_expression(Bexpression* bcomplex, Location); + + Bexpression* + complex_expression(Bexpression* breal, Bexpression* bimag, Location); + + Bexpression* + convert_expression(Btype* type, Bexpression* expr, Location); + + Bexpression* + function_code_expression(Bfunction*, Location); + + Bexpression* + address_expression(Bexpression*, Location); + + Bexpression* + struct_field_expression(Bexpression*, size_t, Location); + + Bexpression* + compound_expression(Bstatement*, Bexpression*, Location); + + Bexpression* + conditional_expression(Bfunction*, Btype*, Bexpression*, Bexpression*, + Bexpression*, Location); + + Bexpression* + unary_expression(Operator, Bexpression*, Location); + + Bexpression* + binary_expression(Operator, Bexpression*, Bexpression*, Location); + + Bexpression* + constructor_expression(Btype*, const std::vector<Bexpression*>&, Location); + + Bexpression* + array_constructor_expression(Btype*, const std::vector<unsigned long>&, + const std::vector<Bexpression*>&, Location); + + Bexpression* + pointer_offset_expression(Bexpression* base, Bexpression* offset, Location); + + Bexpression* + array_index_expression(Bexpression* array, Bexpression* index, Location); + + Bexpression* + call_expression(Bfunction* caller, Bexpression* fn, + const std::vector<Bexpression*>& args, + Bexpression* static_chain, Location); + + // Statements. + + Bstatement* + error_statement() + { return this->make_statement(error_mark_node); } + + Bstatement* + expression_statement(Bfunction*, Bexpression*); + + Bstatement* + init_statement(Bfunction*, Bvariable* var, Bexpression* init); + + Bstatement* + assignment_statement(Bfunction*, Bexpression* lhs, Bexpression* rhs, + Location); + + Bstatement* + return_statement(Bfunction*, const std::vector<Bexpression*>&, + Location); + + Bstatement* + if_statement(Bfunction*, Bexpression* condition, Bblock* then_block, + Bblock* else_block, Location); + + Bstatement* + switch_statement(Bfunction* function, Bexpression* value, + const std::vector<std::vector<Bexpression*> >& cases, + const std::vector<Bstatement*>& statements, + Location); + + Bstatement* + compound_statement(Bstatement*, Bstatement*); + + Bstatement* + statement_list(const std::vector<Bstatement*>&); + + Bstatement* + exception_handler_statement(Bstatement* bstat, Bstatement* except_stmt, + Bstatement* finally_stmt, Location); + + // Blocks. + + Bblock* + block(Bfunction*, Bblock*, const std::vector<Bvariable*>&, + Location, Location); + + void + block_add_statements(Bblock*, const std::vector<Bstatement*>&); + + Bstatement* + block_statement(Bblock*); + + // Variables. + + Bvariable* + error_variable() + { return new Bvariable(error_mark_node); } + + Bvariable* + global_variable(const std::string& var_name, + const std::string& asm_name, + Btype* btype, + bool is_external, + bool is_hidden, + bool in_unique_section, + Location location); + + void + global_variable_set_init(Bvariable*, Bexpression*); + + Bvariable* + local_variable(Bfunction*, const std::string&, Btype*, Bvariable*, bool, + Location); + + Bvariable* + parameter_variable(Bfunction*, const std::string&, Btype*, bool, + Location); + + Bvariable* + static_chain_variable(Bfunction*, const std::string&, Btype*, Location); + + Bvariable* + temporary_variable(Bfunction*, Bblock*, Btype*, Bexpression*, bool, + Location, Bstatement**); + + Bvariable* + implicit_variable(const std::string&, const std::string&, Btype*, + bool, bool, bool, int64_t); + + void + implicit_variable_set_init(Bvariable*, const std::string&, Btype*, + bool, bool, bool, Bexpression*); + + Bvariable* + implicit_variable_reference(const std::string&, const std::string&, Btype*); + + Bvariable* + immutable_struct(const std::string&, const std::string&, + bool, bool, Btype*, Location); + + void + immutable_struct_set_init(Bvariable*, const std::string&, bool, bool, Btype*, + Location, Bexpression*); + + Bvariable* + immutable_struct_reference(const std::string&, const std::string&, + Btype*, Location); + + // Labels. + + Blabel* + label(Bfunction*, const std::string& name, Location); + + Bstatement* + label_definition_statement(Blabel*); + + Bstatement* + goto_statement(Blabel*, Location); + + Bexpression* + label_address(Blabel*, Location); + + // Functions. + + Bfunction* + error_function() + { return this->make_function(error_mark_node); } + + Bfunction* + function(Btype* fntype, const std::string& name, const std::string& asm_name, + unsigned int flags, Location); + + Bstatement* + function_defer_statement(Bfunction* function, Bexpression* undefer, + Bexpression* defer, Location); + + bool + function_set_parameters(Bfunction* function, const std::vector<Bvariable*>&); + + bool + function_set_body(Bfunction* function, Bstatement* code_stmt); + + Bfunction* + lookup_builtin(const std::string&); + + void + write_global_definitions(const std::vector<Btype*>&, + const std::vector<Bexpression*>&, + const std::vector<Bfunction*>&, + const std::vector<Bvariable*>&); + + void + write_export_data(const char* bytes, unsigned int size); + + + private: + // Make a Bexpression from a tree. + Bexpression* + make_expression(tree t) + { return new Bexpression(t); } + + // Make a Bstatement from a tree. + Bstatement* + make_statement(tree t) + { return new Bstatement(t); } + + // Make a Btype from a tree. + Btype* + make_type(tree t) + { return new Btype(t); } + + Bfunction* + make_function(tree t) + { return new Bfunction(t); } + + Btype* + fill_in_struct(Btype*, const std::vector<Btyped_identifier>&); + + Btype* + fill_in_array(Btype*, Btype*, Bexpression*); + + tree + non_zero_size_type(tree); + + tree + convert_tree(tree, tree, Location); + +private: + void + define_builtin(built_in_function bcode, const char* name, const char* libname, + tree fntype, bool const_p, bool noreturn_p); + + // A mapping of the GCC built-ins exposed to GCCGo. + std::map<std::string, Bfunction*> builtin_functions_; +}; + +// A helper function to create a GCC identifier from a C++ string. + +static inline tree +get_identifier_from_string(const std::string& str) +{ + return get_identifier_with_length(str.data(), str.length()); +} + +// Define the built-in functions that are exposed to GCCGo. + +Gcc_backend::Gcc_backend() +{ + /* We need to define the fetch_and_add functions, since we use them + for ++ and --. */ + tree t = this->integer_type(true, BITS_PER_UNIT)->get_tree(); + tree p = build_pointer_type(build_qualified_type(t, TYPE_QUAL_VOLATILE)); + this->define_builtin(BUILT_IN_SYNC_ADD_AND_FETCH_1, "__sync_fetch_and_add_1", + NULL, build_function_type_list(t, p, t, NULL_TREE), + false, false); + + t = this->integer_type(true, BITS_PER_UNIT * 2)->get_tree(); + p = build_pointer_type(build_qualified_type(t, TYPE_QUAL_VOLATILE)); + this->define_builtin(BUILT_IN_SYNC_ADD_AND_FETCH_2, "__sync_fetch_and_add_2", + NULL, build_function_type_list(t, p, t, NULL_TREE), + false, false); + + t = this->integer_type(true, BITS_PER_UNIT * 4)->get_tree(); + p = build_pointer_type(build_qualified_type(t, TYPE_QUAL_VOLATILE)); + this->define_builtin(BUILT_IN_SYNC_ADD_AND_FETCH_4, "__sync_fetch_and_add_4", + NULL, build_function_type_list(t, p, t, NULL_TREE), + false, false); + + t = this->integer_type(true, BITS_PER_UNIT * 8)->get_tree(); + p = build_pointer_type(build_qualified_type(t, TYPE_QUAL_VOLATILE)); + this->define_builtin(BUILT_IN_SYNC_ADD_AND_FETCH_8, "__sync_fetch_and_add_8", + NULL, build_function_type_list(t, p, t, NULL_TREE), + false, false); + + // We use __builtin_expect for magic import functions. + this->define_builtin(BUILT_IN_EXPECT, "__builtin_expect", NULL, + build_function_type_list(long_integer_type_node, + long_integer_type_node, + long_integer_type_node, + NULL_TREE), + true, false); + + // We use __builtin_memcmp for struct comparisons. + this->define_builtin(BUILT_IN_MEMCMP, "__builtin_memcmp", "memcmp", + build_function_type_list(integer_type_node, + const_ptr_type_node, + const_ptr_type_node, + size_type_node, + NULL_TREE), + false, false); + + // We use __builtin_memmove for copying data. + this->define_builtin(BUILT_IN_MEMMOVE, "__builtin_memmove", "memmove", + build_function_type_list(void_type_node, + ptr_type_node, + const_ptr_type_node, + size_type_node, + NULL_TREE), + false, false); + + // We use __builtin_memset for zeroing data. + this->define_builtin(BUILT_IN_MEMSET, "__builtin_memset", "memset", + build_function_type_list(void_type_node, + ptr_type_node, + integer_type_node, + size_type_node, + NULL_TREE), + false, false); + + // Used by runtime/internal/sys and math/bits. + this->define_builtin(BUILT_IN_CTZ, "__builtin_ctz", "ctz", + build_function_type_list(integer_type_node, + unsigned_type_node, + NULL_TREE), + true, false); + this->define_builtin(BUILT_IN_CTZLL, "__builtin_ctzll", "ctzll", + build_function_type_list(integer_type_node, + long_long_unsigned_type_node, + NULL_TREE), + true, false); + this->define_builtin(BUILT_IN_CLZ, "__builtin_clz", "clz", + build_function_type_list(integer_type_node, + unsigned_type_node, + NULL_TREE), + true, false); + this->define_builtin(BUILT_IN_CLZLL, "__builtin_clzll", "clzll", + build_function_type_list(integer_type_node, + long_long_unsigned_type_node, + NULL_TREE), + true, false); + this->define_builtin(BUILT_IN_POPCOUNT, "__builtin_popcount", "popcount", + build_function_type_list(integer_type_node, + unsigned_type_node, + NULL_TREE), + true, false); + this->define_builtin(BUILT_IN_POPCOUNTLL, "__builtin_popcountll", "popcountll", + build_function_type_list(integer_type_node, + long_long_unsigned_type_node, + NULL_TREE), + true, false); + this->define_builtin(BUILT_IN_BSWAP16, "__builtin_bswap16", "bswap16", + build_function_type_list(uint16_type_node, + uint16_type_node, + NULL_TREE), + true, false); + this->define_builtin(BUILT_IN_BSWAP32, "__builtin_bswap32", "bswap32", + build_function_type_list(uint32_type_node, + uint32_type_node, + NULL_TREE), + true, false); + this->define_builtin(BUILT_IN_BSWAP64, "__builtin_bswap64", "bswap64", + build_function_type_list(uint64_type_node, + uint64_type_node, + NULL_TREE), + true, false); + + // We provide some functions for the math library. + tree math_function_type = build_function_type_list(double_type_node, + double_type_node, + NULL_TREE); + tree math_function_type_long = + build_function_type_list(long_double_type_node, long_double_type_node, + NULL_TREE); + tree math_function_type_two = build_function_type_list(double_type_node, + double_type_node, + double_type_node, + NULL_TREE); + tree math_function_type_long_two = + build_function_type_list(long_double_type_node, long_double_type_node, + long_double_type_node, NULL_TREE); + this->define_builtin(BUILT_IN_ACOS, "__builtin_acos", "acos", + math_function_type, true, false); + this->define_builtin(BUILT_IN_ACOSL, "__builtin_acosl", "acosl", + math_function_type_long, true, false); + this->define_builtin(BUILT_IN_ASIN, "__builtin_asin", "asin", + math_function_type, true, false); + this->define_builtin(BUILT_IN_ASINL, "__builtin_asinl", "asinl", + math_function_type_long, true, false); + this->define_builtin(BUILT_IN_ATAN, "__builtin_atan", "atan", + math_function_type, true, false); + this->define_builtin(BUILT_IN_ATANL, "__builtin_atanl", "atanl", + math_function_type_long, true, false); + this->define_builtin(BUILT_IN_ATAN2, "__builtin_atan2", "atan2", + math_function_type_two, true, false); + this->define_builtin(BUILT_IN_ATAN2L, "__builtin_atan2l", "atan2l", + math_function_type_long_two, true, false); + this->define_builtin(BUILT_IN_CEIL, "__builtin_ceil", "ceil", + math_function_type, true, false); + this->define_builtin(BUILT_IN_CEILL, "__builtin_ceill", "ceill", + math_function_type_long, true, false); + this->define_builtin(BUILT_IN_COS, "__builtin_cos", "cos", + math_function_type, true, false); + this->define_builtin(BUILT_IN_COSL, "__builtin_cosl", "cosl", + math_function_type_long, true, false); + this->define_builtin(BUILT_IN_EXP, "__builtin_exp", "exp", + math_function_type, true, false); + this->define_builtin(BUILT_IN_EXPL, "__builtin_expl", "expl", + math_function_type_long, true, false); + this->define_builtin(BUILT_IN_EXPM1, "__builtin_expm1", "expm1", + math_function_type, true, false); + this->define_builtin(BUILT_IN_EXPM1L, "__builtin_expm1l", "expm1l", + math_function_type_long, true, false); + this->define_builtin(BUILT_IN_FABS, "__builtin_fabs", "fabs", + math_function_type, true, false); + this->define_builtin(BUILT_IN_FABSL, "__builtin_fabsl", "fabsl", + math_function_type_long, true, false); + this->define_builtin(BUILT_IN_FLOOR, "__builtin_floor", "floor", + math_function_type, true, false); + this->define_builtin(BUILT_IN_FLOORL, "__builtin_floorl", "floorl", + math_function_type_long, true, false); + this->define_builtin(BUILT_IN_FMOD, "__builtin_fmod", "fmod", + math_function_type_two, true, false); + this->define_builtin(BUILT_IN_FMODL, "__builtin_fmodl", "fmodl", + math_function_type_long_two, true, false); + this->define_builtin(BUILT_IN_LDEXP, "__builtin_ldexp", "ldexp", + build_function_type_list(double_type_node, + double_type_node, + integer_type_node, + NULL_TREE), + true, false); + this->define_builtin(BUILT_IN_LDEXPL, "__builtin_ldexpl", "ldexpl", + build_function_type_list(long_double_type_node, + long_double_type_node, + integer_type_node, + NULL_TREE), + true, false); + this->define_builtin(BUILT_IN_LOG, "__builtin_log", "log", + math_function_type, true, false); + this->define_builtin(BUILT_IN_LOGL, "__builtin_logl", "logl", + math_function_type_long, true, false); + this->define_builtin(BUILT_IN_LOG1P, "__builtin_log1p", "log1p", + math_function_type, true, false); + this->define_builtin(BUILT_IN_LOG1PL, "__builtin_log1pl", "log1pl", + math_function_type_long, true, false); + this->define_builtin(BUILT_IN_LOG10, "__builtin_log10", "log10", + math_function_type, true, false); + this->define_builtin(BUILT_IN_LOG10L, "__builtin_log10l", "log10l", + math_function_type_long, true, false); + this->define_builtin(BUILT_IN_LOG2, "__builtin_log2", "log2", + math_function_type, true, false); + this->define_builtin(BUILT_IN_LOG2L, "__builtin_log2l", "log2l", + math_function_type_long, true, false); + this->define_builtin(BUILT_IN_SIN, "__builtin_sin", "sin", + math_function_type, true, false); + this->define_builtin(BUILT_IN_SINL, "__builtin_sinl", "sinl", + math_function_type_long, true, false); + this->define_builtin(BUILT_IN_SQRT, "__builtin_sqrt", "sqrt", + math_function_type, true, false); + this->define_builtin(BUILT_IN_SQRTL, "__builtin_sqrtl", "sqrtl", + math_function_type_long, true, false); + this->define_builtin(BUILT_IN_TAN, "__builtin_tan", "tan", + math_function_type, true, false); + this->define_builtin(BUILT_IN_TANL, "__builtin_tanl", "tanl", + math_function_type_long, true, false); + this->define_builtin(BUILT_IN_TRUNC, "__builtin_trunc", "trunc", + math_function_type, true, false); + this->define_builtin(BUILT_IN_TRUNCL, "__builtin_truncl", "truncl", + math_function_type_long, true, false); + + // We use __builtin_return_address in the thunk we build for + // functions which call recover, and for runtime.getcallerpc. + t = build_function_type_list(ptr_type_node, unsigned_type_node, NULL_TREE); + this->define_builtin(BUILT_IN_RETURN_ADDRESS, "__builtin_return_address", + NULL, t, false, false); + + // The runtime calls __builtin_dwarf_cfa for runtime.getcallersp. + t = build_function_type_list(ptr_type_node, NULL_TREE); + this->define_builtin(BUILT_IN_DWARF_CFA, "__builtin_dwarf_cfa", + NULL, t, false, false); + + // The runtime calls __builtin_extract_return_addr when recording + // the address to which a function returns. + this->define_builtin(BUILT_IN_EXTRACT_RETURN_ADDR, + "__builtin_extract_return_addr", NULL, + build_function_type_list(ptr_type_node, + ptr_type_node, + NULL_TREE), + false, false); + + // The compiler uses __builtin_trap for some exception handling + // cases. + this->define_builtin(BUILT_IN_TRAP, "__builtin_trap", NULL, + build_function_type(void_type_node, void_list_node), + false, true); + + // The runtime uses __builtin_prefetch. + this->define_builtin(BUILT_IN_PREFETCH, "__builtin_prefetch", NULL, + build_varargs_function_type_list(void_type_node, + const_ptr_type_node, + NULL_TREE), + false, false); + + // The compiler uses __builtin_unreachable for cases that cannot + // occur. + this->define_builtin(BUILT_IN_UNREACHABLE, "__builtin_unreachable", NULL, + build_function_type(void_type_node, void_list_node), + true, true); + + // We provide some atomic functions. + t = build_function_type_list(uint32_type_node, + ptr_type_node, + integer_type_node, + NULL_TREE); + this->define_builtin(BUILT_IN_ATOMIC_LOAD_4, "__atomic_load_4", NULL, + t, false, false); + + t = build_function_type_list(uint64_type_node, + ptr_type_node, + integer_type_node, + NULL_TREE); + this->define_builtin(BUILT_IN_ATOMIC_LOAD_8, "__atomic_load_8", NULL, + t, false, false); + + t = build_function_type_list(void_type_node, + ptr_type_node, + uint32_type_node, + integer_type_node, + NULL_TREE); + this->define_builtin(BUILT_IN_ATOMIC_STORE_4, "__atomic_store_4", NULL, + t, false, false); + + t = build_function_type_list(void_type_node, + ptr_type_node, + uint64_type_node, + integer_type_node, + NULL_TREE); + this->define_builtin(BUILT_IN_ATOMIC_STORE_8, "__atomic_store_8", NULL, + t, false, false); + + t = build_function_type_list(uint32_type_node, + ptr_type_node, + uint32_type_node, + integer_type_node, + NULL_TREE); + this->define_builtin(BUILT_IN_ATOMIC_EXCHANGE_4, "__atomic_exchange_4", NULL, + t, false, false); + + t = build_function_type_list(uint64_type_node, + ptr_type_node, + uint64_type_node, + integer_type_node, + NULL_TREE); + this->define_builtin(BUILT_IN_ATOMIC_EXCHANGE_8, "__atomic_exchange_8", NULL, + t, false, false); + + t = build_function_type_list(boolean_type_node, + ptr_type_node, + ptr_type_node, + uint32_type_node, + boolean_type_node, + integer_type_node, + integer_type_node, + NULL_TREE); + this->define_builtin(BUILT_IN_ATOMIC_COMPARE_EXCHANGE_4, + "__atomic_compare_exchange_4", NULL, + t, false, false); + + t = build_function_type_list(boolean_type_node, + ptr_type_node, + ptr_type_node, + uint64_type_node, + boolean_type_node, + integer_type_node, + integer_type_node, + NULL_TREE); + this->define_builtin(BUILT_IN_ATOMIC_COMPARE_EXCHANGE_8, + "__atomic_compare_exchange_8", NULL, + t, false, false); + + t = build_function_type_list(uint32_type_node, + ptr_type_node, + uint32_type_node, + integer_type_node, + NULL_TREE); + this->define_builtin(BUILT_IN_ATOMIC_ADD_FETCH_4, "__atomic_add_fetch_4", NULL, + t, false, false); + + t = build_function_type_list(uint64_type_node, + ptr_type_node, + uint64_type_node, + integer_type_node, + NULL_TREE); + this->define_builtin(BUILT_IN_ATOMIC_ADD_FETCH_8, "__atomic_add_fetch_8", NULL, + t, false, false); + + t = build_function_type_list(unsigned_char_type_node, + ptr_type_node, + unsigned_char_type_node, + integer_type_node, + NULL_TREE); + this->define_builtin(BUILT_IN_ATOMIC_AND_FETCH_1, "__atomic_and_fetch_1", NULL, + t, false, false); + this->define_builtin(BUILT_IN_ATOMIC_FETCH_AND_1, "__atomic_fetch_and_1", NULL, + t, false, false); + + t = build_function_type_list(unsigned_char_type_node, + ptr_type_node, + unsigned_char_type_node, + integer_type_node, + NULL_TREE); + this->define_builtin(BUILT_IN_ATOMIC_OR_FETCH_1, "__atomic_or_fetch_1", NULL, + t, false, false); + this->define_builtin(BUILT_IN_ATOMIC_FETCH_OR_1, "__atomic_fetch_or_1", NULL, + t, false, false); +} + +// Get an unnamed integer type. + +Btype* +Gcc_backend::integer_type(bool is_unsigned, int bits) +{ + tree type; + if (is_unsigned) + { + if (bits == INT_TYPE_SIZE) + type = unsigned_type_node; + else if (bits == CHAR_TYPE_SIZE) + type = unsigned_char_type_node; + else if (bits == SHORT_TYPE_SIZE) + type = short_unsigned_type_node; + else if (bits == LONG_TYPE_SIZE) + type = long_unsigned_type_node; + else if (bits == LONG_LONG_TYPE_SIZE) + type = long_long_unsigned_type_node; + else + type = make_unsigned_type(bits); + } + else + { + if (bits == INT_TYPE_SIZE) + type = integer_type_node; + else if (bits == CHAR_TYPE_SIZE) + type = signed_char_type_node; + else if (bits == SHORT_TYPE_SIZE) + type = short_integer_type_node; + else if (bits == LONG_TYPE_SIZE) + type = long_integer_type_node; + else if (bits == LONG_LONG_TYPE_SIZE) + type = long_long_integer_type_node; + else + type = make_signed_type(bits); + } + return this->make_type(type); +} + +// Get an unnamed float type. + +Btype* +Gcc_backend::float_type(int bits) +{ + tree type; + if (bits == FLOAT_TYPE_SIZE) + type = float_type_node; + else if (bits == DOUBLE_TYPE_SIZE) + type = double_type_node; + else if (bits == LONG_DOUBLE_TYPE_SIZE) + type = long_double_type_node; + else + { + type = make_node(REAL_TYPE); + TYPE_PRECISION(type) = bits; + layout_type(type); + } + return this->make_type(type); +} + +// Get an unnamed complex type. + +Btype* +Gcc_backend::complex_type(int bits) +{ + tree type; + if (bits == FLOAT_TYPE_SIZE * 2) + type = complex_float_type_node; + else if (bits == DOUBLE_TYPE_SIZE * 2) + type = complex_double_type_node; + else if (bits == LONG_DOUBLE_TYPE_SIZE * 2) + type = complex_long_double_type_node; + else + { + type = make_node(REAL_TYPE); + TYPE_PRECISION(type) = bits / 2; + layout_type(type); + type = build_complex_type(type); + } + return this->make_type(type); +} + +// Get a pointer type. + +Btype* +Gcc_backend::pointer_type(Btype* to_type) +{ + tree to_type_tree = to_type->get_tree(); + if (to_type_tree == error_mark_node) + return this->error_type(); + tree type = build_pointer_type(to_type_tree); + return this->make_type(type); +} + +// Make a function type. + +Btype* +Gcc_backend::function_type(const Btyped_identifier& receiver, + const std::vector<Btyped_identifier>& parameters, + const std::vector<Btyped_identifier>& results, + Btype* result_struct, + Location) +{ + tree args = NULL_TREE; + tree* pp = &args; + if (receiver.btype != NULL) + { + tree t = receiver.btype->get_tree(); + if (t == error_mark_node) + return this->error_type(); + *pp = tree_cons(NULL_TREE, t, NULL_TREE); + pp = &TREE_CHAIN(*pp); + } + + for (std::vector<Btyped_identifier>::const_iterator p = parameters.begin(); + p != parameters.end(); + ++p) + { + tree t = p->btype->get_tree(); + if (t == error_mark_node) + return this->error_type(); + *pp = tree_cons(NULL_TREE, t, NULL_TREE); + pp = &TREE_CHAIN(*pp); + } + + // Varargs is handled entirely at the Go level. When converted to + // GENERIC functions are not varargs. + *pp = void_list_node; + + tree result; + if (results.empty()) + result = void_type_node; + else if (results.size() == 1) + result = results.front().btype->get_tree(); + else + { + gcc_assert(result_struct != NULL); + result = result_struct->get_tree(); + } + if (result == error_mark_node) + return this->error_type(); + + // The libffi library cannot represent a zero-sized object. To + // avoid causing confusion on 32-bit SPARC, we treat a function that + // returns a zero-sized value as returning void. That should do no + // harm since there is no actual value to be returned. See + // https://gcc.gnu.org/PR72814 for details. + if (result != void_type_node && int_size_in_bytes(result) == 0) + result = void_type_node; + + tree fntype = build_function_type(result, args); + if (fntype == error_mark_node) + return this->error_type(); + + return this->make_type(build_pointer_type(fntype)); +} + +// Make a struct type. + +Btype* +Gcc_backend::struct_type(const std::vector<Btyped_identifier>& fields) +{ + return this->fill_in_struct(this->make_type(make_node(RECORD_TYPE)), fields); +} + +// Fill in the fields of a struct type. + +Btype* +Gcc_backend::fill_in_struct(Btype* fill, + const std::vector<Btyped_identifier>& fields) +{ + tree fill_tree = fill->get_tree(); + tree field_trees = NULL_TREE; + tree* pp = &field_trees; + for (std::vector<Btyped_identifier>::const_iterator p = fields.begin(); + p != fields.end(); + ++p) + { + tree name_tree = get_identifier_from_string(p->name); + tree type_tree = p->btype->get_tree(); + if (type_tree == error_mark_node) + return this->error_type(); + tree field = build_decl(p->location.gcc_location(), FIELD_DECL, name_tree, + type_tree); + DECL_CONTEXT(field) = fill_tree; + *pp = field; + pp = &DECL_CHAIN(field); + } + TYPE_FIELDS(fill_tree) = field_trees; + layout_type(fill_tree); + + // Because Go permits converting between named struct types and + // equivalent struct types, for which we use VIEW_CONVERT_EXPR, and + // because we don't try to maintain TYPE_CANONICAL for struct types, + // we need to tell the middle-end to use structural equality. + SET_TYPE_STRUCTURAL_EQUALITY(fill_tree); + + return fill; +} + +// Make an array type. + +Btype* +Gcc_backend::array_type(Btype* element_btype, Bexpression* length) +{ + return this->fill_in_array(this->make_type(make_node(ARRAY_TYPE)), + element_btype, length); +} + +// Fill in an array type. + +Btype* +Gcc_backend::fill_in_array(Btype* fill, Btype* element_type, + Bexpression* length) +{ + tree element_type_tree = element_type->get_tree(); + tree length_tree = length->get_tree(); + if (element_type_tree == error_mark_node || length_tree == error_mark_node) + return this->error_type(); + + gcc_assert(TYPE_SIZE(element_type_tree) != NULL_TREE); + + length_tree = fold_convert(sizetype, length_tree); + + // build_index_type takes the maximum index, which is one less than + // the length. + tree index_type_tree = build_index_type(fold_build2(MINUS_EXPR, sizetype, + length_tree, + size_one_node)); + + tree fill_tree = fill->get_tree(); + TREE_TYPE(fill_tree) = element_type_tree; + TYPE_DOMAIN(fill_tree) = index_type_tree; + TYPE_ADDR_SPACE(fill_tree) = TYPE_ADDR_SPACE(element_type_tree); + layout_type(fill_tree); + + if (TYPE_STRUCTURAL_EQUALITY_P(element_type_tree)) + SET_TYPE_STRUCTURAL_EQUALITY(fill_tree); + else if (TYPE_CANONICAL(element_type_tree) != element_type_tree + || TYPE_CANONICAL(index_type_tree) != index_type_tree) + TYPE_CANONICAL(fill_tree) = + build_array_type(TYPE_CANONICAL(element_type_tree), + TYPE_CANONICAL(index_type_tree)); + + return fill; +} + +// Create a placeholder for a pointer type. + +Btype* +Gcc_backend::placeholder_pointer_type(const std::string& name, + Location location, bool) +{ + tree ret = build_distinct_type_copy(ptr_type_node); + if (!name.empty()) + { + tree decl = build_decl(location.gcc_location(), TYPE_DECL, + get_identifier_from_string(name), + ret); + TYPE_NAME(ret) = decl; + } + return this->make_type(ret); +} + +// Set the real target type for a placeholder pointer type. + +bool +Gcc_backend::set_placeholder_pointer_type(Btype* placeholder, + Btype* to_type) +{ + tree pt = placeholder->get_tree(); + if (pt == error_mark_node) + return false; + gcc_assert(TREE_CODE(pt) == POINTER_TYPE); + tree tt = to_type->get_tree(); + if (tt == error_mark_node) + { + placeholder->set_tree(error_mark_node); + return false; + } + gcc_assert(TREE_CODE(tt) == POINTER_TYPE); + TREE_TYPE(pt) = TREE_TYPE(tt); + TYPE_CANONICAL(pt) = TYPE_CANONICAL(tt); + if (TYPE_NAME(pt) != NULL_TREE) + { + // Build the data structure gcc wants to see for a typedef. + tree copy = build_variant_type_copy(pt); + TYPE_NAME(copy) = NULL_TREE; + DECL_ORIGINAL_TYPE(TYPE_NAME(pt)) = copy; + } + return true; +} + +// Set the real values for a placeholder function type. + +bool +Gcc_backend::set_placeholder_function_type(Btype* placeholder, Btype* ft) +{ + return this->set_placeholder_pointer_type(placeholder, ft); +} + +// Create a placeholder for a struct type. + +Btype* +Gcc_backend::placeholder_struct_type(const std::string& name, + Location location) +{ + tree ret = make_node(RECORD_TYPE); + if (!name.empty()) + { + tree decl = build_decl(location.gcc_location(), TYPE_DECL, + get_identifier_from_string(name), + ret); + TYPE_NAME(ret) = decl; + + // The struct type that eventually replaces this placeholder will require + // structural equality. The placeholder must too, so that the requirement + // for structural equality propagates to references that are constructed + // before the replacement occurs. + SET_TYPE_STRUCTURAL_EQUALITY(ret); + } + return this->make_type(ret); +} + +// Fill in the fields of a placeholder struct type. + +bool +Gcc_backend::set_placeholder_struct_type( + Btype* placeholder, + const std::vector<Btyped_identifier>& fields) +{ + tree t = placeholder->get_tree(); + gcc_assert(TREE_CODE(t) == RECORD_TYPE && TYPE_FIELDS(t) == NULL_TREE); + Btype* r = this->fill_in_struct(placeholder, fields); + + if (TYPE_NAME(t) != NULL_TREE) + { + // Build the data structure gcc wants to see for a typedef. + tree copy = build_distinct_type_copy(t); + TYPE_NAME(copy) = NULL_TREE; + DECL_ORIGINAL_TYPE(TYPE_NAME(t)) = copy; + TYPE_SIZE(copy) = NULL_TREE; + Btype* bc = this->make_type(copy); + this->fill_in_struct(bc, fields); + delete bc; + } + + return r->get_tree() != error_mark_node; +} + +// Create a placeholder for an array type. + +Btype* +Gcc_backend::placeholder_array_type(const std::string& name, + Location location) +{ + tree ret = make_node(ARRAY_TYPE); + tree decl = build_decl(location.gcc_location(), TYPE_DECL, + get_identifier_from_string(name), + ret); + TYPE_NAME(ret) = decl; + return this->make_type(ret); +} + +// Fill in the fields of a placeholder array type. + +bool +Gcc_backend::set_placeholder_array_type(Btype* placeholder, + Btype* element_btype, + Bexpression* length) +{ + tree t = placeholder->get_tree(); + gcc_assert(TREE_CODE(t) == ARRAY_TYPE && TREE_TYPE(t) == NULL_TREE); + Btype* r = this->fill_in_array(placeholder, element_btype, length); + + // Build the data structure gcc wants to see for a typedef. + tree copy = build_distinct_type_copy(t); + TYPE_NAME(copy) = NULL_TREE; + DECL_ORIGINAL_TYPE(TYPE_NAME(t)) = copy; + + return r->get_tree() != error_mark_node; +} + +// Return a named version of a type. + +Btype* +Gcc_backend::named_type(const std::string& name, Btype* btype, + Location location) +{ + tree type = btype->get_tree(); + if (type == error_mark_node) + return this->error_type(); + + // The middle-end expects a basic type to have a name. In Go every + // basic type will have a name. The first time we see a basic type, + // give it whatever Go name we have at this point. + if (TYPE_NAME(type) == NULL_TREE + && location.gcc_location() == BUILTINS_LOCATION + && (TREE_CODE(type) == INTEGER_TYPE + || TREE_CODE(type) == REAL_TYPE + || TREE_CODE(type) == COMPLEX_TYPE + || TREE_CODE(type) == BOOLEAN_TYPE)) + { + tree decl = build_decl(BUILTINS_LOCATION, TYPE_DECL, + get_identifier_from_string(name), + type); + TYPE_NAME(type) = decl; + return this->make_type(type); + } + + tree copy = build_variant_type_copy(type); + tree decl = build_decl(location.gcc_location(), TYPE_DECL, + get_identifier_from_string(name), + copy); + DECL_ORIGINAL_TYPE(decl) = type; + TYPE_NAME(copy) = decl; + return this->make_type(copy); +} + +// Return a pointer type used as a marker for a circular type. + +Btype* +Gcc_backend::circular_pointer_type(Btype*, bool) +{ + return this->make_type(ptr_type_node); +} + +// Return whether we might be looking at a circular type. + +bool +Gcc_backend::is_circular_pointer_type(Btype* btype) +{ + return btype->get_tree() == ptr_type_node; +} + +// Return the size of a type. + +int64_t +Gcc_backend::type_size(Btype* btype) +{ + tree t = btype->get_tree(); + if (t == error_mark_node) + return 1; + if (t == void_type_node) + return 0; + t = TYPE_SIZE_UNIT(t); + gcc_assert(tree_fits_uhwi_p (t)); + unsigned HOST_WIDE_INT val_wide = TREE_INT_CST_LOW(t); + int64_t ret = static_cast<int64_t>(val_wide); + if (ret < 0 || static_cast<unsigned HOST_WIDE_INT>(ret) != val_wide) + return -1; + return ret; +} + +// Return the alignment of a type. + +int64_t +Gcc_backend::type_alignment(Btype* btype) +{ + tree t = btype->get_tree(); + if (t == error_mark_node) + return 1; + return TYPE_ALIGN_UNIT(t); +} + +// Return the alignment of a struct field of type BTYPE. + +int64_t +Gcc_backend::type_field_alignment(Btype* btype) +{ + tree t = btype->get_tree(); + if (t == error_mark_node) + return 1; + return rust_field_alignment(t); +} + +// Return the offset of a field in a struct. + +int64_t +Gcc_backend::type_field_offset(Btype* btype, size_t index) +{ + tree struct_tree = btype->get_tree(); + if (struct_tree == error_mark_node) + return 0; + gcc_assert(TREE_CODE(struct_tree) == RECORD_TYPE); + tree field = TYPE_FIELDS(struct_tree); + for (; index > 0; --index) + { + field = DECL_CHAIN(field); + gcc_assert(field != NULL_TREE); + } + HOST_WIDE_INT offset_wide = int_byte_position(field); + int64_t ret = static_cast<int64_t>(offset_wide); + gcc_assert(ret == offset_wide); + return ret; +} + +// Return the zero value for a type. + +Bexpression* +Gcc_backend::zero_expression(Btype* btype) +{ + tree t = btype->get_tree(); + tree ret; + if (t == error_mark_node) + ret = error_mark_node; + else + ret = build_zero_cst(t); + return this->make_expression(ret); +} + +// An expression that references a variable. + +Bexpression* +Gcc_backend::var_expression(Bvariable* var, Location location) +{ + tree ret = var->get_tree(location); + if (ret == error_mark_node) + return this->error_expression(); + return this->make_expression(ret); +} + +// An expression that indirectly references an expression. + +Bexpression* +Gcc_backend::indirect_expression(Btype* btype, Bexpression* expr, + bool known_valid, Location location) +{ + tree expr_tree = expr->get_tree(); + tree type_tree = btype->get_tree(); + if (expr_tree == error_mark_node || type_tree == error_mark_node) + return this->error_expression(); + + // If the type of EXPR is a recursive pointer type, then we + // need to insert a cast before indirecting. + tree target_type_tree = TREE_TYPE(TREE_TYPE(expr_tree)); + if (VOID_TYPE_P(target_type_tree)) + expr_tree = fold_convert_loc(location.gcc_location(), + build_pointer_type(type_tree), expr_tree); + + tree ret = build_fold_indirect_ref_loc(location.gcc_location(), + expr_tree); + if (known_valid) + TREE_THIS_NOTRAP(ret) = 1; + return this->make_expression(ret); +} + +// Return an expression that declares a constant named NAME with the +// constant value VAL in BTYPE. + +Bexpression* +Gcc_backend::named_constant_expression(Btype* btype, const std::string& name, + Bexpression* val, Location location) +{ + tree type_tree = btype->get_tree(); + tree const_val = val->get_tree(); + if (type_tree == error_mark_node || const_val == error_mark_node) + return this->error_expression(); + + tree name_tree = get_identifier_from_string(name); + tree decl = build_decl(location.gcc_location(), CONST_DECL, name_tree, + type_tree); + DECL_INITIAL(decl) = const_val; + TREE_CONSTANT(decl) = 1; + TREE_READONLY(decl) = 1; + + rust_preserve_from_gc(decl); + return this->make_expression(decl); +} + +// Return a typed value as a constant integer. + +Bexpression* +Gcc_backend::integer_constant_expression(Btype* btype, mpz_t val) +{ + tree t = btype->get_tree(); + if (t == error_mark_node) + return this->error_expression(); + + tree ret = double_int_to_tree(t, mpz_get_double_int(t, val, true)); + return this->make_expression(ret); +} + +// Return a typed value as a constant floating-point number. + +Bexpression* +Gcc_backend::float_constant_expression(Btype* btype, mpfr_t val) +{ + tree t = btype->get_tree(); + tree ret; + if (t == error_mark_node) + return this->error_expression(); + + REAL_VALUE_TYPE r1; + real_from_mpfr(&r1, val, t, GMP_RNDN); + REAL_VALUE_TYPE r2; + real_convert(&r2, TYPE_MODE(t), &r1); + ret = build_real(t, r2); + return this->make_expression(ret); +} + +// Return a typed real and imaginary value as a constant complex number. + +Bexpression* +Gcc_backend::complex_constant_expression(Btype* btype, mpc_t val) +{ + tree t = btype->get_tree(); + tree ret; + if (t == error_mark_node) + return this->error_expression(); + + REAL_VALUE_TYPE r1; + real_from_mpfr(&r1, mpc_realref(val), TREE_TYPE(t), GMP_RNDN); + REAL_VALUE_TYPE r2; + real_convert(&r2, TYPE_MODE(TREE_TYPE(t)), &r1); + + REAL_VALUE_TYPE r3; + real_from_mpfr(&r3, mpc_imagref(val), TREE_TYPE(t), GMP_RNDN); + REAL_VALUE_TYPE r4; + real_convert(&r4, TYPE_MODE(TREE_TYPE(t)), &r3); + + ret = build_complex(t, build_real(TREE_TYPE(t), r2), + build_real(TREE_TYPE(t), r4)); + return this->make_expression(ret); +} + +// Make a constant string expression. + +Bexpression* +Gcc_backend::string_constant_expression(const std::string& val) +{ + tree index_type = build_index_type(size_int(val.length())); + tree const_char_type = build_qualified_type(unsigned_char_type_node, + TYPE_QUAL_CONST); + tree string_type = build_array_type(const_char_type, index_type); + TYPE_STRING_FLAG(string_type) = 1; + tree string_val = build_string(val.length(), val.data()); + TREE_TYPE(string_val) = string_type; + + return this->make_expression(string_val); +} + +// Make a constant boolean expression. + +Bexpression* +Gcc_backend::boolean_constant_expression(bool val) +{ + tree bool_cst = val ? boolean_true_node : boolean_false_node; + return this->make_expression(bool_cst); +} + +// Return the real part of a complex expression. + +Bexpression* +Gcc_backend::real_part_expression(Bexpression* bcomplex, Location location) +{ + tree complex_tree = bcomplex->get_tree(); + if (complex_tree == error_mark_node) + return this->error_expression(); + gcc_assert(COMPLEX_FLOAT_TYPE_P(TREE_TYPE(complex_tree))); + tree ret = fold_build1_loc(location.gcc_location(), REALPART_EXPR, + TREE_TYPE(TREE_TYPE(complex_tree)), + complex_tree); + return this->make_expression(ret); +} + +// Return the imaginary part of a complex expression. + +Bexpression* +Gcc_backend::imag_part_expression(Bexpression* bcomplex, Location location) +{ + tree complex_tree = bcomplex->get_tree(); + if (complex_tree == error_mark_node) + return this->error_expression(); + gcc_assert(COMPLEX_FLOAT_TYPE_P(TREE_TYPE(complex_tree))); + tree ret = fold_build1_loc(location.gcc_location(), IMAGPART_EXPR, + TREE_TYPE(TREE_TYPE(complex_tree)), + complex_tree); + return this->make_expression(ret); +} + +// Make a complex expression given its real and imaginary parts. + +Bexpression* +Gcc_backend::complex_expression(Bexpression* breal, Bexpression* bimag, + Location location) +{ + tree real_tree = breal->get_tree(); + tree imag_tree = bimag->get_tree(); + if (real_tree == error_mark_node || imag_tree == error_mark_node) + return this->error_expression(); + gcc_assert(TYPE_MAIN_VARIANT(TREE_TYPE(real_tree)) + == TYPE_MAIN_VARIANT(TREE_TYPE(imag_tree))); + gcc_assert(SCALAR_FLOAT_TYPE_P(TREE_TYPE(real_tree))); + tree ret = fold_build2_loc(location.gcc_location(), COMPLEX_EXPR, + build_complex_type(TREE_TYPE(real_tree)), + real_tree, imag_tree); + return this->make_expression(ret); +} + +// An expression that converts an expression to a different type. + +Bexpression* +Gcc_backend::convert_expression(Btype* type, Bexpression* expr, + Location location) +{ + tree type_tree = type->get_tree(); + tree expr_tree = expr->get_tree(); + if (type_tree == error_mark_node + || expr_tree == error_mark_node + || TREE_TYPE(expr_tree) == error_mark_node) + return this->error_expression(); + + tree ret; + if (this->type_size(type) == 0 + || TREE_TYPE(expr_tree) == void_type_node) + { + // Do not convert zero-sized types. + ret = expr_tree; + } + else if (TREE_CODE(type_tree) == INTEGER_TYPE) + ret = fold(convert_to_integer(type_tree, expr_tree)); + else if (TREE_CODE(type_tree) == REAL_TYPE) + ret = fold(convert_to_real(type_tree, expr_tree)); + else if (TREE_CODE(type_tree) == COMPLEX_TYPE) + ret = fold(convert_to_complex(type_tree, expr_tree)); + else if (TREE_CODE(type_tree) == POINTER_TYPE + && TREE_CODE(TREE_TYPE(expr_tree)) == INTEGER_TYPE) + ret = fold(convert_to_pointer(type_tree, expr_tree)); + else if (TREE_CODE(type_tree) == RECORD_TYPE + || TREE_CODE(type_tree) == ARRAY_TYPE) + ret = fold_build1_loc(location.gcc_location(), VIEW_CONVERT_EXPR, + type_tree, expr_tree); + else + ret = fold_convert_loc(location.gcc_location(), type_tree, expr_tree); + + return this->make_expression(ret); +} + +// Get the address of a function. + +Bexpression* +Gcc_backend::function_code_expression(Bfunction* bfunc, Location location) +{ + tree func = bfunc->get_tree(); + if (func == error_mark_node) + return this->error_expression(); + + tree ret = build_fold_addr_expr_loc(location.gcc_location(), func); + return this->make_expression(ret); +} + +// Get the address of an expression. + +Bexpression* +Gcc_backend::address_expression(Bexpression* bexpr, Location location) +{ + tree expr = bexpr->get_tree(); + if (expr == error_mark_node) + return this->error_expression(); + + tree ret = build_fold_addr_expr_loc(location.gcc_location(), expr); + return this->make_expression(ret); +} + +// Return an expression for the field at INDEX in BSTRUCT. + +Bexpression* +Gcc_backend::struct_field_expression(Bexpression* bstruct, size_t index, + Location location) +{ + tree struct_tree = bstruct->get_tree(); + if (struct_tree == error_mark_node + || TREE_TYPE(struct_tree) == error_mark_node) + return this->error_expression(); + gcc_assert(TREE_CODE(TREE_TYPE(struct_tree)) == RECORD_TYPE); + tree field = TYPE_FIELDS(TREE_TYPE(struct_tree)); + if (field == NULL_TREE) + { + // This can happen for a type which refers to itself indirectly + // and then turns out to be erroneous. + return this->error_expression(); + } + for (unsigned int i = index; i > 0; --i) + { + field = DECL_CHAIN(field); + gcc_assert(field != NULL_TREE); + } + if (TREE_TYPE(field) == error_mark_node) + return this->error_expression(); + tree ret = fold_build3_loc(location.gcc_location(), COMPONENT_REF, + TREE_TYPE(field), struct_tree, field, + NULL_TREE); + if (TREE_CONSTANT(struct_tree)) + TREE_CONSTANT(ret) = 1; + return this->make_expression(ret); +} + +// Return an expression that executes BSTAT before BEXPR. + +Bexpression* +Gcc_backend::compound_expression(Bstatement* bstat, Bexpression* bexpr, + Location location) +{ + tree stat = bstat->get_tree(); + tree expr = bexpr->get_tree(); + if (stat == error_mark_node || expr == error_mark_node) + return this->error_expression(); + tree ret = fold_build2_loc(location.gcc_location(), COMPOUND_EXPR, + TREE_TYPE(expr), stat, expr); + return this->make_expression(ret); +} + +// Return an expression that executes THEN_EXPR if CONDITION is true, or +// ELSE_EXPR otherwise. + +Bexpression* +Gcc_backend::conditional_expression(Bfunction*, Btype* btype, + Bexpression* condition, + Bexpression* then_expr, + Bexpression* else_expr, Location location) +{ + tree type_tree = btype == NULL ? void_type_node : btype->get_tree(); + tree cond_tree = condition->get_tree(); + tree then_tree = then_expr->get_tree(); + tree else_tree = else_expr == NULL ? NULL_TREE : else_expr->get_tree(); + if (type_tree == error_mark_node + || cond_tree == error_mark_node + || then_tree == error_mark_node + || else_tree == error_mark_node) + return this->error_expression(); + tree ret = build3_loc(location.gcc_location(), COND_EXPR, type_tree, + cond_tree, then_tree, else_tree); + return this->make_expression(ret); +} + +// Return an expression for the unary operation OP EXPR. + +Bexpression* +Gcc_backend::unary_expression(Operator op, Bexpression* expr, Location location) +{ + tree expr_tree = expr->get_tree(); + if (expr_tree == error_mark_node + || TREE_TYPE(expr_tree) == error_mark_node) + return this->error_expression(); + + tree type_tree = TREE_TYPE(expr_tree); + enum tree_code code; + switch (op) + { + case OPERATOR_MINUS: + { + tree computed_type = excess_precision_type(type_tree); + if (computed_type != NULL_TREE) + { + expr_tree = convert(computed_type, expr_tree); + type_tree = computed_type; + } + code = NEGATE_EXPR; + break; + } + case OPERATOR_NOT: + code = TRUTH_NOT_EXPR; + break; + case OPERATOR_XOR: + code = BIT_NOT_EXPR; + break; + default: + gcc_unreachable(); + break; + } + + tree ret = fold_build1_loc(location.gcc_location(), code, type_tree, + expr_tree); + return this->make_expression(ret); +} + +// Convert a gofrontend operator to an equivalent tree_code. + +static enum tree_code +operator_to_tree_code(Operator op, tree type) +{ + enum tree_code code; + switch (op) + { + case OPERATOR_EQEQ: + code = EQ_EXPR; + break; + case OPERATOR_NOTEQ: + code = NE_EXPR; + break; + case OPERATOR_LT: + code = LT_EXPR; + break; + case OPERATOR_LE: + code = LE_EXPR; + break; + case OPERATOR_GT: + code = GT_EXPR; + break; + case OPERATOR_GE: + code = GE_EXPR; + break; + case OPERATOR_OROR: + code = TRUTH_ORIF_EXPR; + break; + case OPERATOR_ANDAND: + code = TRUTH_ANDIF_EXPR; + break; + case OPERATOR_PLUS: + code = PLUS_EXPR; + break; + case OPERATOR_MINUS: + code = MINUS_EXPR; + break; + case OPERATOR_OR: + code = BIT_IOR_EXPR; + break; + case OPERATOR_XOR: + code = BIT_XOR_EXPR; + break; + case OPERATOR_MULT: + code = MULT_EXPR; + break; + case OPERATOR_DIV: + if (TREE_CODE(type) == REAL_TYPE || TREE_CODE(type) == COMPLEX_TYPE) + code = RDIV_EXPR; + else + code = TRUNC_DIV_EXPR; + break; + case OPERATOR_MOD: + code = TRUNC_MOD_EXPR; + break; + case OPERATOR_LSHIFT: + code = LSHIFT_EXPR; + break; + case OPERATOR_RSHIFT: + code = RSHIFT_EXPR; + break; + case OPERATOR_AND: + code = BIT_AND_EXPR; + break; + case OPERATOR_BITCLEAR: + code = BIT_AND_EXPR; + break; + default: + gcc_unreachable(); + } + + return code; +} + +// Return an expression for the binary operation LEFT OP RIGHT. + +Bexpression* +Gcc_backend::binary_expression(Operator op, Bexpression* left, + Bexpression* right, Location location) +{ + tree left_tree = left->get_tree(); + tree right_tree = right->get_tree(); + if (left_tree == error_mark_node + || right_tree == error_mark_node) + return this->error_expression(); + enum tree_code code = operator_to_tree_code(op, TREE_TYPE(left_tree)); + + bool use_left_type = op != OPERATOR_OROR && op != OPERATOR_ANDAND; + tree type_tree = use_left_type ? TREE_TYPE(left_tree) : TREE_TYPE(right_tree); + tree computed_type = excess_precision_type(type_tree); + if (computed_type != NULL_TREE) + { + left_tree = convert(computed_type, left_tree); + right_tree = convert(computed_type, right_tree); + type_tree = computed_type; + } + + // For comparison operators, the resulting type should be boolean. + switch (op) + { + case OPERATOR_EQEQ: + case OPERATOR_NOTEQ: + case OPERATOR_LT: + case OPERATOR_LE: + case OPERATOR_GT: + case OPERATOR_GE: + type_tree = boolean_type_node; + break; + default: + break; + } + + tree ret = fold_build2_loc(location.gcc_location(), code, type_tree, + left_tree, right_tree); + return this->make_expression(ret); +} + +// Return an expression that constructs BTYPE with VALS. + +Bexpression* +Gcc_backend::constructor_expression(Btype* btype, + const std::vector<Bexpression*>& vals, + Location location) +{ + tree type_tree = btype->get_tree(); + if (type_tree == error_mark_node) + return this->error_expression(); + + vec<constructor_elt, va_gc> *init; + vec_alloc(init, vals.size()); + + tree sink = NULL_TREE; + bool is_constant = true; + tree field = TYPE_FIELDS(type_tree); + for (std::vector<Bexpression*>::const_iterator p = vals.begin(); + p != vals.end(); + ++p, field = DECL_CHAIN(field)) + { + gcc_assert(field != NULL_TREE); + tree val = (*p)->get_tree(); + if (TREE_TYPE(field) == error_mark_node + || val == error_mark_node + || TREE_TYPE(val) == error_mark_node) + return this->error_expression(); + + if (int_size_in_bytes(TREE_TYPE(field)) == 0) + { + // GIMPLE cannot represent indices of zero-sized types so + // trying to construct a map with zero-sized keys might lead + // to errors. Instead, we evaluate each expression that + // would have been added as a map element for its + // side-effects and construct an empty map. + append_to_statement_list(val, &sink); + continue; + } + + constructor_elt empty = {NULL, NULL}; + constructor_elt* elt = init->quick_push(empty); + elt->index = field; + elt->value = this->convert_tree(TREE_TYPE(field), val, location); + if (!TREE_CONSTANT(elt->value)) + is_constant = false; + } + gcc_assert(field == NULL_TREE); + tree ret = build_constructor(type_tree, init); + if (is_constant) + TREE_CONSTANT(ret) = 1; + if (sink != NULL_TREE) + ret = fold_build2_loc(location.gcc_location(), COMPOUND_EXPR, + type_tree, sink, ret); + return this->make_expression(ret); +} + +Bexpression* +Gcc_backend::array_constructor_expression( + Btype* array_btype, const std::vector<unsigned long>& indexes, + const std::vector<Bexpression*>& vals, Location location) +{ + tree type_tree = array_btype->get_tree(); + if (type_tree == error_mark_node) + return this->error_expression(); + + gcc_assert(indexes.size() == vals.size()); + + tree element_type = TREE_TYPE(type_tree); + HOST_WIDE_INT element_size = int_size_in_bytes(element_type); + vec<constructor_elt, va_gc> *init; + vec_alloc(init, element_size == 0 ? 0 : vals.size()); + + tree sink = NULL_TREE; + bool is_constant = true; + for (size_t i = 0; i < vals.size(); ++i) + { + tree index = size_int(indexes[i]); + tree val = (vals[i])->get_tree(); + + if (index == error_mark_node + || val == error_mark_node) + return this->error_expression(); + + if (element_size == 0) + { + // GIMPLE cannot represent arrays of zero-sized types so trying + // to construct an array of zero-sized values might lead to errors. + // Instead, we evaluate each expression that would have been added as + // an array value for its side-effects and construct an empty array. + append_to_statement_list(val, &sink); + continue; + } + + if (!TREE_CONSTANT(val)) + is_constant = false; + + constructor_elt empty = {NULL, NULL}; + constructor_elt* elt = init->quick_push(empty); + elt->index = index; + elt->value = val; + } + + tree ret = build_constructor(type_tree, init); + if (is_constant) + TREE_CONSTANT(ret) = 1; + if (sink != NULL_TREE) + ret = fold_build2_loc(location.gcc_location(), COMPOUND_EXPR, + type_tree, sink, ret); + return this->make_expression(ret); +} + +// Return an expression for the address of BASE[INDEX]. + +Bexpression* +Gcc_backend::pointer_offset_expression(Bexpression* base, Bexpression* index, + Location location) +{ + tree base_tree = base->get_tree(); + tree index_tree = index->get_tree(); + tree element_type_tree = TREE_TYPE(TREE_TYPE(base_tree)); + if (base_tree == error_mark_node + || TREE_TYPE(base_tree) == error_mark_node + || index_tree == error_mark_node + || element_type_tree == error_mark_node) + return this->error_expression(); + + tree element_size = TYPE_SIZE_UNIT(element_type_tree); + index_tree = fold_convert_loc(location.gcc_location(), sizetype, index_tree); + tree offset = fold_build2_loc(location.gcc_location(), MULT_EXPR, sizetype, + index_tree, element_size); + tree ptr = fold_build2_loc(location.gcc_location(), POINTER_PLUS_EXPR, + TREE_TYPE(base_tree), base_tree, offset); + return this->make_expression(ptr); +} + +// Return an expression representing ARRAY[INDEX] + +Bexpression* +Gcc_backend::array_index_expression(Bexpression* array, Bexpression* index, + Location location) +{ + tree array_tree = array->get_tree(); + tree index_tree = index->get_tree(); + if (array_tree == error_mark_node + || TREE_TYPE(array_tree) == error_mark_node + || index_tree == error_mark_node) + return this->error_expression(); + + // A function call that returns a zero sized object will have been + // changed to return void. If we see void here, assume we are + // dealing with a zero sized type and just evaluate the operands. + tree ret; + if (TREE_TYPE(array_tree) != void_type_node) + ret = build4_loc(location.gcc_location(), ARRAY_REF, + TREE_TYPE(TREE_TYPE(array_tree)), array_tree, + index_tree, NULL_TREE, NULL_TREE); + else + ret = fold_build2_loc(location.gcc_location(), COMPOUND_EXPR, + void_type_node, array_tree, index_tree); + + return this->make_expression(ret); +} + +// Create an expression for a call to FN_EXPR with FN_ARGS. +Bexpression* +Gcc_backend::call_expression(Bfunction*, // containing fcn for call + Bexpression* fn_expr, + const std::vector<Bexpression*>& fn_args, + Bexpression* chain_expr, + Location location) +{ + tree fn = fn_expr->get_tree(); + if (fn == error_mark_node || TREE_TYPE(fn) == error_mark_node) + return this->error_expression(); + + gcc_assert(FUNCTION_POINTER_TYPE_P(TREE_TYPE(fn))); + tree rettype = TREE_TYPE(TREE_TYPE(TREE_TYPE(fn))); + + size_t nargs = fn_args.size(); + tree* args = nargs == 0 ? NULL : new tree[nargs]; + for (size_t i = 0; i < nargs; ++i) + { + args[i] = fn_args.at(i)->get_tree(); + if (args[i] == error_mark_node) + return this->error_expression(); + } + + tree fndecl = fn; + if (TREE_CODE(fndecl) == ADDR_EXPR) + fndecl = TREE_OPERAND(fndecl, 0); + + // This is to support builtin math functions when using 80387 math. + tree excess_type = NULL_TREE; + if (optimize + && TREE_CODE(fndecl) == FUNCTION_DECL + && fndecl_built_in_p (fndecl, BUILT_IN_NORMAL) + && DECL_IS_BUILTIN (fndecl) + && nargs > 0 + && ((SCALAR_FLOAT_TYPE_P(rettype) + && SCALAR_FLOAT_TYPE_P(TREE_TYPE(args[0]))) + || (COMPLEX_FLOAT_TYPE_P(rettype) + && COMPLEX_FLOAT_TYPE_P(TREE_TYPE(args[0]))))) + { + excess_type = excess_precision_type(TREE_TYPE(args[0])); + if (excess_type != NULL_TREE) + { + tree excess_fndecl = mathfn_built_in(excess_type, + DECL_FUNCTION_CODE(fndecl)); + if (excess_fndecl == NULL_TREE) + excess_type = NULL_TREE; + else + { + fn = build_fold_addr_expr_loc(location.gcc_location(), + excess_fndecl); + for (size_t i = 0; i < nargs; ++i) + { + if (SCALAR_FLOAT_TYPE_P(TREE_TYPE(args[i])) + || COMPLEX_FLOAT_TYPE_P(TREE_TYPE(args[i]))) + args[i] = ::convert(excess_type, args[i]); + } + } + } + } + + tree ret = + build_call_array_loc(location.gcc_location(), + excess_type != NULL_TREE ? excess_type : rettype, + fn, nargs, args); + + if (chain_expr) + CALL_EXPR_STATIC_CHAIN (ret) = chain_expr->get_tree(); + + if (excess_type != NULL_TREE) + { + // Calling convert here can undo our excess precision change. + // That may or may not be a bug in convert_to_real. + ret = build1_loc(location.gcc_location(), NOP_EXPR, rettype, ret); + } + + delete[] args; + return this->make_expression(ret); +} + +// An expression as a statement. + +Bstatement* +Gcc_backend::expression_statement(Bfunction*, Bexpression* expr) +{ + return this->make_statement(expr->get_tree()); +} + +// Variable initialization. + +Bstatement* +Gcc_backend::init_statement(Bfunction*, Bvariable* var, Bexpression* init) +{ + tree var_tree = var->get_decl(); + tree init_tree = init->get_tree(); + if (var_tree == error_mark_node || init_tree == error_mark_node) + return this->error_statement(); + gcc_assert(TREE_CODE(var_tree) == VAR_DECL); + + // To avoid problems with GNU ld, we don't make zero-sized + // externally visible variables. That might lead us to doing an + // initialization of a zero-sized expression to a non-zero sized + // variable, or vice-versa. Avoid crashes by omitting the + // initializer. Such initializations don't mean anything anyhow. + if (int_size_in_bytes(TREE_TYPE(var_tree)) != 0 + && init_tree != NULL_TREE + && TREE_TYPE(init_tree) != void_type_node + && int_size_in_bytes(TREE_TYPE(init_tree)) != 0) + { + DECL_INITIAL(var_tree) = init_tree; + init_tree = NULL_TREE; + } + + tree ret = build1_loc(DECL_SOURCE_LOCATION(var_tree), DECL_EXPR, + void_type_node, var_tree); + if (init_tree != NULL_TREE) + ret = build2_loc(DECL_SOURCE_LOCATION(var_tree), COMPOUND_EXPR, + void_type_node, init_tree, ret); + + return this->make_statement(ret); +} + +// Assignment. + +Bstatement* +Gcc_backend::assignment_statement(Bfunction* bfn, Bexpression* lhs, + Bexpression* rhs, Location location) +{ + tree lhs_tree = lhs->get_tree(); + tree rhs_tree = rhs->get_tree(); + if (lhs_tree == error_mark_node || rhs_tree == error_mark_node) + return this->error_statement(); + + // To avoid problems with GNU ld, we don't make zero-sized + // externally visible variables. That might lead us to doing an + // assignment of a zero-sized expression to a non-zero sized + // expression; avoid crashes here by avoiding assignments of + // zero-sized expressions. Such assignments don't really mean + // anything anyhow. + if (TREE_TYPE(lhs_tree) == void_type_node + || int_size_in_bytes(TREE_TYPE(lhs_tree)) == 0 + || TREE_TYPE(rhs_tree) == void_type_node + || int_size_in_bytes(TREE_TYPE(rhs_tree)) == 0) + return this->compound_statement(this->expression_statement(bfn, lhs), + this->expression_statement(bfn, rhs)); + + rhs_tree = this->convert_tree(TREE_TYPE(lhs_tree), rhs_tree, location); + + return this->make_statement(fold_build2_loc(location.gcc_location(), + MODIFY_EXPR, + void_type_node, + lhs_tree, rhs_tree)); +} + +// Return. + +Bstatement* +Gcc_backend::return_statement(Bfunction* bfunction, + const std::vector<Bexpression*>& vals, + Location location) +{ + tree fntree = bfunction->get_tree(); + if (fntree == error_mark_node) + return this->error_statement(); + tree result = DECL_RESULT(fntree); + if (result == error_mark_node) + return this->error_statement(); + + // If the result size is zero bytes, we have set the function type + // to have a result type of void, so don't return anything. + // See the function_type method. + tree res_type = TREE_TYPE(result); + if (res_type == void_type_node || int_size_in_bytes(res_type) == 0) + { + tree stmt_list = NULL_TREE; + for (std::vector<Bexpression*>::const_iterator p = vals.begin(); + p != vals.end(); + p++) + { + tree val = (*p)->get_tree(); + if (val == error_mark_node) + return this->error_statement(); + append_to_statement_list(val, &stmt_list); + } + tree ret = fold_build1_loc(location.gcc_location(), RETURN_EXPR, + void_type_node, NULL_TREE); + append_to_statement_list(ret, &stmt_list); + return this->make_statement(stmt_list); + } + + tree ret; + if (vals.empty()) + ret = fold_build1_loc(location.gcc_location(), RETURN_EXPR, void_type_node, + NULL_TREE); + else if (vals.size() == 1) + { + tree val = vals.front()->get_tree(); + if (val == error_mark_node) + return this->error_statement(); + tree set = fold_build2_loc(location.gcc_location(), MODIFY_EXPR, + void_type_node, result, + vals.front()->get_tree()); + ret = fold_build1_loc(location.gcc_location(), RETURN_EXPR, + void_type_node, set); + } + else + { + // To return multiple values, copy the values into a temporary + // variable of the right structure type, and then assign the + // temporary variable to the DECL_RESULT in the return + // statement. + tree stmt_list = NULL_TREE; + tree rettype = TREE_TYPE(result); + + if (DECL_STRUCT_FUNCTION(fntree) == NULL) + push_struct_function(fntree); + else + push_cfun(DECL_STRUCT_FUNCTION(fntree)); + tree rettmp = create_tmp_var(rettype, "RESULT"); + pop_cfun(); + + tree field = TYPE_FIELDS(rettype); + for (std::vector<Bexpression*>::const_iterator p = vals.begin(); + p != vals.end(); + p++, field = DECL_CHAIN(field)) + { + gcc_assert(field != NULL_TREE); + tree ref = fold_build3_loc(location.gcc_location(), COMPONENT_REF, + TREE_TYPE(field), rettmp, field, + NULL_TREE); + tree val = (*p)->get_tree(); + if (val == error_mark_node) + return this->error_statement(); + tree set = fold_build2_loc(location.gcc_location(), MODIFY_EXPR, + void_type_node, + ref, (*p)->get_tree()); + append_to_statement_list(set, &stmt_list); + } + gcc_assert(field == NULL_TREE); + tree set = fold_build2_loc(location.gcc_location(), MODIFY_EXPR, + void_type_node, + result, rettmp); + tree ret_expr = fold_build1_loc(location.gcc_location(), RETURN_EXPR, + void_type_node, set); + append_to_statement_list(ret_expr, &stmt_list); + ret = stmt_list; + } + return this->make_statement(ret); +} + +// Create a statement that attempts to execute BSTAT and calls EXCEPT_STMT if an +// error occurs. EXCEPT_STMT may be NULL. FINALLY_STMT may be NULL and if not +// NULL, it will always be executed. This is used for handling defers in Go +// functions. In C++, the resulting code is of this form: +// try { BSTAT; } catch { EXCEPT_STMT; } finally { FINALLY_STMT; } + +Bstatement* +Gcc_backend::exception_handler_statement(Bstatement* bstat, + Bstatement* except_stmt, + Bstatement* finally_stmt, + Location location) +{ + tree stat_tree = bstat->get_tree(); + tree except_tree = except_stmt == NULL ? NULL_TREE : except_stmt->get_tree(); + tree finally_tree = finally_stmt == NULL + ? NULL_TREE + : finally_stmt->get_tree(); + + if (stat_tree == error_mark_node + || except_tree == error_mark_node + || finally_tree == error_mark_node) + return this->error_statement(); + + if (except_tree != NULL_TREE) + stat_tree = build2_loc(location.gcc_location(), TRY_CATCH_EXPR, + void_type_node, stat_tree, + build2_loc(location.gcc_location(), CATCH_EXPR, + void_type_node, NULL, except_tree)); + if (finally_tree != NULL_TREE) + stat_tree = build2_loc(location.gcc_location(), TRY_FINALLY_EXPR, + void_type_node, stat_tree, finally_tree); + return this->make_statement(stat_tree); +} + +// If. + +Bstatement* +Gcc_backend::if_statement(Bfunction*, Bexpression* condition, + Bblock* then_block, Bblock* else_block, + Location location) +{ + tree cond_tree = condition->get_tree(); + tree then_tree = then_block->get_tree(); + tree else_tree = else_block == NULL ? NULL_TREE : else_block->get_tree(); + if (cond_tree == error_mark_node + || then_tree == error_mark_node + || else_tree == error_mark_node) + return this->error_statement(); + tree ret = build3_loc(location.gcc_location(), COND_EXPR, void_type_node, + cond_tree, then_tree, else_tree); + return this->make_statement(ret); +} + +// Switch. + +Bstatement* +Gcc_backend::switch_statement( + Bfunction* function, + Bexpression* value, + const std::vector<std::vector<Bexpression*> >& cases, + const std::vector<Bstatement*>& statements, + Location switch_location) +{ + gcc_assert(cases.size() == statements.size()); + + tree decl = function->get_tree(); + if (DECL_STRUCT_FUNCTION(decl) == NULL) + push_struct_function(decl); + else + push_cfun(DECL_STRUCT_FUNCTION(decl)); + + tree stmt_list = NULL_TREE; + std::vector<std::vector<Bexpression*> >::const_iterator pc = cases.begin(); + for (std::vector<Bstatement*>::const_iterator ps = statements.begin(); + ps != statements.end(); + ++ps, ++pc) + { + if (pc->empty()) + { + location_t loc = (*ps != NULL + ? EXPR_LOCATION((*ps)->get_tree()) + : UNKNOWN_LOCATION); + tree label = create_artificial_label(loc); + tree c = build_case_label(NULL_TREE, NULL_TREE, label); + append_to_statement_list(c, &stmt_list); + } + else + { + for (std::vector<Bexpression*>::const_iterator pcv = pc->begin(); + pcv != pc->end(); + ++pcv) + { + tree t = (*pcv)->get_tree(); + if (t == error_mark_node) + return this->error_statement(); + location_t loc = EXPR_LOCATION(t); + tree label = create_artificial_label(loc); + tree c = build_case_label((*pcv)->get_tree(), NULL_TREE, label); + append_to_statement_list(c, &stmt_list); + } + } + + if (*ps != NULL) + { + tree t = (*ps)->get_tree(); + if (t == error_mark_node) + return this->error_statement(); + append_to_statement_list(t, &stmt_list); + } + } + pop_cfun(); + + tree tv = value->get_tree(); + if (tv == error_mark_node) + return this->error_statement(); + tree t = build2_loc(switch_location.gcc_location(), SWITCH_EXPR, + NULL_TREE, tv, stmt_list); + return this->make_statement(t); +} + +// Pair of statements. + +Bstatement* +Gcc_backend::compound_statement(Bstatement* s1, Bstatement* s2) +{ + tree stmt_list = NULL_TREE; + tree t = s1->get_tree(); + if (t == error_mark_node) + return this->error_statement(); + append_to_statement_list(t, &stmt_list); + t = s2->get_tree(); + if (t == error_mark_node) + return this->error_statement(); + append_to_statement_list(t, &stmt_list); + + // If neither statement has any side effects, stmt_list can be NULL + // at this point. + if (stmt_list == NULL_TREE) + stmt_list = integer_zero_node; + + return this->make_statement(stmt_list); +} + +// List of statements. + +Bstatement* +Gcc_backend::statement_list(const std::vector<Bstatement*>& statements) +{ + tree stmt_list = NULL_TREE; + for (std::vector<Bstatement*>::const_iterator p = statements.begin(); + p != statements.end(); + ++p) + { + tree t = (*p)->get_tree(); + if (t == error_mark_node) + return this->error_statement(); + append_to_statement_list(t, &stmt_list); + } + return this->make_statement(stmt_list); +} + +// Make a block. For some reason gcc uses a dual structure for +// blocks: BLOCK tree nodes and BIND_EXPR tree nodes. Since the +// BIND_EXPR node points to the BLOCK node, we store the BIND_EXPR in +// the Bblock. + +Bblock* +Gcc_backend::block(Bfunction* function, Bblock* enclosing, + const std::vector<Bvariable*>& vars, + Location start_location, + Location) +{ + tree block_tree = make_node(BLOCK); + if (enclosing == NULL) + { + tree fndecl = function->get_tree(); + gcc_assert(fndecl != NULL_TREE); + + // We may have already created a block for local variables when + // we take the address of a parameter. + if (DECL_INITIAL(fndecl) == NULL_TREE) + { + BLOCK_SUPERCONTEXT(block_tree) = fndecl; + DECL_INITIAL(fndecl) = block_tree; + } + else + { + tree superblock_tree = DECL_INITIAL(fndecl); + BLOCK_SUPERCONTEXT(block_tree) = superblock_tree; + tree* pp; + for (pp = &BLOCK_SUBBLOCKS(superblock_tree); + *pp != NULL_TREE; + pp = &BLOCK_CHAIN(*pp)) + ; + *pp = block_tree; + } + } + else + { + tree superbind_tree = enclosing->get_tree(); + tree superblock_tree = BIND_EXPR_BLOCK(superbind_tree); + gcc_assert(TREE_CODE(superblock_tree) == BLOCK); + + BLOCK_SUPERCONTEXT(block_tree) = superblock_tree; + tree* pp; + for (pp = &BLOCK_SUBBLOCKS(superblock_tree); + *pp != NULL_TREE; + pp = &BLOCK_CHAIN(*pp)) + ; + *pp = block_tree; + } + + tree* pp = &BLOCK_VARS(block_tree); + for (std::vector<Bvariable*>::const_iterator pv = vars.begin(); + pv != vars.end(); + ++pv) + { + *pp = (*pv)->get_decl(); + if (*pp != error_mark_node) + pp = &DECL_CHAIN(*pp); + } + *pp = NULL_TREE; + + TREE_USED(block_tree) = 1; + + tree bind_tree = build3_loc(start_location.gcc_location(), BIND_EXPR, + void_type_node, BLOCK_VARS(block_tree), + NULL_TREE, block_tree); + TREE_SIDE_EFFECTS(bind_tree) = 1; + return new Bblock(bind_tree); +} + +// Add statements to a block. + +void +Gcc_backend::block_add_statements(Bblock* bblock, + const std::vector<Bstatement*>& statements) +{ + tree stmt_list = NULL_TREE; + for (std::vector<Bstatement*>::const_iterator p = statements.begin(); + p != statements.end(); + ++p) + { + tree s = (*p)->get_tree(); + if (s != error_mark_node) + append_to_statement_list(s, &stmt_list); + } + + tree bind_tree = bblock->get_tree(); + gcc_assert(TREE_CODE(bind_tree) == BIND_EXPR); + BIND_EXPR_BODY(bind_tree) = stmt_list; +} + +// Return a block as a statement. + +Bstatement* +Gcc_backend::block_statement(Bblock* bblock) +{ + tree bind_tree = bblock->get_tree(); + gcc_assert(TREE_CODE(bind_tree) == BIND_EXPR); + return this->make_statement(bind_tree); +} + +// This is not static because we declare it with GTY(()) in go-c.h. +tree go_non_zero_struct; + +// Return a type corresponding to TYPE with non-zero size. + +tree +Gcc_backend::non_zero_size_type(tree type) +{ + if (int_size_in_bytes(type) != 0) + return type; + + switch (TREE_CODE(type)) + { + case RECORD_TYPE: + if (TYPE_FIELDS(type) != NULL_TREE) + { + tree ns = make_node(RECORD_TYPE); + tree field_trees = NULL_TREE; + tree *pp = &field_trees; + for (tree field = TYPE_FIELDS(type); + field != NULL_TREE; + field = DECL_CHAIN(field)) + { + tree ft = TREE_TYPE(field); + if (field == TYPE_FIELDS(type)) + ft = non_zero_size_type(ft); + tree f = build_decl(DECL_SOURCE_LOCATION(field), FIELD_DECL, + DECL_NAME(field), ft); + DECL_CONTEXT(f) = ns; + *pp = f; + pp = &DECL_CHAIN(f); + } + TYPE_FIELDS(ns) = field_trees; + layout_type(ns); + return ns; + } + + if (go_non_zero_struct == NULL_TREE) + { + type = make_node(RECORD_TYPE); + tree field = build_decl(UNKNOWN_LOCATION, FIELD_DECL, + get_identifier("dummy"), + boolean_type_node); + DECL_CONTEXT(field) = type; + TYPE_FIELDS(type) = field; + layout_type(type); + go_non_zero_struct = type; + } + return go_non_zero_struct; + + case ARRAY_TYPE: + { + tree element_type = non_zero_size_type(TREE_TYPE(type)); + return build_array_type_nelts(element_type, 1); + } + + default: + gcc_unreachable(); + } + + gcc_unreachable(); +} + +// Convert EXPR_TREE to TYPE_TREE. Sometimes the same unnamed Go type +// can be created multiple times and thus have multiple tree +// representations. Make sure this does not confuse the middle-end. + +tree +Gcc_backend::convert_tree(tree type_tree, tree expr_tree, Location location) +{ + if (type_tree == TREE_TYPE(expr_tree)) + return expr_tree; + + if (type_tree == error_mark_node + || expr_tree == error_mark_node + || TREE_TYPE(expr_tree) == error_mark_node) + return error_mark_node; + + gcc_assert(TREE_CODE(type_tree) == TREE_CODE(TREE_TYPE(expr_tree))); + if (POINTER_TYPE_P(type_tree) + || INTEGRAL_TYPE_P(type_tree) + || SCALAR_FLOAT_TYPE_P(type_tree) + || COMPLEX_FLOAT_TYPE_P(type_tree)) + return fold_convert_loc(location.gcc_location(), type_tree, expr_tree); + else if (TREE_CODE(type_tree) == RECORD_TYPE + || TREE_CODE(type_tree) == ARRAY_TYPE) + { + gcc_assert(int_size_in_bytes(type_tree) + == int_size_in_bytes(TREE_TYPE(expr_tree))); + if (TYPE_MAIN_VARIANT(type_tree) + == TYPE_MAIN_VARIANT(TREE_TYPE(expr_tree))) + return fold_build1_loc(location.gcc_location(), NOP_EXPR, + type_tree, expr_tree); + return fold_build1_loc(location.gcc_location(), VIEW_CONVERT_EXPR, + type_tree, expr_tree); + } + + gcc_unreachable(); +} + +// Make a global variable. + +Bvariable* +Gcc_backend::global_variable(const std::string& var_name, + const std::string& asm_name, + Btype* btype, + bool is_external, + bool is_hidden, + bool in_unique_section, + Location location) +{ + tree type_tree = btype->get_tree(); + if (type_tree == error_mark_node) + return this->error_variable(); + + // The GNU linker does not like dynamic variables with zero size. + tree orig_type_tree = type_tree; + if ((is_external || !is_hidden) && int_size_in_bytes(type_tree) == 0) + type_tree = this->non_zero_size_type(type_tree); + + tree decl = build_decl(location.gcc_location(), VAR_DECL, + get_identifier_from_string(var_name), + type_tree); + if (is_external) + DECL_EXTERNAL(decl) = 1; + else + TREE_STATIC(decl) = 1; + if (!is_hidden) + { + TREE_PUBLIC(decl) = 1; + SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name)); + } + else + { + SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name)); + } + + TREE_USED(decl) = 1; + + if (in_unique_section) + resolve_unique_section (decl, 0, 1); + + rust_preserve_from_gc(decl); + + return new Bvariable(decl, orig_type_tree); +} + +// Set the initial value of a global variable. + +void +Gcc_backend::global_variable_set_init(Bvariable* var, Bexpression* expr) +{ + tree expr_tree = expr->get_tree(); + if (expr_tree == error_mark_node) + return; + gcc_assert(TREE_CONSTANT(expr_tree)); + tree var_decl = var->get_decl(); + if (var_decl == error_mark_node) + return; + DECL_INITIAL(var_decl) = expr_tree; + + // If this variable goes in a unique section, it may need to go into + // a different one now that DECL_INITIAL is set. + if (symtab_node::get(var_decl) + && symtab_node::get(var_decl)->implicit_section) + { + set_decl_section_name (var_decl, NULL); + resolve_unique_section (var_decl, + compute_reloc_for_constant (expr_tree), + 1); + } +} + +// Make a local variable. + +Bvariable* +Gcc_backend::local_variable(Bfunction* function, const std::string& name, + Btype* btype, Bvariable* decl_var, + bool is_address_taken, Location location) +{ + tree type_tree = btype->get_tree(); + if (type_tree == error_mark_node) + return this->error_variable(); + tree decl = build_decl(location.gcc_location(), VAR_DECL, + get_identifier_from_string(name), + type_tree); + DECL_CONTEXT(decl) = function->get_tree(); + TREE_USED(decl) = 1; + if (is_address_taken) + TREE_ADDRESSABLE(decl) = 1; + if (decl_var != NULL) + { + DECL_HAS_VALUE_EXPR_P(decl) = 1; + SET_DECL_VALUE_EXPR(decl, decl_var->get_decl()); + } + rust_preserve_from_gc(decl); + return new Bvariable(decl); +} + +// Make a function parameter variable. + +Bvariable* +Gcc_backend::parameter_variable(Bfunction* function, const std::string& name, + Btype* btype, bool is_address_taken, + Location location) +{ + tree type_tree = btype->get_tree(); + if (type_tree == error_mark_node) + return this->error_variable(); + tree decl = build_decl(location.gcc_location(), PARM_DECL, + get_identifier_from_string(name), + type_tree); + DECL_CONTEXT(decl) = function->get_tree(); + DECL_ARG_TYPE(decl) = type_tree; + TREE_USED(decl) = 1; + if (is_address_taken) + TREE_ADDRESSABLE(decl) = 1; + rust_preserve_from_gc(decl); + return new Bvariable(decl); +} + +// Make a static chain variable. + +Bvariable* +Gcc_backend::static_chain_variable(Bfunction* function, const std::string& name, + Btype* btype, Location location) +{ + tree type_tree = btype->get_tree(); + if (type_tree == error_mark_node) + return this->error_variable(); + tree decl = build_decl(location.gcc_location(), PARM_DECL, + get_identifier_from_string(name), type_tree); + tree fndecl = function->get_tree(); + DECL_CONTEXT(decl) = fndecl; + DECL_ARG_TYPE(decl) = type_tree; + TREE_USED(decl) = 1; + DECL_ARTIFICIAL(decl) = 1; + DECL_IGNORED_P(decl) = 1; + TREE_READONLY(decl) = 1; + + struct function *f = DECL_STRUCT_FUNCTION(fndecl); + if (f == NULL) + { + push_struct_function(fndecl); + pop_cfun(); + f = DECL_STRUCT_FUNCTION(fndecl); + } + gcc_assert(f->static_chain_decl == NULL); + f->static_chain_decl = decl; + DECL_STATIC_CHAIN(fndecl) = 1; + + rust_preserve_from_gc(decl); + return new Bvariable(decl); +} + +// Make a temporary variable. + +Bvariable* +Gcc_backend::temporary_variable(Bfunction* function, Bblock* bblock, + Btype* btype, Bexpression* binit, + bool is_address_taken, + Location location, + Bstatement** pstatement) +{ + gcc_assert(function != NULL); + tree decl = function->get_tree(); + tree type_tree = btype->get_tree(); + tree init_tree = binit == NULL ? NULL_TREE : binit->get_tree(); + if (type_tree == error_mark_node + || init_tree == error_mark_node + || decl == error_mark_node) + { + *pstatement = this->error_statement(); + return this->error_variable(); + } + + tree var; + // We can only use create_tmp_var if the type is not addressable. + if (!TREE_ADDRESSABLE(type_tree)) + { + if (DECL_STRUCT_FUNCTION(decl) == NULL) + push_struct_function(decl); + else + push_cfun(DECL_STRUCT_FUNCTION(decl)); + + var = create_tmp_var(type_tree, "GOTMP"); + pop_cfun(); + } + else + { + gcc_assert(bblock != NULL); + var = build_decl(location.gcc_location(), VAR_DECL, + create_tmp_var_name("GOTMP"), + type_tree); + DECL_ARTIFICIAL(var) = 1; + DECL_IGNORED_P(var) = 1; + TREE_USED(var) = 1; + DECL_CONTEXT(var) = decl; + + // We have to add this variable to the BLOCK and the BIND_EXPR. + tree bind_tree = bblock->get_tree(); + gcc_assert(TREE_CODE(bind_tree) == BIND_EXPR); + tree block_tree = BIND_EXPR_BLOCK(bind_tree); + gcc_assert(TREE_CODE(block_tree) == BLOCK); + DECL_CHAIN(var) = BLOCK_VARS(block_tree); + BLOCK_VARS(block_tree) = var; + BIND_EXPR_VARS(bind_tree) = BLOCK_VARS(block_tree); + } + + if (this->type_size(btype) != 0 + && init_tree != NULL_TREE + && TREE_TYPE(init_tree) != void_type_node) + DECL_INITIAL(var) = this->convert_tree(type_tree, init_tree, location); + + if (is_address_taken) + TREE_ADDRESSABLE(var) = 1; + + *pstatement = this->make_statement(build1_loc(location.gcc_location(), + DECL_EXPR, + void_type_node, var)); + + // For a zero sized type, don't initialize VAR with BINIT, but still + // evaluate BINIT for its side effects. + if (init_tree != NULL_TREE + && (this->type_size(btype) == 0 + || TREE_TYPE(init_tree) == void_type_node)) + *pstatement = + this->compound_statement(this->expression_statement(function, binit), + *pstatement); + + return new Bvariable(var); +} + +// Create an implicit variable that is compiler-defined. This is used when +// generating GC root variables and storing the values of a slice initializer. + +Bvariable* +Gcc_backend::implicit_variable(const std::string& name, + const std::string& asm_name, + Btype* type, bool is_hidden, bool is_constant, + bool is_common, int64_t alignment) +{ + tree type_tree = type->get_tree(); + if (type_tree == error_mark_node) + return this->error_variable(); + + tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL, + get_identifier_from_string(name), type_tree); + DECL_EXTERNAL(decl) = 0; + TREE_PUBLIC(decl) = !is_hidden; + TREE_STATIC(decl) = 1; + TREE_USED(decl) = 1; + DECL_ARTIFICIAL(decl) = 1; + if (is_common) + { + DECL_COMMON(decl) = 1; + + // When the initializer for one implicit_variable refers to another, + // it needs to know the visibility of the referenced struct so that + // compute_reloc_for_constant will return the right value. On many + // systems calling make_decl_one_only will mark the decl as weak, + // which will change the return value of compute_reloc_for_constant. + // We can't reliably call make_decl_one_only yet, because we don't + // yet know the initializer. This issue doesn't arise in C because + // Go initializers, unlike C initializers, can be indirectly + // recursive. To ensure that compute_reloc_for_constant computes + // the right value if some other initializer refers to this one, we + // mark this symbol as weak here. We undo that below in + // immutable_struct_set_init before calling mark_decl_one_only. + DECL_WEAK(decl) = 1; + } + if (is_constant) + { + TREE_READONLY(decl) = 1; + TREE_CONSTANT(decl) = 1; + } + if (alignment != 0) + { + SET_DECL_ALIGN(decl, alignment * BITS_PER_UNIT); + DECL_USER_ALIGN(decl) = 1; + } + if (! asm_name.empty()) + SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name)); + + rust_preserve_from_gc(decl); + return new Bvariable(decl); +} + +// Set the initalizer for a variable created by implicit_variable. +// This is where we finish compiling the variable. + +void +Gcc_backend::implicit_variable_set_init(Bvariable* var, const std::string&, + Btype*, bool, bool, bool is_common, + Bexpression* init) +{ + tree decl = var->get_decl(); + tree init_tree; + if (init == NULL) + init_tree = NULL_TREE; + else + init_tree = init->get_tree(); + if (decl == error_mark_node || init_tree == error_mark_node) + return; + + DECL_INITIAL(decl) = init_tree; + + // Now that DECL_INITIAL is set, we can't call make_decl_one_only. + // See the comment where DECL_WEAK is set in implicit_variable. + if (is_common) + { + DECL_WEAK(decl) = 0; + make_decl_one_only(decl, DECL_ASSEMBLER_NAME(decl)); + } + + resolve_unique_section(decl, 2, 1); + + rest_of_decl_compilation(decl, 1, 0); +} + +// Return a reference to an implicit variable defined in another package. + +Bvariable* +Gcc_backend::implicit_variable_reference(const std::string& name, + const std::string& asm_name, + Btype* btype) +{ + tree type_tree = btype->get_tree(); + if (type_tree == error_mark_node) + return this->error_variable(); + + tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL, + get_identifier_from_string(name), type_tree); + DECL_EXTERNAL(decl) = 1; + TREE_PUBLIC(decl) = 1; + TREE_STATIC(decl) = 0; + DECL_ARTIFICIAL(decl) = 1; + if (! asm_name.empty()) + SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name)); + rust_preserve_from_gc(decl); + return new Bvariable(decl); +} + +// Create a named immutable initialized data structure. + +Bvariable* +Gcc_backend::immutable_struct(const std::string& name, + const std::string& asm_name, + bool is_hidden, + bool is_common, Btype* btype, Location location) +{ + tree type_tree = btype->get_tree(); + if (type_tree == error_mark_node) + return this->error_variable(); + gcc_assert(TREE_CODE(type_tree) == RECORD_TYPE); + tree decl = build_decl(location.gcc_location(), VAR_DECL, + get_identifier_from_string(name), + build_qualified_type(type_tree, TYPE_QUAL_CONST)); + TREE_STATIC(decl) = 1; + TREE_USED(decl) = 1; + TREE_READONLY(decl) = 1; + TREE_CONSTANT(decl) = 1; + DECL_ARTIFICIAL(decl) = 1; + if (!is_hidden) + TREE_PUBLIC(decl) = 1; + if (! asm_name.empty()) + SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name)); + + // When the initializer for one immutable_struct refers to another, + // it needs to know the visibility of the referenced struct so that + // compute_reloc_for_constant will return the right value. On many + // systems calling make_decl_one_only will mark the decl as weak, + // which will change the return value of compute_reloc_for_constant. + // We can't reliably call make_decl_one_only yet, because we don't + // yet know the initializer. This issue doesn't arise in C because + // Go initializers, unlike C initializers, can be indirectly + // recursive. To ensure that compute_reloc_for_constant computes + // the right value if some other initializer refers to this one, we + // mark this symbol as weak here. We undo that below in + // immutable_struct_set_init before calling mark_decl_one_only. + if (is_common) + DECL_WEAK(decl) = 1; + + // We don't call rest_of_decl_compilation until we have the + // initializer. + + rust_preserve_from_gc(decl); + return new Bvariable(decl); +} + +// Set the initializer for a variable created by immutable_struct. +// This is where we finish compiling the variable. + +void +Gcc_backend::immutable_struct_set_init(Bvariable* var, const std::string&, + bool, bool is_common, Btype*, Location, + Bexpression* initializer) +{ + tree decl = var->get_decl(); + tree init_tree = initializer->get_tree(); + if (decl == error_mark_node || init_tree == error_mark_node) + return; + + DECL_INITIAL(decl) = init_tree; + + // Now that DECL_INITIAL is set, we can't call make_decl_one_only. + // See the comment where DECL_WEAK is set in immutable_struct. + if (is_common) + { + DECL_WEAK(decl) = 0; + make_decl_one_only(decl, DECL_ASSEMBLER_NAME(decl)); + } + + // These variables are often unneeded in the final program, so put + // them in their own section so that linker GC can discard them. + resolve_unique_section(decl, + compute_reloc_for_constant (init_tree), + 1); + + rest_of_decl_compilation(decl, 1, 0); +} + +// Return a reference to an immutable initialized data structure +// defined in another package. + +Bvariable* +Gcc_backend::immutable_struct_reference(const std::string& name, + const std::string& asm_name, + Btype* btype, + Location location) +{ + tree type_tree = btype->get_tree(); + if (type_tree == error_mark_node) + return this->error_variable(); + gcc_assert(TREE_CODE(type_tree) == RECORD_TYPE); + tree decl = build_decl(location.gcc_location(), VAR_DECL, + get_identifier_from_string(name), + build_qualified_type(type_tree, TYPE_QUAL_CONST)); + TREE_READONLY(decl) = 1; + TREE_CONSTANT(decl) = 1; + DECL_ARTIFICIAL(decl) = 1; + TREE_PUBLIC(decl) = 1; + DECL_EXTERNAL(decl) = 1; + if (! asm_name.empty()) + SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name)); + rust_preserve_from_gc(decl); + return new Bvariable(decl); +} + +// Make a label. + +Blabel* +Gcc_backend::label(Bfunction* function, const std::string& name, + Location location) +{ + tree decl; + if (name.empty()) + { + tree func_tree = function->get_tree(); + if (DECL_STRUCT_FUNCTION(func_tree) == NULL) + push_struct_function(func_tree); + else + push_cfun(DECL_STRUCT_FUNCTION(func_tree)); + + decl = create_artificial_label(location.gcc_location()); + + pop_cfun(); + } + else + { + tree id = get_identifier_from_string(name); + decl = build_decl(location.gcc_location(), LABEL_DECL, id, + void_type_node); + DECL_CONTEXT(decl) = function->get_tree(); + } + return new Blabel(decl); +} + +// Make a statement which defines a label. + +Bstatement* +Gcc_backend::label_definition_statement(Blabel* label) +{ + tree lab = label->get_tree(); + tree ret = fold_build1_loc(DECL_SOURCE_LOCATION(lab), LABEL_EXPR, + void_type_node, lab); + return this->make_statement(ret); +} + +// Make a goto statement. + +Bstatement* +Gcc_backend::goto_statement(Blabel* label, Location location) +{ + tree lab = label->get_tree(); + tree ret = fold_build1_loc(location.gcc_location(), GOTO_EXPR, void_type_node, + lab); + return this->make_statement(ret); +} + +// Get the address of a label. + +Bexpression* +Gcc_backend::label_address(Blabel* label, Location location) +{ + tree lab = label->get_tree(); + TREE_USED(lab) = 1; + TREE_ADDRESSABLE(lab) = 1; + tree ret = fold_convert_loc(location.gcc_location(), ptr_type_node, + build_fold_addr_expr_loc(location.gcc_location(), + lab)); + return this->make_expression(ret); +} + +// Declare or define a new function. + +Bfunction* +Gcc_backend::function(Btype* fntype, const std::string& name, + const std::string& asm_name, unsigned int flags, + Location location) +{ + tree functype = fntype->get_tree(); + if (functype != error_mark_node) + { + gcc_assert(FUNCTION_POINTER_TYPE_P(functype)); + functype = TREE_TYPE(functype); + } + tree id = get_identifier_from_string(name); + if (functype == error_mark_node || id == error_mark_node) + return this->error_function(); + + tree decl = build_decl(location.gcc_location(), FUNCTION_DECL, id, functype); + if (! asm_name.empty()) + SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name)); + if ((flags & function_is_visible) != 0) + TREE_PUBLIC(decl) = 1; + if ((flags & function_is_declaration) != 0) + DECL_EXTERNAL(decl) = 1; + else + { + tree restype = TREE_TYPE(functype); + tree resdecl = + build_decl(location.gcc_location(), RESULT_DECL, NULL_TREE, restype); + DECL_ARTIFICIAL(resdecl) = 1; + DECL_IGNORED_P(resdecl) = 1; + DECL_CONTEXT(resdecl) = decl; + DECL_RESULT(decl) = resdecl; + } + if ((flags & function_is_inlinable) == 0) + DECL_UNINLINABLE(decl) = 1; + if ((flags & function_no_split_stack) != 0) + { + tree attr = get_identifier ("no_split_stack"); + DECL_ATTRIBUTES(decl) = tree_cons(attr, NULL_TREE, NULL_TREE); + } + if ((flags & function_does_not_return) != 0) + TREE_THIS_VOLATILE(decl) = 1; + if ((flags & function_in_unique_section) != 0) + resolve_unique_section(decl, 0, 1); + if ((flags & function_only_inline) != 0) + { + TREE_PUBLIC (decl) = 1; + DECL_EXTERNAL(decl) = 1; + DECL_DECLARED_INLINE_P(decl) = 1; + } + + // Optimize thunk functions for size. A thunk created for a defer + // statement that may call recover looks like: + // if runtime.setdeferretaddr(L1) { + // goto L1 + // } + // realfn() + // L1: + // The idea is that L1 should be the address to which realfn + // returns. This only works if this little function is not over + // optimized. At some point GCC started duplicating the epilogue in + // the basic-block reordering pass, breaking this assumption. + // Optimizing the function for size avoids duplicating the epilogue. + // This optimization shouldn't matter for any thunk since all thunks + // are small. + size_t pos = name.find("..thunk"); + if (pos != std::string::npos) + { + for (pos += 7; pos < name.length(); ++pos) + { + if (name[pos] < '0' || name[pos] > '9') + break; + } + if (pos == name.length()) + { + struct cl_optimization cur_opts; + cl_optimization_save(&cur_opts, &global_options); + global_options.x_optimize_size = 1; + global_options.x_optimize_fast = 0; + global_options.x_optimize_debug = 0; + DECL_FUNCTION_SPECIFIC_OPTIMIZATION(decl) = + build_optimization_node(&global_options); + cl_optimization_restore(&global_options, &cur_opts); + } + } + + rust_preserve_from_gc(decl); + return new Bfunction(decl); +} + +// Create a statement that runs all deferred calls for FUNCTION. This should +// be a statement that looks like this in C++: +// finish: +// try { UNDEFER; } catch { CHECK_DEFER; goto finish; } + +Bstatement* +Gcc_backend::function_defer_statement(Bfunction* function, Bexpression* undefer, + Bexpression* defer, Location location) +{ + tree undefer_tree = undefer->get_tree(); + tree defer_tree = defer->get_tree(); + tree fntree = function->get_tree(); + + if (undefer_tree == error_mark_node + || defer_tree == error_mark_node + || fntree == error_mark_node) + return this->error_statement(); + + if (DECL_STRUCT_FUNCTION(fntree) == NULL) + push_struct_function(fntree); + else + push_cfun(DECL_STRUCT_FUNCTION(fntree)); + + tree stmt_list = NULL; + Blabel* blabel = this->label(function, "", location); + Bstatement* label_def = this->label_definition_statement(blabel); + append_to_statement_list(label_def->get_tree(), &stmt_list); + + Bstatement* jump_stmt = this->goto_statement(blabel, location); + tree jump = jump_stmt->get_tree(); + tree catch_body = build2(COMPOUND_EXPR, void_type_node, defer_tree, jump); + catch_body = build2(CATCH_EXPR, void_type_node, NULL, catch_body); + tree try_catch = + build2(TRY_CATCH_EXPR, void_type_node, undefer_tree, catch_body); + append_to_statement_list(try_catch, &stmt_list); + pop_cfun(); + + return this->make_statement(stmt_list); +} + +// Record PARAM_VARS as the variables to use for the parameters of FUNCTION. +// This will only be called for a function definition. + +bool +Gcc_backend::function_set_parameters(Bfunction* function, + const std::vector<Bvariable*>& param_vars) +{ + tree func_tree = function->get_tree(); + if (func_tree == error_mark_node) + return false; + + tree params = NULL_TREE; + tree *pp = ¶ms; + for (std::vector<Bvariable*>::const_iterator pv = param_vars.begin(); + pv != param_vars.end(); + ++pv) + { + *pp = (*pv)->get_decl(); + gcc_assert(*pp != error_mark_node); + pp = &DECL_CHAIN(*pp); + } + *pp = NULL_TREE; + DECL_ARGUMENTS(func_tree) = params; + return true; +} + +// Set the function body for FUNCTION using the code in CODE_BLOCK. + +bool +Gcc_backend::function_set_body(Bfunction* function, Bstatement* code_stmt) +{ + tree func_tree = function->get_tree(); + tree code = code_stmt->get_tree(); + + if (func_tree == error_mark_node || code == error_mark_node) + return false; + DECL_SAVED_TREE(func_tree) = code; + return true; +} + +// Look up a named built-in function in the current backend implementation. +// Returns NULL if no built-in function by that name exists. + +Bfunction* +Gcc_backend::lookup_builtin(const std::string& name) +{ + if (this->builtin_functions_.count(name) != 0) + return this->builtin_functions_[name]; + return NULL; +} + +// Write the definitions for all TYPE_DECLS, CONSTANT_DECLS, +// FUNCTION_DECLS, and VARIABLE_DECLS declared globally, as well as +// emit early debugging information. + +void +Gcc_backend::write_global_definitions( + const std::vector<Btype*>& type_decls, + const std::vector<Bexpression*>& constant_decls, + const std::vector<Bfunction*>& function_decls, + const std::vector<Bvariable*>& variable_decls) +{ + size_t count_definitions = type_decls.size() + constant_decls.size() + + function_decls.size() + variable_decls.size(); + + tree* defs = new tree[count_definitions]; + + // Convert all non-erroneous declarations into Gimple form. + size_t i = 0; + for (std::vector<Bvariable*>::const_iterator p = variable_decls.begin(); + p != variable_decls.end(); + ++p) + { + tree v = (*p)->get_decl(); + if (v != error_mark_node) + { + defs[i] = v; + rust_preserve_from_gc(defs[i]); + ++i; + } + } + + for (std::vector<Btype*>::const_iterator p = type_decls.begin(); + p != type_decls.end(); + ++p) + { + tree type_tree = (*p)->get_tree(); + if (type_tree != error_mark_node + && IS_TYPE_OR_DECL_P(type_tree)) + { + defs[i] = TYPE_NAME(type_tree); + gcc_assert(defs[i] != NULL); + rust_preserve_from_gc(defs[i]); + ++i; + } + } + for (std::vector<Bexpression*>::const_iterator p = constant_decls.begin(); + p != constant_decls.end(); + ++p) + { + if ((*p)->get_tree() != error_mark_node) + { + defs[i] = (*p)->get_tree(); + rust_preserve_from_gc(defs[i]); + ++i; + } + } + for (std::vector<Bfunction*>::const_iterator p = function_decls.begin(); + p != function_decls.end(); + ++p) + { + tree decl = (*p)->get_tree(); + if (decl != error_mark_node) + { + rust_preserve_from_gc(decl); + if (DECL_STRUCT_FUNCTION(decl) == NULL) + allocate_struct_function(decl, false); + cgraph_node::finalize_function(decl, true); + + defs[i] = decl; + ++i; + } + } + + // Pass everything back to the middle-end. + + wrapup_global_declarations(defs, i); + + delete[] defs; +} + +void +Gcc_backend::write_export_data(const char* bytes, unsigned int size) +{ + rust_write_export_data(bytes, size); +} + + +// Define a builtin function. BCODE is the builtin function code +// defined by builtins.def. NAME is the name of the builtin function. +// LIBNAME is the name of the corresponding library function, and is +// NULL if there isn't one. FNTYPE is the type of the function. +// CONST_P is true if the function has the const attribute. +// NORETURN_P is true if the function has the noreturn attribute. + +void +Gcc_backend::define_builtin(built_in_function bcode, const char* name, + const char* libname, tree fntype, bool const_p, + bool noreturn_p) +{ + tree decl = add_builtin_function(name, fntype, bcode, BUILT_IN_NORMAL, + libname, NULL_TREE); + if (const_p) + TREE_READONLY(decl) = 1; + if (noreturn_p) + TREE_THIS_VOLATILE(decl) = 1; + set_builtin_decl(bcode, decl, true); + this->builtin_functions_[name] = this->make_function(decl); + if (libname != NULL) + { + decl = add_builtin_function(libname, fntype, bcode, BUILT_IN_NORMAL, + NULL, NULL_TREE); + if (const_p) + TREE_READONLY(decl) = 1; + if (noreturn_p) + TREE_THIS_VOLATILE(decl) = 1; + this->builtin_functions_[libname] = this->make_function(decl); + } +} + +// Return the backend generator. + +Backend* +go_get_backend() +{ + return new Gcc_backend(); +} diff --git a/gcc/rust/rust-lang.c b/gcc/rust/rust-lang.c index 3bc1d95..6e1be89e 100644 --- a/gcc/rust/rust-lang.c +++ b/gcc/rust/rust-lang.c @@ -181,47 +181,47 @@ rust_langhook_handle_option ( switch (code) { - case OPT_I: + /*case OPT_I: rust_add_search_path (arg); - break; - - case OPT_L: - /* A -L option is assumed to come from the compiler driver. - This is a system directory. We search the following - directories, if they exist, before this one: - dir/go/VERSION - dir/go/VERSION/MACHINE - This is like include/c++. */ - { - static const char dir_separator_str[] = { DIR_SEPARATOR, 0 }; - size_t len; - char *p; - struct stat st; - - len = strlen (arg); - p = XALLOCAVEC (char, - (len + sizeof "rust" + sizeof DEFAULT_TARGET_VERSION - + sizeof DEFAULT_TARGET_MACHINE + 3)); - strcpy (p, arg); - if (len > 0 && !IS_DIR_SEPARATOR (p[len - 1])) - strcat (p, dir_separator_str); - strcat (p, "rust"); - strcat (p, dir_separator_str); - strcat (p, DEFAULT_TARGET_VERSION); - if (stat (p, &st) == 0 && S_ISDIR (st.st_mode)) - { - rust_add_search_path (p); - strcat (p, dir_separator_str); - strcat (p, DEFAULT_TARGET_MACHINE); - if (stat (p, &st) == 0 && S_ISDIR (st.st_mode)) - rust_add_search_path (p); - } - - /* Search ARG too, but only after we've searched to Rust - specific directories for all -L arguments. */ - rust_search_dirs.safe_push (arg); - } - break; + break;*/ + + /* case OPT_L: */ + /* /\* A -L option is assumed to come from the compiler driver. */ + /* This is a system directory. We search the following */ + /* directories, if they exist, before this one: */ + /* dir/go/VERSION */ + /* dir/go/VERSION/MACHINE */ + /* This is like include/c++. *\/ */ + /* { */ + /* static const char dir_separator_str[] = { DIR_SEPARATOR, 0 }; */ + /* size_t len; */ + /* char *p; */ + /* struct stat st; */ + + /* len = strlen (arg); */ + /* p = XALLOCAVEC (char, */ + /* (len + sizeof "rust" + sizeof DEFAULT_TARGET_VERSION */ + /* + sizeof DEFAULT_TARGET_MACHINE + 3)); */ + /* strcpy (p, arg); */ + /* if (len > 0 && !IS_DIR_SEPARATOR (p[len - 1])) */ + /* strcat (p, dir_separator_str); */ + /* strcat (p, "rust"); */ + /* strcat (p, dir_separator_str); */ + /* strcat (p, DEFAULT_TARGET_VERSION); */ + /* if (stat (p, &st) == 0 && S_ISDIR (st.st_mode)) */ + /* { */ + /* rust_add_search_path (p); */ + /* strcat (p, dir_separator_str); */ + /* strcat (p, DEFAULT_TARGET_MACHINE); */ + /* if (stat (p, &st) == 0 && S_ISDIR (st.st_mode)) */ + /* rust_add_search_path (p); */ + /* } */ + + /* /\* Search ARG too, but only after we've searched to Rust */ + /* specific directories for all -L arguments. *\/ */ + /* rust_search_dirs.safe_push (arg); */ + /* } */ + /* break; */ default: /* Just return 1 to indicate that the option is valid. */ @@ -241,12 +241,13 @@ rust_langhook_post_options (const char **pfilename ATTRIBUTE_UNUSED) gcc_assert (num_in_fnames > 0); - FOR_EACH_VEC_ELT (rust_search_dirs, ix, dir) - rust_add_search_path (dir); - rust_search_dirs.release (); + // FIXME + /* FOR_EACH_VEC_ELT (rust_search_dirs, ix, dir) */ + /* rust_add_search_path (dir); */ + /* rust_search_dirs.release (); */ - if (flag_excess_precision_cmdline == EXCESS_PRECISION_DEFAULT) - flag_excess_precision_cmdline = EXCESS_PRECISION_STANDARD; + /* if (flag_excess_precision_cmdline == EXCESS_PRECISION_DEFAULT) */ + /* flag_excess_precision_cmdline = EXCESS_PRECISION_STANDARD; */ /* Tail call optimizations can confuse uses of runtime.Callers. */ if (!global_options_set.x_flag_optimize_sibling_calls) @@ -279,10 +280,16 @@ rust_langhook_post_options (const char **pfilename ATTRIBUTE_UNUSED) static void rust_langhook_parse_file (void) { - rust_parse_input_files (in_fnames, num_in_fnames, flag_syntax_only); + // RUSTLY MAIN + + // TODO + // rust_parse_input_files (in_fnames, num_in_fnames, flag_syntax_only); + + /* Final processing of globals and early debug info generation. */ + // rust_write_globals (); - /* Final processing of globals and early debug info generation. */ - // rust_write_globals (); + rust_create_rustly(flag_syntax_only, rust_get_linemap()); + rust_parse_input_files(in_fnames, num_in_fnames); } static tree diff --git a/gcc/rust/rust-system.h b/gcc/rust/rust-system.h index 5a82240..d4c0ac1 100644 --- a/gcc/rust/rust-system.h +++ b/gcc/rust/rust-system.h @@ -37,6 +37,11 @@ #include <set> #include <vector> #include <sstream> +<<<<<<< HEAD +======= +#include <string> +#include <deque> +>>>>>>> c611d209696bd5983b4b777be0beea80351dee46 #if defined(HAVE_UNORDERED_MAP) diff --git a/gcc/rust/rustfrontend/backend.h b/gcc/rust/rustfrontend/backend.h new file mode 100644 index 0000000..d69ad91 --- /dev/null +++ b/gcc/rust/rustfrontend/backend.h @@ -0,0 +1,778 @@ +#pragma once + +#include <gmp.h> +#include <mpfr.h> +#include <mpc.h> + +#include "operator.h" + +// Pointers to these types are created by the backend, passed to the +// frontend, and passed back to the backend. The types must be +// defined by the backend using these names. + +// The backend representation of a type. +class Btype; + +// The backend represention of an expression. +class Bexpression; + +// The backend representation of a statement. +class Bstatement; + +// The backend representation of a function definition or declaration. +class Bfunction; + +// The backend representation of a block. +class Bblock; + +// The backend representation of a variable. +class Bvariable; + +// The backend representation of a label. +class Blabel; + + +// The backend interface. This is a pure abstract class that a +// specific backend will implement. + +class Backend +{ + public: + virtual ~Backend() { } + + // Name/type/location. Used for function parameters, struct fields, + // interface methods. + struct Btyped_identifier + { + std::string name; + Btype* btype; + Location location; + + Btyped_identifier() + : name(), btype(NULL), location(Linemap::unknown_location()) + { } + + Btyped_identifier(const std::string& a_name, Btype* a_btype, + Location a_location) + : name(a_name), btype(a_btype), location(a_location) + { } + }; + + // Types. + + // Produce an error type. Actually the backend could probably just + // crash if this is called. + virtual Btype* + error_type() = 0; + + // Get a void type. This is used in (at least) two ways: 1) as the + // return type of a function with no result parameters; 2) + // unsafe.Pointer is represented as *void. + virtual Btype* + void_type() = 0; + + // Get the unnamed boolean type. + virtual Btype* + bool_type() = 0; + + // Get an unnamed integer type with the given signedness and number + // of bits. + virtual Btype* + integer_type(bool is_unsigned, int bits) = 0; + + // Get an unnamed floating point type with the given number of bits + // (32 or 64). + virtual Btype* + float_type(int bits) = 0; + + // Get an unnamed complex type with the given number of bits (64 or 128). + virtual Btype* + complex_type(int bits) = 0; + + // Get a pointer type. + virtual Btype* + pointer_type(Btype* to_type) = 0; + + // Get a function type. The receiver, parameter, and results are + // generated from the types in the Function_type. The Function_type + // is provided so that the names are available. This should return + // not the type of a Go function (which is a pointer to a struct) + // but the type of a C function pointer (which will be used as the + // type of the first field of the struct). If there is more than + // one result, RESULT_STRUCT is a struct type to hold the results, + // and RESULTS may be ignored; if there are zero or one results, + // RESULT_STRUCT is NULL. + virtual Btype* + function_type(const Btyped_identifier& receiver, + const std::vector<Btyped_identifier>& parameters, + const std::vector<Btyped_identifier>& results, + Btype* result_struct, + Location location) = 0; + + // Get a struct type. + virtual Btype* + struct_type(const std::vector<Btyped_identifier>& fields) = 0; + + // Get an array type. + virtual Btype* + array_type(Btype* element_type, Bexpression* length) = 0; + + // Create a placeholder pointer type. This is used for a named + // pointer type, since in Go a pointer type may refer to itself. + // NAME is the name of the type, and the location is where the named + // type is defined. This function is also used for unnamed function + // types with multiple results, in which case the type has no name + // and NAME will be empty. FOR_FUNCTION is true if this is for a C + // pointer to function type. A Go func type is represented as a + // pointer to a struct, and the first field of the struct is a C + // pointer to function. The return value will later be passed as + // the first parameter to set_placeholder_pointer_type or + // set_placeholder_function_type. + virtual Btype* + placeholder_pointer_type(const std::string& name, Location, + bool for_function) = 0; + + // Fill in a placeholder pointer type as a pointer. This takes a + // type returned by placeholder_pointer_type and arranges for it to + // point to the type that TO_TYPE points to (that is, PLACEHOLDER + // becomes the same type as TO_TYPE). Returns true on success, + // false on failure. + virtual bool + set_placeholder_pointer_type(Btype* placeholder, Btype* to_type) = 0; + + // Fill in a placeholder pointer type as a function. This takes a + // type returned by placeholder_pointer_type and arranges for it to + // become a real Go function type (which corresponds to a C/C++ + // pointer to function type). FT will be something returned by the + // function_type method. Returns true on success, false on failure. + virtual bool + set_placeholder_function_type(Btype* placeholder, Btype* ft) = 0; + + // Create a placeholder struct type. This is used for a named + // struct type, as with placeholder_pointer_type. It is also used + // for interface types, in which case NAME will be the empty string. + virtual Btype* + placeholder_struct_type(const std::string& name, Location) = 0; + + // Fill in a placeholder struct type. This takes a type returned by + // placeholder_struct_type and arranges for it to become a real + // struct type. The parameter is as for struct_type. Returns true + // on success, false on failure. + virtual bool + set_placeholder_struct_type(Btype* placeholder, + const std::vector<Btyped_identifier>& fields) + = 0; + + // Create a placeholder array type. This is used for a named array + // type, as with placeholder_pointer_type, to handle cases like + // type A []*A. + virtual Btype* + placeholder_array_type(const std::string& name, Location) = 0; + + // Fill in a placeholder array type. This takes a type returned by + // placeholder_array_type and arranges for it to become a real array + // type. The parameters are as for array_type. Returns true on + // success, false on failure. + virtual bool + set_placeholder_array_type(Btype* placeholder, Btype* element_type, + Bexpression* length) = 0; + + // Return a named version of a type. The location is the location + // of the type definition. This will not be called for a type + // created via placeholder_pointer_type, placeholder_struct_type, or + // placeholder_array_type.. (It may be called for a pointer, + // struct, or array type in a case like "type P *byte; type Q P".) + virtual Btype* + named_type(const std::string& name, Btype*, Location) = 0; + + // Create a marker for a circular pointer type. Go pointer and + // function types can refer to themselves in ways that are not + // permitted in C/C++. When a circular type is found, this function + // is called for the circular reference. This permits the backend + // to decide how to handle such a type. PLACEHOLDER is the + // placeholder type which has already been created; if the backend + // is prepared to handle a circular pointer type, it may simply + // return PLACEHOLDER. FOR_FUNCTION is true if this is for a + // function type. + // + // For "type P *P" the sequence of calls will be + // bt1 = placeholder_pointer_type(); + // bt2 = circular_pointer_type(bt1, false); + // set_placeholder_pointer_type(bt1, bt2); + virtual Btype* + circular_pointer_type(Btype* placeholder, bool for_function) = 0; + + // Return whether the argument could be a special type created by + // circular_pointer_type. This is used to introduce explicit type + // conversions where needed. If circular_pointer_type returns its + // PLACEHOLDER parameter, this may safely always return false. + virtual bool + is_circular_pointer_type(Btype*) = 0; + + // Return the size of a type. + virtual int64_t + type_size(Btype*) = 0; + + // Return the alignment of a type. + virtual int64_t + type_alignment(Btype*) = 0; + + // Return the alignment of a struct field of this type. This is + // normally the same as type_alignment, but not always. + virtual int64_t + type_field_alignment(Btype*) = 0; + + // Return the offset of field INDEX in a struct type. INDEX is the + // entry in the FIELDS std::vector parameter of struct_type or + // set_placeholder_struct_type. + virtual int64_t + type_field_offset(Btype*, size_t index) = 0; + + // Expressions. + + // Return an expression for a zero value of the given type. This is + // used for cases such as local variable initialization and + // converting nil to other types. + virtual Bexpression* + zero_expression(Btype*) = 0; + + // Create an error expression. This is used for cases which should + // not occur in a correct program, in order to keep the compilation + // going without crashing. + virtual Bexpression* + error_expression() = 0; + + // Create a nil pointer expression. + virtual Bexpression* + nil_pointer_expression() = 0; + + // Create a reference to a variable. + virtual Bexpression* + var_expression(Bvariable* var, Location) = 0; + + // Create an expression that indirects through the pointer expression EXPR + // (i.e., return the expression for *EXPR). KNOWN_VALID is true if the pointer + // is known to point to a valid memory location. BTYPE is the expected type + // of the indirected EXPR. + virtual Bexpression* + indirect_expression(Btype* btype, Bexpression* expr, bool known_valid, + Location) = 0; + + // Return an expression that declares a constant named NAME with the + // constant value VAL in BTYPE. + virtual Bexpression* + named_constant_expression(Btype* btype, const std::string& name, + Bexpression* val, Location) = 0; + + // Return an expression for the multi-precision integer VAL in BTYPE. + virtual Bexpression* + integer_constant_expression(Btype* btype, mpz_t val) = 0; + + // Return an expression for the floating point value VAL in BTYPE. + virtual Bexpression* + float_constant_expression(Btype* btype, mpfr_t val) = 0; + + // Return an expression for the complex value VAL in BTYPE. + virtual Bexpression* + complex_constant_expression(Btype* btype, mpc_t val) = 0; + + // Return an expression for the string value VAL. + virtual Bexpression* + string_constant_expression(const std::string& val) = 0; + + // Return an expression for the boolean value VAL. + virtual Bexpression* + boolean_constant_expression(bool val) = 0; + + // Return an expression for the real part of BCOMPLEX. + virtual Bexpression* + real_part_expression(Bexpression* bcomplex, Location) = 0; + + // Return an expression for the imaginary part of BCOMPLEX. + virtual Bexpression* + imag_part_expression(Bexpression* bcomplex, Location) = 0; + + // Return an expression for the complex number (BREAL, BIMAG). + virtual Bexpression* + complex_expression(Bexpression* breal, Bexpression* bimag, Location) = 0; + + // Return an expression that converts EXPR to TYPE. + virtual Bexpression* + convert_expression(Btype* type, Bexpression* expr, Location) = 0; + + // Create an expression for the address of a function. This is used to + // get the address of the code for a function. + virtual Bexpression* + function_code_expression(Bfunction*, Location) = 0; + + // Create an expression that takes the address of an expression. + virtual Bexpression* + address_expression(Bexpression*, Location) = 0; + + // Return an expression for the field at INDEX in BSTRUCT. + virtual Bexpression* + struct_field_expression(Bexpression* bstruct, size_t index, Location) = 0; + + // Create an expression that executes BSTAT before BEXPR. + virtual Bexpression* + compound_expression(Bstatement* bstat, Bexpression* bexpr, Location) = 0; + + // Return an expression that executes THEN_EXPR if CONDITION is true, or + // ELSE_EXPR otherwise and returns the result as type BTYPE, within the + // specified function FUNCTION. ELSE_EXPR may be NULL. BTYPE may be NULL. + virtual Bexpression* + conditional_expression(Bfunction* function, Btype* btype, + Bexpression* condition, Bexpression* then_expr, + Bexpression* else_expr, Location) = 0; + + // Return an expression for the unary operation OP EXPR. + // Supported values of OP are (from operators.h): + // MINUS, NOT, XOR. + virtual Bexpression* + unary_expression(Operator op, Bexpression* expr, Location) = 0; + + // Return an expression for the binary operation LEFT OP RIGHT. + // Supported values of OP are (from operators.h): + // EQEQ, NOTEQ, LT, LE, GT, GE, PLUS, MINUS, OR, XOR, MULT, DIV, MOD, + // LSHIFT, RSHIFT, AND, NOT. + virtual Bexpression* + binary_expression(Operator op, Bexpression* left, Bexpression* right, + Location) = 0; + + // Return an expression that constructs BTYPE with VALS. BTYPE must be the + // backend representation a of struct. VALS must be in the same order as the + // corresponding fields in BTYPE. + virtual Bexpression* + constructor_expression(Btype* btype, const std::vector<Bexpression*>& vals, + Location) = 0; + + // Return an expression that constructs an array of BTYPE with INDEXES and + // VALS. INDEXES and VALS must have the same amount of elements. Each index + // in INDEXES must be in the same order as the corresponding value in VALS. + virtual Bexpression* + array_constructor_expression(Btype* btype, + const std::vector<unsigned long>& indexes, + const std::vector<Bexpression*>& vals, + Location) = 0; + + // Return an expression for the address of BASE[INDEX]. + // BASE has a pointer type. This is used for slice indexing. + virtual Bexpression* + pointer_offset_expression(Bexpression* base, Bexpression* index, + Location) = 0; + + // Return an expression for ARRAY[INDEX] as an l-value. ARRAY is a valid + // fixed-length array, not a slice. + virtual Bexpression* + array_index_expression(Bexpression* array, Bexpression* index, Location) = 0; + + // Create an expression for a call to FN with ARGS, taking place within + // caller CALLER. + virtual Bexpression* + call_expression(Bfunction *caller, Bexpression* fn, + const std::vector<Bexpression*>& args, + Bexpression* static_chain, Location) = 0; + + // Statements. + + // Create an error statement. This is used for cases which should + // not occur in a correct program, in order to keep the compilation + // going without crashing. + virtual Bstatement* + error_statement() = 0; + + // Create an expression statement within the specified function. + virtual Bstatement* + expression_statement(Bfunction*, Bexpression*) = 0; + + // Create a variable initialization statement in the specified + // function. This initializes a local variable at the point in the + // program flow where it is declared. + virtual Bstatement* + init_statement(Bfunction*, Bvariable* var, Bexpression* init) = 0; + + // Create an assignment statement within the specified function. + virtual Bstatement* + assignment_statement(Bfunction*, Bexpression* lhs, Bexpression* rhs, + Location) = 0; + + // Create a return statement, passing the representation of the + // function and the list of values to return. + virtual Bstatement* + return_statement(Bfunction*, const std::vector<Bexpression*>&, + Location) = 0; + + // Create an if statement within a function. ELSE_BLOCK may be NULL. + virtual Bstatement* + if_statement(Bfunction*, Bexpression* condition, + Bblock* then_block, Bblock* else_block, + Location) = 0; + + // Create a switch statement where the case values are constants. + // CASES and STATEMENTS must have the same number of entries. If + // VALUE matches any of the list in CASES[i], which will all be + // integers, then STATEMENTS[i] is executed. STATEMENTS[i] will + // either end with a goto statement or will fall through into + // STATEMENTS[i + 1]. CASES[i] is empty for the default clause, + // which need not be last. FUNCTION is the current function. + virtual Bstatement* + switch_statement(Bfunction* function, Bexpression* value, + const std::vector<std::vector<Bexpression*> >& cases, + const std::vector<Bstatement*>& statements, + Location) = 0; + + // Create a single statement from two statements. + virtual Bstatement* + compound_statement(Bstatement*, Bstatement*) = 0; + + // Create a single statement from a list of statements. + virtual Bstatement* + statement_list(const std::vector<Bstatement*>&) = 0; + + // Create a statement that attempts to execute BSTAT and calls EXCEPT_STMT if + // an exception occurs. EXCEPT_STMT may be NULL. FINALLY_STMT may be NULL and + // if not NULL, it will always be executed. This is used for handling defers + // in Go functions. In C++, the resulting code is of this form: + // try { BSTAT; } catch { EXCEPT_STMT; } finally { FINALLY_STMT; } + virtual Bstatement* + exception_handler_statement(Bstatement* bstat, Bstatement* except_stmt, + Bstatement* finally_stmt, Location) = 0; + + // Blocks. + + // Create a block. The frontend will call this function when it + // starts converting a block within a function. FUNCTION is the + // current function. ENCLOSING is the enclosing block; it will be + // NULL for the top-level block in a function. VARS is the list of + // local variables defined within this block; each entry will be + // created by the local_variable function. START_LOCATION is the + // location of the start of the block, more or less the location of + // the initial curly brace. END_LOCATION is the location of the end + // of the block, more or less the location of the final curly brace. + // The statements will be added after the block is created. + virtual Bblock* + block(Bfunction* function, Bblock* enclosing, + const std::vector<Bvariable*>& vars, + Location start_location, Location end_location) = 0; + + // Add the statements to a block. The block is created first. Then + // the statements are created. Then the statements are added to the + // block. This will called exactly once per block. The vector may + // be empty if there are no statements. + virtual void + block_add_statements(Bblock*, const std::vector<Bstatement*>&) = 0; + + // Return the block as a statement. This is used to include a block + // in a list of statements. + virtual Bstatement* + block_statement(Bblock*) = 0; + + // Variables. + + // Create an error variable. This is used for cases which should + // not occur in a correct program, in order to keep the compilation + // going without crashing. + virtual Bvariable* + error_variable() = 0; + + // Create a global variable. NAME is the package-qualified name of + // the variable. ASM_NAME is the encoded identifier for the + // variable, incorporating the package, and made safe for the + // assembler. BTYPE is the type of the variable. IS_EXTERNAL is + // true if the variable is defined in some other package. IS_HIDDEN + // is true if the variable is not exported (name begins with a lower + // case letter). IN_UNIQUE_SECTION is true if the variable should + // be put into a unique section if possible; this is intended to + // permit the linker to garbage collect the variable if it is not + // referenced. LOCATION is where the variable was defined. + virtual Bvariable* + global_variable(const std::string& name, + const std::string& asm_name, + Btype* btype, + bool is_external, + bool is_hidden, + bool in_unique_section, + Location location) = 0; + + // A global variable will 1) be initialized to zero, or 2) be + // initialized to a constant value, or 3) be initialized in the init + // function. In case 2, the frontend will call + // global_variable_set_init to set the initial value. If this is + // not called, the backend should initialize a global variable to 0. + // The init function may then assign a value to it. + virtual void + global_variable_set_init(Bvariable*, Bexpression*) = 0; + + // Create a local variable. The frontend will create the local + // variables first, and then create the block which contains them. + // FUNCTION is the function in which the variable is defined. NAME + // is the name of the variable. TYPE is the type. DECL_VAR, if not + // null, gives the location at which the value of this variable may + // be found, typically used to create an inner-scope reference to an + // outer-scope variable, to extend the lifetime of the variable beyond + // the inner scope. IS_ADDRESS_TAKEN is true if the address of this + // variable is taken (this implies that the address does not escape + // the function, as otherwise the variable would be on the heap). + // LOCATION is where the variable is defined. For each local variable + // the frontend will call init_statement to set the initial value. + virtual Bvariable* + local_variable(Bfunction* function, const std::string& name, Btype* type, + Bvariable* decl_var, bool is_address_taken, Location location) = 0; + + // Create a function parameter. This is an incoming parameter, not + // a result parameter (result parameters are treated as local + // variables). The arguments are as for local_variable. + virtual Bvariable* + parameter_variable(Bfunction* function, const std::string& name, + Btype* type, bool is_address_taken, + Location location) = 0; + + // Create a static chain parameter. This is the closure parameter. + virtual Bvariable* + static_chain_variable(Bfunction* function, const std::string& name, + Btype* type, Location location) = 0; + + // Create a temporary variable. A temporary variable has no name, + // just a type. We pass in FUNCTION and BLOCK in case they are + // needed. If INIT is not NULL, the variable should be initialized + // to that value. Otherwise the initial value is irrelevant--the + // backend does not have to explicitly initialize it to zero. + // ADDRESS_IS_TAKEN is true if the programs needs to take the + // address of this temporary variable. LOCATION is the location of + // the statement or expression which requires creating the temporary + // variable, and may not be very useful. This function should + // return a variable which can be referenced later and should set + // *PSTATEMENT to a statement which initializes the variable. + virtual Bvariable* + temporary_variable(Bfunction*, Bblock*, Btype*, Bexpression* init, + bool address_is_taken, Location location, + Bstatement** pstatement) = 0; + + // Create an implicit variable that is compiler-defined. This is + // used when generating GC data and roots, when storing the values + // of a slice constructor, and for the zero value of types. This returns a + // Bvariable because it corresponds to an initialized variable in C. + // + // NAME is the name to use for the initialized variable this will create. + // + // ASM_NAME is encoded assembler-friendly version of the name, or the + // empty string if no encoding is needed. + // + // TYPE is the type of the implicit variable. + // + // IS_HIDDEN will be true if the descriptor should only be visible + // within the current object. + // + // IS_CONSTANT is true if the implicit variable should be treated like it is + // immutable. For slice initializers, if the values must be copied to the + // heap, the variable IS_CONSTANT. + // + // IS_COMMON is true if the implicit variable should + // be treated as a common variable (multiple definitions with + // different sizes permitted in different object files, all merged + // into the largest definition at link time); this will be true for + // the zero value. IS_HIDDEN and IS_COMMON will never both be true. + // + // If ALIGNMENT is not zero, it is the desired alignment of the variable. + virtual Bvariable* + implicit_variable(const std::string& name, const std::string& asm_name, + Btype* type, bool is_hidden, bool is_constant, + bool is_common, int64_t alignment) = 0; + + + // Set the initial value of a variable created by implicit_variable. + // This must be called even if there is no initializer, i.e., INIT is NULL. + // The NAME, TYPE, IS_HIDDEN, IS_CONSTANT, and IS_COMMON parameters are + // the same ones passed to implicit_variable. INIT will be a composite + // literal of type TYPE. It will not contain any function calls or anything + // else that can not be put into a read-only data section. + // It may contain the address of variables created by implicit_variable. + // + // If IS_COMMON is true, INIT will be NULL, and the + // variable should be initialized to all zeros. + virtual void + implicit_variable_set_init(Bvariable*, const std::string& name, Btype* type, + bool is_hidden, bool is_constant, bool is_common, + Bexpression* init) = 0; + + // Create a reference to a named implicit variable defined in some + // other package. This will be a variable created by a call to + // implicit_variable with the same NAME, ASM_NAME and TYPE and with + // IS_COMMON passed as false. This corresponds to an extern global + // variable in C. + virtual Bvariable* + implicit_variable_reference(const std::string& name, + const std::string& asm_name, + Btype* type) = 0; + + // Create a named immutable initialized data structure. This is + // used for type descriptors, map descriptors, and function + // descriptors. This returns a Bvariable because it corresponds to + // an initialized const variable in C. + // + // NAME is the name to use for the initialized global variable which + // this call will create. + // + // ASM_NAME is the encoded, assembler-friendly version of NAME, or + // the empty string if no encoding is needed. + // + // IS_HIDDEN will be true if the descriptor should only be visible + // within the current object. + // + // IS_COMMON is true if NAME may be defined by several packages, and + // the linker should merge all such definitions. If IS_COMMON is + // false, NAME should be defined in only one file. In general + // IS_COMMON will be true for the type descriptor of an unnamed type + // or a builtin type. IS_HIDDEN and IS_COMMON will never both be + // true. + // + // TYPE will be a struct type; the type of the returned expression + // must be a pointer to this struct type. + // + // We must create the named structure before we know its + // initializer, because the initializer may refer to its own + // address. After calling this the frontend will call + // immutable_struct_set_init. + virtual Bvariable* + immutable_struct(const std::string& name, + const std::string& asm_name, + bool is_hidden, bool is_common, + Btype* type, Location) = 0; + + // Set the initial value of a variable created by immutable_struct. + // The NAME, IS_HIDDEN, IS_COMMON, TYPE, and location parameters are + // the same ones passed to immutable_struct. INITIALIZER will be a + // composite literal of type TYPE. It will not contain any function + // calls or anything else that can not be put into a read-only data + // section. It may contain the address of variables created by + // immutable_struct. + virtual void + immutable_struct_set_init(Bvariable*, const std::string& name, + bool is_hidden, bool is_common, Btype* type, + Location, Bexpression* initializer) = 0; + + // Create a reference to a named immutable initialized data + // structure defined in some other package. This will be a + // structure created by a call to immutable_struct with the same + // NAME, ASM_NAME and TYPE and with IS_COMMON passed as false. This + // corresponds to an extern const global variable in C. + virtual Bvariable* + immutable_struct_reference(const std::string& name, + const std::string& asm_name, + Btype* type, Location) = 0; + + // Labels. + + // Create a new label. NAME will be empty if this is a label + // created by the frontend for a loop construct. The location is + // where the label is defined. + virtual Blabel* + label(Bfunction*, const std::string& name, Location) = 0; + + // Create a statement which defines a label. This statement will be + // put into the codestream at the point where the label should be + // defined. + virtual Bstatement* + label_definition_statement(Blabel*) = 0; + + // Create a goto statement to a label. + virtual Bstatement* + goto_statement(Blabel*, Location) = 0; + + // Create an expression for the address of a label. This is used to + // get the return address of a deferred function which may call + // recover. + virtual Bexpression* + label_address(Blabel*, Location) = 0; + + // Functions. + + // Create an error function. This is used for cases which should + // not occur in a correct program, in order to keep the compilation + // going without crashing. + virtual Bfunction* + error_function() = 0; + + // Bit flags to pass to the function method. + + // Set if the function should be visible outside of the current + // compilation unit. + static const unsigned int function_is_visible = 1 << 0; + + // Set if this is a function declaration rather than a definition; + // the definition will be in another compilation unit. + static const unsigned int function_is_declaration = 1 << 1; + + // Set if the function can be inlined. This is normally set, but is + // false for functions that may not be inlined because they call + // recover and must be visible for correct panic recovery. + static const unsigned int function_is_inlinable = 1 << 2; + + // Set if the function may not split the stack. This is set for the + // implementation of recover itself, among other things. + static const unsigned int function_no_split_stack = 1 << 3; + + // Set if the function does not return. This is set for the + // implementation of panic. + static const unsigned int function_does_not_return = 1 << 4; + + // Set if the function should be put in a unique section if + // possible. This is used for field tracking. + static const unsigned int function_in_unique_section = 1 << 5; + + // Set if the function should be available for inlining in the + // backend, but should not be emitted as a standalone function. Any + // call to the function that is not inlined should be treated as a + // call to a function defined in a different compilation unit. This + // is like a C99 function marked inline but not extern. + static const unsigned int function_only_inline = 1 << 6; + + // Declare or define a function of FNTYPE. + // NAME is the Go name of the function. ASM_NAME, if not the empty + // string, is the name that should be used in the symbol table; this + // will be non-empty if a magic extern comment is used. FLAGS is + // bit flags described above. + virtual Bfunction* + function(Btype* fntype, const std::string& name, const std::string& asm_name, + unsigned int flags, Location) = 0; + + // Create a statement that runs all deferred calls for FUNCTION. This should + // be a statement that looks like this in C++: + // finish: + // try { DEFER_RETURN; } catch { CHECK_DEFER; goto finish; } + virtual Bstatement* + function_defer_statement(Bfunction* function, Bexpression* undefer, + Bexpression* check_defer, Location) = 0; + + // Record PARAM_VARS as the variables to use for the parameters of FUNCTION. + // This will only be called for a function definition. Returns true on + // success, false on failure. + virtual bool + function_set_parameters(Bfunction* function, + const std::vector<Bvariable*>& param_vars) = 0; + + // Set the function body for FUNCTION using the code in CODE_STMT. Returns + // true on success, false on failure. + virtual bool + function_set_body(Bfunction* function, Bstatement* code_stmt) = 0; + + // Look up a named built-in function in the current backend implementation. + // Returns NULL if no built-in function by that name exists. + virtual Bfunction* + lookup_builtin(const std::string&) = 0; + + // Utility. + + // Write the definitions for all TYPE_DECLS, CONSTANT_DECLS, + // FUNCTION_DECLS, and VARIABLE_DECLS declared globally. + virtual void + write_global_definitions(const std::vector<Btype*>& type_decls, + const std::vector<Bexpression*>& constant_decls, + const std::vector<Bfunction*>& function_decls, + const std::vector<Bvariable*>& variable_decls) = 0; + + // Write SIZE bytes of export data from BYTES to the proper + // section in the output object file. + virtual void + write_export_data(const char* bytes, unsigned int size) = 0; +}; diff --git a/gcc/rust/rustfrontend/node.cc b/gcc/rust/rustfrontend/node.cc new file mode 100644 index 0000000..24393a5 --- /dev/null +++ b/gcc/rust/rustfrontend/node.cc @@ -0,0 +1,862 @@ +#include "rust-system.h" +#include "node.h" + + +static int const indent_step = 4; + +void print_indent(int depth); + +#define PUSHBACK_LEN 4 + +static char pushback[PUSHBACK_LEN]; +static int verbose; +struct node* nodes = NULL; +int n_nodes; + +void +parser_init(int v) +{ + verbose = v; + n_nodes = 0; + memset(pushback, '\0', PUSHBACK_LEN); +} + +// Note: this does nothing if the pushback queue is full. As long as +// there aren't more than PUSHBACK_LEN consecutive calls to push_back +// in an action, this shouldn't be a problem. +void push_back(char c) +{ + for (int i = 0; i < PUSHBACK_LEN; ++i) { + if (pushback[i] == '\0') { + pushback[i] = c; + break; + } + } +} + +Node +mk_node(ast_opcode_t op, int n, ...) +{ + unsigned sz = sizeof(struct node); + struct node* nd = (struct node *)xmalloc(sz); + nd->elems = (struct node **)xcalloc(n, sizeof(struct node*)); + + nd->prev = NULL; + nd->next = nodes; + if (nodes) { + nodes->prev = nd; + } + nodes = nd; + + nd->op = op; + nd->value = NULL; + nd->n_elems = n; + + va_list ap; + va_start(ap, n); + for (int i = 0; i < n; ++i) + { + struct node *nn = va_arg(ap, struct node *); + nd->elems[i] = nn; + } + va_end(ap); + + n_nodes++; + return nd; +} + +Node +mk_node_value(ast_opcode_t op, char* value, int n, ...) +{ + unsigned sz = sizeof(struct node); + struct node* nd = (struct node *)xmalloc(sz); + nd->elems = (struct node **)xcalloc(n, sizeof(struct node*)); + + nd->prev = NULL; + nd->next = nodes; + if (nodes) { + nodes->prev = nd; + } + nodes = nd; + + nd->op = op; + nd->value = value; + nd->n_elems = n; + + va_list ap; + va_start(ap, n); + for (int i = 0; i < n; ++i) + { + struct node *nn = va_arg(ap, struct node *); + nd->elems[i] = nn; + } + va_end(ap); + + n_nodes++; + return nd; +} + +Node +mk_atom(ast_opcode_t op, const char *value) +{ + return value == NULL ? + mk_empty_atom(op) : + mk_node_value(op, xstrdup(value), 0); +} + +Node +mk_empty_atom(ast_opcode_t op) +{ + return mk_node_value(op, NULL, 0); +} + +Node +mk_none() +{ + return mk_atom(NN_NONE, NULL); +} + +Node +ext_node(Node nd, int n, ...) +{ + int c = nd->n_elems + n; + unsigned sz = sizeof(struct node) + (c * sizeof(struct node *)); + + if (nd->next) { + nd->next->prev = nd->prev; + } + if (nd->prev) { + nd->prev->next = nd->next; + } + nd = (struct node*)xrealloc(nd, sz); + nd->prev = NULL; + nd->next = nodes; + nodes->prev = nd; + nodes = nd; + + va_list ap; + va_start(ap, n); + for (int i = 0; i < n; ++i) { + struct node* nn = va_arg(ap, struct node *); + nd->elems[nd->n_elems++] = nn; + } + va_end(ap); + + return nd; +} + + +void +print_indent(int depth) { + while (depth) { + if (depth-- % indent_step == 0) { + printf("|"); + } else { + printf(" "); + } + } +} + +void +print_node(Node n, int depth) +{ + print_indent(depth); + + if (n->n_elems == 0) { + printf("%s -> %s\n", NODE_TYPE_STR(n), NODE_TYPE_VALUE_STR(n)); + return; + } + + printf("(%s\n", NODE_TYPE_STR(n)); + for (int i = 0; i < n->n_elems; ++i) { + print_node(n->elems[i], depth + indent_step); + } + print_indent(depth); + printf(")\n"); +} + +const char* +get_ast_op_string(ast_opcode_t op) +{ + switch (op) { + case NN_ViewItemExternFn: + return "NN_ViewItemExternFn"; + case NN_TyParam: + return "NN_TyParam"; + case NN_DeclLocal: + return "NN_DeclLocal"; + case NN_DocComment: + return "NN_DocComment"; + case NN_WherePredicate: + return "NN_WherePredicate"; + case NN_ExprAddrOf: + return "NN_ExprAddrOf"; + case NN_TypeMethod: + return "NN_TypeMethod"; + case NN_crate: + return "NN_crate"; + case NN_DefaultFieldInit: + return "NN_DefaultFieldInit"; + case NN_ExprBinary: + return "NN_ExprBinary"; + case NN_ExprAssignBitAnd: + return "NN_ExprAssignBitAnd"; + case NN_TyFnDecl: + return "NN_TyFnDecl"; + case NN_Public: + return "NN_Public"; + case NN_Pats: + return "NN_Pats"; + case NN_ViewPathSimple: + return "NN_ViewPathSimple"; + case NN_TyParams: + return "NN_TyParams"; + case NN_ExprIf: + return "NN_ExprIf"; + case NN_Args: + return "NN_Args"; + case NN_MetaItems: + return "NN_MetaItems"; + case NN_AttrsAndVis: + return "NN_AttrsAndVis"; + case NN_LitInteger: + return "NN_LitInteger"; + case NN_ExprPath: + return "NN_ExprPath"; + case NN_ExprField: + return "NN_ExprField"; + case NN_TyDefault: + return "NN_TyDefault"; + case NN_ExprAssignAdd: + return "NN_ExprAssignAdd"; + case NN_ExprYield: + return "NN_ExprYield"; + case NN_ImplItems: + return "NN_ImplItems"; + case NN_TyRptr: + return "NN_TyRptr"; + case NN_TySum: + return "NN_TySum"; + case NN_ExprAssignDiv: + return "NN_ExprAssignDiv"; + case NN_PatTup: + return "NN_PatTup"; + case NN_ViewPath: + return "NN_ViewPath"; + case NN_ItemImplNeg: + return "NN_ItemImplNeg"; + case NN_ExprWhile: + return "NN_ExprWhile"; + case NN_WherePredicates: + return "NN_WherePredicates"; + case NN_FieldInits: + return "NN_FieldInits"; + case NN_PatQualifiedPath: + return "NN_PatQualifiedPath"; + case NN_ExprMatch: + return "NN_ExprMatch"; + case NN_Binding: + return "NN_Binding"; + case NN_ExprAssignBitOr: + return "NN_ExprAssignBitOr"; + case NN_ItemImpl: + return "NN_ItemImpl"; + case NN_ForeignItem: + return "NN_ForeignItem"; + case NN_Arg: + return "NN_Arg"; + case NN_Bindings: + return "NN_Bindings"; + case NN_PatWild: + return "NN_PatWild"; + case NN_ExprTypeAscr: + return "NN_ExprTypeAscr"; + case NN_ExprBreak: + return "NN_ExprBreak"; + case NN_ExprIfLet: + return "NN_ExprIfLet"; + case NN_Inherited: + return "NN_Inherited"; + case NN_TyPtr: + return "NN_TyPtr"; + case NN_Arms: + return "NN_Arms"; + case NN_LitByteStr: + return "NN_LitByteStr"; + case NN_ItemConst: + return "NN_ItemConst"; + case NN_ItemImplDefault: + return "NN_ItemImplDefault"; + case NN_VecRepeat: + return "NN_VecRepeat"; + case NN_TTTok: + return "NN_TTTok"; + case NN_RetTy: + return "NN_RetTy"; + case NN_TySumsAndBindings: + return "NN_TySumsAndBindings"; + case NN_MetaList: + return "NN_MetaList"; + case NN_ExprQualifiedPath: + return "NN_ExprQualifiedPath"; + case NN_ExprAssignBitXor: + return "NN_ExprAssignBitXor"; + case NN_Macro: + return "NN_Macro"; + case NN_Super: + return "NN_Super"; + case NN_ForeignFn: + return "NN_ForeignFn"; + case NN_SelfLower: + return "NN_SelfLower"; + case NN_ExprAssign: + return "NN_ExprAssign"; + case NN_OuterAttrs: + return "NN_OuterAttrs"; + case NN_ItemMacro: + return "NN_ItemMacro"; + case NN_ForeignItems: + return "NN_ForeignItems"; + case NN_Items: + return "NN_Items"; + case NN_TraitMacroItem: + return "NN_TraitMacroItem"; + case NN_ExprWhileLet: + return "NN_ExprWhileLet"; + case NN_BindByRef: + return "NN_BindByRef"; + case NN_ImplType: + return "NN_ImplType"; + case NN_ExprLoop: + return "NN_ExprLoop"; + case NN_SelfRegion: + return "NN_SelfRegion"; + case NN_TyTup: + return "NN_TyTup"; + case NN_PatUnit: + return "NN_PatUnit"; + case NN_ForInType: + return "NN_ForInType"; + case NN_FnDecl: + return "NN_FnDecl"; + case NN_PatUniq: + return "NN_PatUniq"; + case NN_UnsafeBlock: + return "NN_UnsafeBlock"; + case NN_TyQualifiedPath: + return "NN_TyQualifiedPath"; + case NN_TyBox: + return "NN_TyBox"; + case NN_PatEnum: + return "NN_PatEnum"; + case NN_TyClosure: + return "NN_TyClosure"; + case NN_ForSized: + return "NN_ForSized"; + case NN_ExprAssignSub: + return "NN_ExprAssignSub"; + case NN_GenericValues: + return "NN_GenericValues"; + case NN_TyPath: + return "NN_TyPath"; + case NN_PatIdent: + return "NN_PatIdent"; + case NN_ConstDefault: + return "NN_ConstDefault"; + case NN_WhereClause: + return "NN_WhereClause"; + case NN_MutImmutable: + return "NN_MutImmutable"; + case NN_TyMacro: + return "NN_TyMacro"; + case NN_ExprTupleIndex: + return "NN_ExprTupleIndex"; + case NN_ImplMacroItem: + return "NN_ImplMacroItem"; + case NN_ExprTry: + return "NN_ExprTry"; + case NN_ExprCast: + return "NN_ExprCast"; + case NN_Provided: + return "NN_Provided"; + case NN_PatRegion: + return "NN_PatRegion"; + case NN_ExprAssignShl: + return "NN_ExprAssignShl"; + case NN_static_lifetime: + return "NN_static_lifetime"; + case NN_MetaNameValue: + return "NN_MetaNameValue"; + case NN_ExprStruct: + return "NN_ExprStruct"; + case NN_ExprAssignShr: + return "NN_ExprAssignShr"; + case NN_FieldInit: + return "NN_FieldInit"; + case NN_Generics: + return "NN_Generics"; + case NN_ExprForLoop: + return "NN_ExprForLoop"; + case NN_Method: + return "NN_Method"; + case NN_TySums: + return "NN_TySums"; + case NN_ExprVec: + return "NN_ExprVec"; + case NN_LitChar: + return "NN_LitChar"; + case NN_PatFields: + return "NN_PatFields"; + case NN_PatMac: + return "NN_PatMac"; + case NN_InnerAttr: + return "NN_InnerAttr"; + case NN_ViewPathGlob: + return "NN_ViewPathGlob"; + case NN_ItemStatic: + return "NN_ItemStatic"; + case NN_PatRange: + return "NN_PatRange"; + case NN_LitBool: + return "NN_LitBool"; + case NN_IdentsOrSelf: + return "NN_IdentsOrSelf"; + case NN_ItemFn: + return "NN_ItemFn"; + case NN_ExprCall: + return "NN_ExprCall"; + case NN_Default: + return "NN_Default"; + case NN_trait: + return "NN_trait"; + case NN_Required: + return "NN_Required"; + case NN_TyInfer: + return "NN_TyInfer"; + case NN_ConstTraitItem: + return "NN_ConstTraitItem"; + case NN_SelfStatic: + return "NN_SelfStatic"; + case NN_ExprAssignRem: + return "NN_ExprAssignRem"; + case NN_PatLit: + return "NN_PatLit"; + case NN_PatField: + return "NN_PatField"; + case NN_TyNil: + return "NN_TyNil"; + case NN_EnumDef: + return "NN_EnumDef"; + case NN_TypeTraitItem: + return "NN_TypeTraitItem"; + case NN_PatVec: + return "NN_PatVec"; + case NN_ident: + return "NN_ident"; + case NN_MetaWord: + return "NN_MetaWord"; + case NN_Lifetimes: + return "NN_Lifetimes"; + case NN_LitStr: + return "NN_LitStr"; + case NN_SelfPath: + return "NN_SelfPath"; + case NN_bounds: + return "NN_bounds"; + case NN_EnumDefs: + return "NN_EnumDefs"; + case NN_ltbounds: + return "NN_ltbounds"; + case NN_ViewItemUse: + return "NN_ViewItemUse"; + case NN_ItemImplDefaultNeg: + return "NN_ItemImplDefaultNeg"; + case NN_PatVecElts: + return "NN_PatVecElts"; + case NN_TokenTrees: + return "NN_TokenTrees"; + case NN_semicolon: + return "NN_semicolon"; + case NN_ItemMod: + return "NN_ItemMod"; + case NN_ExprUnary: + return "NN_ExprUnary"; + case NN_ExprBlock: + return "NN_ExprBlock"; + case NN_ItemUnsafeFn: + return "NN_ItemUnsafeFn"; + case NN_EnumArgs: + return "NN_EnumArgs"; + case NN_ViewItemExternCrate: + return "NN_ViewItemExternCrate"; + case NN_lifetime: + return "NN_lifetime"; + case NN_StructFields: + return "NN_StructFields"; + case NN_ExprRet: + return "NN_ExprRet"; + case NN_ExprAssignMul: + return "NN_ExprAssignMul"; + case NN_ItemStruct: + return "NN_ItemStruct"; + case NN_LitFloat: + return "NN_LitFloat"; + case NN_TyTypeof: + return "NN_TyTypeof"; + case NN_exprs: + return "NN_exprs"; + case NN_InnerAttrs: + return "NN_InnerAttrs"; + case NN_PolyBound: + return "NN_PolyBound"; + case NN_TyVec: + return "NN_TyVec"; + case NN_ArmNonblock: + return "NN_ArmNonblock"; + case NN_ViewPathList: + return "NN_ViewPathList"; + case NN_TTDelim: + return "NN_TTDelim"; + case NN_ItemForeignMod: + return "NN_ItemForeignMod"; + case NN_PatTupElts: + return "NN_PatTupElts"; + case NN_ExprMac: + return "NN_ExprMac"; + case NN_ExprParen: + return "NN_ExprParen"; + case NN_StaticItem: + return "NN_StaticItem"; + case NN_ItemTrait: + return "NN_ItemTrait"; + case NN_ExprRange: + return "NN_ExprRange"; + case NN_ItemUnion: + return "NN_ItemUnion"; + case NN_ExprIndex: + return "NN_ExprIndex"; + case NN_ArmBlock: + return "NN_ArmBlock"; + case NN_DefaultUnsafe: + return "NN_DefaultUnsafe"; + case NN_PatStruct: + return "NN_PatStruct"; + case NN_MutMutable: + return "NN_MutMutable"; + case NN_ExprLit: + return "NN_ExprLit"; + case NN_TyFixedLengthVec: + return "NN_TyFixedLengthVec"; + case NN_ImplConst: + return "NN_ImplConst"; + case NN_InferrableParams: + return "NN_InferrableParams"; + case NN_Item: + return "NN_Item"; + case NN_TraitItems: + return "NN_TraitItems"; + case NN_MacroExpr: + return "NN_MacroExpr"; + case NN_LitByte: + return "NN_LitByte"; + case NN_InferrableParam: + return "NN_InferrableParam"; + case NN_BindByValue: + return "NN_BindByValue"; + case NN_StructField: + return "NN_StructField"; + case NN_Unsafe: + return "NN_Unsafe"; + case NN_ViewPathListEmpty: + return "NN_ViewPathListEmpty"; + case NN_ExprFnBlock: + return "NN_ExprFnBlock"; + case NN_ExprAgain: + return "NN_ExprAgain"; + case NN_components: + return "NN_components"; + case NN_ItemEnum: + return "NN_ItemEnum"; + case NN_ExprBox: + return "NN_ExprBox"; + case NN_ItemTy: + return "NN_ItemTy"; + case NN_NONE: + return "NN_NONE"; + case NN_SHL: + return "NN_SHL"; + case NN_SHR: + return "NN_SHR"; + case NN_LE: + return "NN_LE"; + case NN_EQEQ: + return "NN_EQEQ"; + case NN_NE: + return "NN_NE"; + case NN_GE: + return "NN_GE"; + case NN_ANDAND: + return "NN_ANDAND"; + case NN_OROR: + return "NN_OROR"; + case NN_LARROW: + return "NN_LARROW"; + case NN_SHLEQ: + return "NN_SHLEQ"; + case NN_SHREQ: + return "NN_SHREQ"; + case NN_MINUSEQ: + return "NN_MINUSEQ"; + case NN_ANDEQ: + return "NN_ANDEQ"; + case NN_OREQ: + return "NN_OREQ"; + case NN_PLUSEQ: + return "NN_PLUSEQ"; + case NN_STAREQ: + return "NN_STAREQ"; + case NN_SLASHEQ: + return "NN_SLASHEQ"; + case NN_CARETEQ: + return "NN_CARETEQ"; + case NN_PERCENTEQ: + return "NN_PERCENTEQ"; + case NN_DOTDOT: + return "NN_DOTDOT"; + case NN_DOTDOTDOT: + return "NN_DOTDOTDOT"; + case NN_MOD_SEP: + return "NN_MOD_SEP"; + case NN_RARROW: + return "NN_RARROW"; + case NN_FAT_ARROW: + return "NN_FAT_ARROW"; + case NN_LIT_BYTE: + return "NN_LIT_BYTE"; + case NN_LIT_CHAR: + return "NN_LIT_CHAR"; + case NN_LIT_INTEGER: + return "NN_LIT_INTEGER"; + case NN_LIT_FLOAT: + return "NN_LIT_FLOAT"; + case NN_LIT_STR: + return "NN_LIT_STR"; + case NN_LIT_STR_RAW: + return "NN_LIT_STR_RAW"; + case NN_LIT_BYTE_STR: + return "NN_LIT_BYTE_STR"; + case NN_LIT_BYTE_STR_RAW: + return "NN_LIT_BYTE_STR_RAW"; + case NN_IDENT: + return "NN_IDENT"; + case NN_UNDERSCORE: + return "NN_UNDERSCORE"; + case NN_LIFETIME: + return "NN_LIFETIME"; + case NN_SELF: + return "NN_SELF"; + case NN_STATIC: + return "NN_STATIC"; + case NN_ABSTRACT: + return "NN_ABSTRACT"; + case NN_ALIGNOF: + return "NN_ALIGNOF"; + case NN_AS: + return "NN_AS"; + case NN_BECOME: + return "NN_BECOME"; + case NN_BREAK: + return "NN_BREAK"; + case NN_CATCH: + return "NN_CATCH"; + case NN_CRATE: + return "NN_CRATE"; + case NN_DEFAULT: + return "NN_DEFAULT"; + case NN_DO: + return "NN_DO"; + case NN_ELSE: + return "NN_ELSE"; + case NN_ENUM: + return "NN_ENUM"; + case NN_EXTERN: + return "NN_EXTERN"; + case NN_XFALSE: + return "NN_XFALSE"; + case NN_FINAL: + return "NN_FINAL"; + case NN_FN: + return "NN_FN"; + case NN_FOR: + return "NN_FOR"; + case NN_IF: + return "NN_IF"; + case NN_IMPL: + return "NN_IMPL"; + case NN_IN: + return "NN_IN"; + case NN_LET: + return "NN_LET"; + case NN_LOOP: + return "NN_LOOP"; + case NN_MACRO: + return "NN_MACRO"; + case NN_MATCH: + return "NN_MATCH"; + case NN_MOD: + return "NN_MOD"; + case NN_MOVE: + return "NN_MOVE"; + case NN_MUT: + return "NN_MUT"; + case NN_OFFSETOF: + return "NN_OFFSETOF"; + case NN_OVERRIDE: + return "NN_OVERRIDE"; + case NN_PRIV: + return "NN_PRIV"; + case NN_PUB: + return "NN_PUB"; + case NN_PURE: + return "NN_PURE"; + case NN_REF: + return "NN_REF"; + case NN_RETURN: + return "NN_RETURN"; + case NN_STRUCT: + return "NN_STRUCT"; + case NN_SIZEOF: + return "NN_SIZEOF"; + case NN_SUPER: + return "NN_SUPER"; + case NN_XTRUE: + return "NN_XTRUE"; + case NN_TRAIT: + return "NN_TRAIT"; + case NN_TYPE: + return "NN_TYPE"; + case NN_UNION: + return "NN_UNION"; + case NN_UNSAFE: + return "NN_UNSAFE"; + case NN_UNSIZED: + return "NN_UNSIZED"; + case NN_USE: + return "NN_USE"; + case NN_VIRTUAL: + return "NN_VIRTUAL"; + case NN_WHILE: + return "NN_WHILE"; + case NN_YIELD: + return "NN_YIELD"; + case NN_CONTINUE: + return "NN_CONTINUE"; + case NN_PROC: + return "NN_PROC"; + case NN_BOX: + return "NN_BOX"; + case NN_CONST: + return "NN_CONST"; + case NN_WHERE: + return "NN_WHERE"; + case NN_TYPEOF: + return "NN_TYPEOF"; + case NN_INNER_DOC_COMMENT: + return "NN_INNER_DOC_COMMENT"; + case NN_OUTER_DOC_COMMENT: + return "NN_OUTER_DOC_COMMENT"; + case NN_SHEBANG: + return "NN_SHEBANG"; + case NN_STATIC_LIFETIME: + return "NN_STATIC_LIFETIME"; + case NN_SEMI_COLON: + return "NN_SEMI_COLON"; + case NN_COMMA: + return "NN_COMMA"; + case NN_SINGLE_DOT: + return "NN_SINGLE_DOT"; + case NN_AT: + return "NN_AT"; + case NN_HASH: + return "NN_HASH"; + case NN_TILDA: + return "NN_TILDA"; + case NN_COLON: + return "NN_COLON"; + case NN_DOLLAR: + return "NN_DOLLAR"; + case NN_EQUALS: + return "NN_EQUALS"; + case NN_QUESTION: + return "NN_QUESTION"; + case NN_EXCLAIM: + return "NN_EXCLAIM"; + case NN_LESS_THAN: + return "NN_LESS_THAN"; + case NN_GREATER_THAN: + return "NN_GREATER_THAN"; + case NN_MINUS: + return "NN_MINUS"; + case NN_AMPERSAND: + return "NN_AMPERSAND"; + case NN_PIPE: + return "NN_PIPE"; + case NN_PLUS: + return "NN_PLUS"; + case NN_MULT: + return "NN_MULT"; + case NN_DIVIDE: + return "NN_DIVIDE"; + case NN_HAT: + return "NN_HAT"; + case NN_PERCENTAGE: + return "NN_PERCENTAGE"; + case NN_GLOBAL: + return "NN_GLOBAL"; + case NN_stmts: + return "NN_stmts"; + case NN_BiOr: + return "NN_BiOr"; + case NN_BiAnd: + return "NN_BiAnd"; + case NN_BiEq: + return "NN_BiEq"; + case NN_BiNe: + return "NN_BiNe"; + case NN_BiLt: + return "NN_BiLt"; + case NN_BiGt: + return "NN_BiGt"; + case NN_BiLe: + return "NN_BiLe"; + case NN_BiGe: + return "NN_BiGe"; + case NN_BiBitOr: + return "NN_BiBitOr"; + case NN_BiBitXor: + return "NN_BiBitXor"; + case NN_BiBitAnd: + return "NN_BiBitAnd"; + case NN_BiShl: + return "NN_BiShl"; + case NN_BiShr: + return "NN_BiShr"; + case NN_BiAdd: + return "NN_BiAdd"; + case NN_BiSub: + return "NN_BiSub"; + case NN_BiMul: + return "NN_BiMul"; + case NN_BiDiv: + return "NN_BiDiv"; + case NN_BiRem: + return "NN_BiRem"; + case NN_UnNeg: + return "NN_UnNeg"; + case NN_UnNot: + return "NN_UnNot"; + case NN_UnDeref: + return "NN_UnDeref"; + } + return NULL; +} diff --git a/gcc/rust/rustfrontend/node.h b/gcc/rust/rustfrontend/node.h new file mode 100644 index 0000000..7d83c2d --- /dev/null +++ b/gcc/rust/rustfrontend/node.h @@ -0,0 +1,378 @@ +#pragma once + +#include <string> + +typedef enum { + NN_ViewItemExternFn, + NN_TyParam, + NN_DeclLocal, + NN_DocComment, + NN_WherePredicate, + NN_ExprAddrOf, + NN_TypeMethod, + NN_crate, + NN_DefaultFieldInit, + NN_ExprBinary, + NN_ExprAssignBitAnd, + NN_TyFnDecl, + NN_Public, + NN_Pats, + NN_ViewPathSimple, + NN_TyParams, + NN_ExprIf, + NN_Args, + NN_MetaItems, + NN_AttrsAndVis, + NN_LitInteger, + NN_ExprPath, + NN_ExprField, + NN_TyDefault, + NN_ExprAssignAdd, + NN_ExprYield, + NN_ImplItems, + NN_TyRptr, + NN_TySum, + NN_ExprAssignDiv, + NN_PatTup, + NN_ViewPath, + NN_ItemImplNeg, + NN_ExprWhile, + NN_WherePredicates, + NN_FieldInits, + NN_PatQualifiedPath, + NN_ExprMatch, + NN_Binding, + NN_ExprAssignBitOr, + NN_ItemImpl, + NN_ForeignItem, + NN_Arg, + NN_Bindings, + NN_PatWild, + NN_ExprTypeAscr, + NN_ExprBreak, + NN_ExprIfLet, + NN_Inherited, + NN_TyPtr, + NN_Arms, + NN_LitByteStr, + NN_ItemConst, + NN_ItemImplDefault, + NN_VecRepeat, + NN_TTTok, + NN_RetTy, + NN_TySumsAndBindings, + NN_MetaList, + NN_ExprQualifiedPath, + NN_ExprAssignBitXor, + NN_Macro, + NN_Super, + NN_ForeignFn, + NN_SelfLower, + NN_ExprAssign, + NN_OuterAttrs, + NN_ItemMacro, + NN_ForeignItems, + NN_Items, + NN_TraitMacroItem, + NN_ExprWhileLet, + NN_BindByRef, + NN_ImplType, + NN_ExprLoop, + NN_SelfRegion, + NN_TyTup, + NN_PatUnit, + NN_ForInType, + NN_FnDecl, + NN_PatUniq, + NN_UnsafeBlock, + NN_TyQualifiedPath, + NN_TyBox, + NN_PatEnum, + NN_TyClosure, + NN_ForSized, + NN_ExprAssignSub, + NN_GenericValues, + NN_TyPath, + NN_PatIdent, + NN_ConstDefault, + NN_WhereClause, + NN_MutImmutable, + NN_TyMacro, + NN_ExprTupleIndex, + NN_ImplMacroItem, + NN_ExprTry, + NN_ExprCast, + NN_Provided, + NN_PatRegion, + NN_ExprAssignShl, + NN_static_lifetime, + NN_MetaNameValue, + NN_ExprStruct, + NN_ExprAssignShr, + NN_FieldInit, + NN_Generics, + NN_ExprForLoop, + NN_Method, + NN_TySums, + NN_ExprVec, + NN_LitChar, + NN_PatFields, + NN_PatMac, + NN_InnerAttr, + NN_ViewPathGlob, + NN_ItemStatic, + NN_PatRange, + NN_LitBool, + NN_IdentsOrSelf, + NN_ItemFn, + NN_ExprCall, + NN_Default, + NN_trait, + NN_Required, + NN_TyInfer, + NN_ConstTraitItem, + NN_SelfStatic, + NN_ExprAssignRem, + NN_PatLit, + NN_PatField, + NN_TyNil, + NN_EnumDef, + NN_TypeTraitItem, + NN_PatVec, + NN_ident, + NN_MetaWord, + NN_Lifetimes, + NN_LitStr, + NN_SelfPath, + NN_bounds, + NN_EnumDefs, + NN_ltbounds, + NN_ViewItemUse, + NN_ItemImplDefaultNeg, + NN_PatVecElts, + NN_TokenTrees, + NN_semicolon, + NN_ItemMod, + NN_ExprUnary, + NN_ExprBlock, + NN_ItemUnsafeFn, + NN_EnumArgs, + NN_ViewItemExternCrate, + NN_lifetime, + NN_StructFields, + NN_ExprRet, + NN_ExprAssignMul, + NN_ItemStruct, + NN_LitFloat, + NN_TyTypeof, + NN_exprs, + NN_InnerAttrs, + NN_PolyBound, + NN_TyVec, + NN_ArmNonblock, + NN_ViewPathList, + NN_TTDelim, + NN_ItemForeignMod, + NN_PatTupElts, + NN_ExprMac, + NN_ExprParen, + NN_StaticItem, + NN_ItemTrait, + NN_ExprRange, + NN_ItemUnion, + NN_ExprIndex, + NN_ArmBlock, + NN_DefaultUnsafe, + NN_PatStruct, + NN_MutMutable, + NN_ExprLit, + NN_TyFixedLengthVec, + NN_ImplConst, + NN_InferrableParams, + NN_Item, + NN_TraitItems, + NN_MacroExpr, + NN_LitByte, + NN_InferrableParam, + NN_BindByValue, + NN_StructField, + NN_Unsafe, + NN_ViewPathListEmpty, + NN_ExprFnBlock, + NN_ExprAgain, + NN_components, + NN_ItemEnum, + NN_ExprBox, + NN_ItemTy, + NN_NONE, + NN_SHL, + NN_SHR, + NN_LE, + NN_EQEQ, + NN_NE, + NN_GE, + NN_ANDAND, + NN_OROR, + NN_LARROW, + NN_SHLEQ, + NN_SHREQ, + NN_MINUSEQ, + NN_ANDEQ, + NN_OREQ, + NN_PLUSEQ, + NN_STAREQ, + NN_SLASHEQ, + NN_CARETEQ, + NN_PERCENTEQ, + NN_DOTDOT, + NN_DOTDOTDOT, + NN_MOD_SEP, + NN_RARROW, + NN_FAT_ARROW, + NN_LIT_BYTE, + NN_LIT_CHAR, + NN_LIT_INTEGER, + NN_LIT_FLOAT, + NN_LIT_STR, + NN_LIT_STR_RAW, + NN_LIT_BYTE_STR, + NN_LIT_BYTE_STR_RAW, + NN_IDENT, + NN_UNDERSCORE, + NN_LIFETIME, + NN_SELF, + NN_STATIC, + NN_ABSTRACT, + NN_ALIGNOF, + NN_AS, + NN_BECOME, + NN_BREAK, + NN_CATCH, + NN_CRATE, + NN_DEFAULT, + NN_DO, + NN_ELSE, + NN_ENUM, + NN_EXTERN, + NN_XFALSE, + NN_FINAL, + NN_FN, + NN_FOR, + NN_IF, + NN_IMPL, + NN_IN, + NN_LET, + NN_LOOP, + NN_MACRO, + NN_MATCH, + NN_MOD, + NN_MOVE, + NN_MUT, + NN_OFFSETOF, + NN_OVERRIDE, + NN_PRIV, + NN_PUB, + NN_PURE, + NN_REF, + NN_RETURN, + NN_STRUCT, + NN_SIZEOF, + NN_SUPER, + NN_XTRUE, + NN_TRAIT, + NN_TYPE, + NN_UNION, + NN_UNSAFE, + NN_UNSIZED, + NN_USE, + NN_VIRTUAL, + NN_WHILE, + NN_YIELD, + NN_CONTINUE, + NN_PROC, + NN_BOX, + NN_CONST, + NN_WHERE, + NN_TYPEOF, + NN_INNER_DOC_COMMENT, + NN_OUTER_DOC_COMMENT, + NN_SHEBANG, + NN_STATIC_LIFETIME, + NN_SEMI_COLON, + NN_COMMA, + NN_SINGLE_DOT, + NN_AT, + NN_HASH, + NN_TILDA, + NN_COLON, + NN_DOLLAR, + NN_EQUALS, + NN_QUESTION, + NN_EXCLAIM, + NN_LESS_THAN, + NN_GREATER_THAN, + NN_MINUS, + NN_AMPERSAND, + NN_PIPE, + NN_PLUS, + NN_MULT, + NN_DIVIDE, + NN_HAT, + NN_PERCENTAGE, + NN_GLOBAL, + NN_stmts, + + NN_BiOr, + NN_BiAnd, + NN_BiEq, + NN_BiNe, + NN_BiLt, + NN_BiGt, + NN_BiLe, + NN_BiGe, + NN_BiBitOr, + NN_BiBitXor, + NN_BiBitAnd, + NN_BiShl, + NN_BiShr, + NN_BiAdd, + NN_BiSub, + NN_BiMul, + NN_BiDiv, + NN_BiRem, + NN_UnNeg, + NN_UnNot, + NN_UnDeref +} ast_opcode_t; + +typedef struct node { + ast_opcode_t op; + char* value; + + struct node* next; + struct node* prev; + + int n_elems; + struct node** elems; +} *Node; + +#define NODE_TYPE(x_) x_->op +#define NODE_TYPE_STR(x_) get_ast_op_string(x_->op) +#define NODE_TYPE_VALUE_STR(x_) (n->value == NULL ? "NULL" : n->value) +#define NODE_CHAIN(x_) (x_->next) +#define NODE_RCHAIN(x_) (x_->prev) + +extern Node mk_node(ast_opcode_t, int n, ...); +extern Node mk_node_value(ast_opcode_t, char*, int n, ...); +extern Node mk_atom(ast_opcode_t, const char *value); +extern Node mk_empty_atom(ast_opcode_t); +extern Node mk_none(); +extern Node ext_node(struct node *nd, int n, ...); +extern void print_node(Node n, int depth); +extern const char* get_ast_op_string(ast_opcode_t); + +extern void push_back(char); +extern void parser_init(int verbose); + +extern int n_nodes; +extern node* nodes; diff --git a/gcc/rust/rustfrontend/operator.h b/gcc/rust/rustfrontend/operator.h new file mode 100644 index 0000000..2ada147 --- /dev/null +++ b/gcc/rust/rustfrontend/operator.h @@ -0,0 +1,55 @@ +#pragma once + +enum Operator +{ + OPERATOR_INVALID, + OPERATOR_OROR, // || + OPERATOR_ANDAND, // && + OPERATOR_EQEQ, // == + OPERATOR_NOTEQ, // != + OPERATOR_LT, // < + OPERATOR_LE, // <= + OPERATOR_GT, // > + OPERATOR_GE, // >= + OPERATOR_PLUS, // + + OPERATOR_MINUS, // - + OPERATOR_OR, // | + OPERATOR_XOR, // ^ + OPERATOR_MULT, // * + OPERATOR_DIV, // / + OPERATOR_MOD, // % + OPERATOR_LSHIFT, // << + OPERATOR_RSHIFT, // >> + OPERATOR_AND, // & + OPERATOR_NOT, // ! + OPERATOR_BITCLEAR, // &^ + OPERATOR_CHANOP, // <- + + OPERATOR_EQ, // = + OPERATOR_PLUSEQ, // += + OPERATOR_MINUSEQ, // -= + OPERATOR_OREQ, // |= + OPERATOR_XOREQ, // ^= + OPERATOR_MULTEQ, // *= + OPERATOR_DIVEQ, // /= + OPERATOR_MODEQ, // %= + OPERATOR_LSHIFTEQ, // <<= + OPERATOR_RSHIFTEQ, // >>= + OPERATOR_ANDEQ, // &= + OPERATOR_BITCLEAREQ, // &^= + OPERATOR_PLUSPLUS, // ++ + OPERATOR_MINUSMINUS, // -- + + OPERATOR_COLON, // : + OPERATOR_COLONEQ, // := + OPERATOR_SEMICOLON, // ; + OPERATOR_DOT, // . + OPERATOR_ELLIPSIS, // ... + OPERATOR_COMMA, // , + OPERATOR_LPAREN, // ( + OPERATOR_RPAREN, // ) + OPERATOR_LCURLY, // { + OPERATOR_RCURLY, // } + OPERATOR_LSQUARE, // [ + OPERATOR_RSQUARE // ] +}; diff --git a/gcc/rust/rustfrontend/rs-lexer.l b/gcc/rust/rustfrontend/rs-lexer.l new file mode 100644 index 0000000..76bbed3 --- /dev/null +++ b/gcc/rust/rustfrontend/rs-lexer.l @@ -0,0 +1,350 @@ +%{ +#include "rs-parser.h" + +static int num_hashes; +static int end_hashes; +static int saw_non_hash; +%} + +%option noyywrap +%option stack +%option yylineno + +%x str +%x rawstr +%x rawstr_esc_begin +%x rawstr_esc_body +%x rawstr_esc_end +%x byte +%x bytestr +%x rawbytestr +%x rawbytestr_nohash +%x pound +%x shebang_or_attr +%x ltorchar +%x linecomment +%x doc_line +%x blockcomment +%x doc_block +%x suffix + +ident [a-zA-Z\x80-\xff_][a-zA-Z0-9\x80-\xff_]* + +%% + +<suffix>{ident} { BEGIN(INITIAL); } +<suffix>(.|\n) { yyless(0); BEGIN(INITIAL); } + +[ \n\t\r] { } + +\xef\xbb\xbf { + // UTF-8 byte order mark (BOM), ignore if in line 1, error otherwise + if (yyget_lineno() != 1) { + return -1; + } +} + +\/\/(\/|\!) { BEGIN(doc_line); yymore(); } +<doc_line>\n { BEGIN(INITIAL); + yyleng--; + yytext[yyleng] = 0; + return ((yytext[2] == '!') ? INNER_DOC_COMMENT : OUTER_DOC_COMMENT); + } +<doc_line>[^\n]* { yymore(); } + +\/\/|\/\/\/\/ { BEGIN(linecomment); } +<linecomment>\n { BEGIN(INITIAL); } +<linecomment>[^\n]* { } + +\/\*(\*|\!)[^*] { yy_push_state(INITIAL); yy_push_state(doc_block); yymore(); } +<doc_block>\/\* { yy_push_state(doc_block); yymore(); } +<doc_block>\*\/ { + yy_pop_state(); + if (yy_top_state() == doc_block) { + yymore(); + } else { + return ((yytext[2] == '!') ? INNER_DOC_COMMENT : OUTER_DOC_COMMENT); + } +} +<doc_block>(.|\n) { yymore(); } + +\/\* { yy_push_state(blockcomment); } +<blockcomment>\/\* { yy_push_state(blockcomment); } +<blockcomment>\*\/ { yy_pop_state(); } +<blockcomment>(.|\n) { } + +_ { return UNDERSCORE; } +abstract { return ABSTRACT; } +alignof { return ALIGNOF; } +as { return AS; } +become { return BECOME; } +box { return BOX; } +break { return BREAK; } +catch { return CATCH; } +const { return CONST; } +continue { return CONTINUE; } +crate { return CRATE; } +default { return DEFAULT; } +do { return DO; } +else { return ELSE; } +enum { return ENUM; } +extern { return EXTERN; } +false { return XFALSE; } +final { return FINAL; } +fn { return FN; } +for { return FOR; } +if { return IF; } +impl { return IMPL; } +in { return IN; } +let { return LET; } +loop { return LOOP; } +macro { return MACRO; } +match { return MATCH; } +mod { return MOD; } +move { return MOVE; } +mut { return MUT; } +offsetof { return OFFSETOF; } +override { return OVERRIDE; } +priv { return PRIV; } +proc { return PROC; } +pure { return PURE; } +pub { return PUB; } +ref { return REF; } +return { return RETURN; } +self { return SELF; } +sizeof { return SIZEOF; } +static { return STATIC; } +struct { return STRUCT; } +super { return SUPER; } +trait { return TRAIT; } +true { return XTRUE; } +type { return TYPE; } +typeof { return TYPEOF; } +union { return UNION; } +unsafe { return UNSAFE; } +unsized { return UNSIZED; } +use { return USE; } +virtual { return VIRTUAL; } +where { return WHERE; } +while { return WHILE; } +yield { return YIELD; } + +{ident} { return IDENT; } + +0x[0-9a-fA-F_]+ { BEGIN(suffix); return LIT_INTEGER; } +0o[0-7_]+ { BEGIN(suffix); return LIT_INTEGER; } +0b[01_]+ { BEGIN(suffix); return LIT_INTEGER; } +[0-9][0-9_]* { BEGIN(suffix); return LIT_INTEGER; } +[0-9][0-9_]*\.(\.|[a-zA-Z]) { yyless(yyleng - 2); BEGIN(suffix); return LIT_INTEGER; } + +[0-9][0-9_]*\.[0-9_]*([eE][-\+]?[0-9_]+)? { BEGIN(suffix); return LIT_FLOAT; } +[0-9][0-9_]*(\.[0-9_]*)?[eE][-\+]?[0-9_]+ { BEGIN(suffix); return LIT_FLOAT; } + +; { return ';'; } +, { return ','; } +\.\.\. { return DOTDOTDOT; } +\.\. { return DOTDOT; } +\. { return '.'; } +\( { return '('; } +\) { return ')'; } +\{ { return '{'; } +\} { return '}'; } +\[ { return '['; } +\] { return ']'; } +@ { return '@'; } +# { BEGIN(pound); yymore(); } +<pound>\! { BEGIN(shebang_or_attr); yymore(); } +<shebang_or_attr>\[ { + BEGIN(INITIAL); + yyless(2); + return SHEBANG; +} +<shebang_or_attr>[^\[\n]*\n { + // Since the \n was eaten as part of the token, yylineno will have + // been incremented to the value 2 if the shebang was on the first + // line. This yyless undoes that, setting yylineno back to 1. + yyless(yyleng - 1); + if (yyget_lineno() == 1) { + BEGIN(INITIAL); + return SHEBANG_LINE; + } else { + BEGIN(INITIAL); + yyless(2); + return SHEBANG; + } +} +<pound>. { BEGIN(INITIAL); yyless(1); return '#'; } + +\~ { return '~'; } +:: { return MOD_SEP; } +: { return ':'; } +\$ { return '$'; } +\? { return '?'; } + +== { return EQEQ; } +=> { return FAT_ARROW; } += { return '='; } +\!= { return NE; } +\! { return '!'; } +\<= { return LE; } +\<\< { return SHL; } +\<\<= { return SHLEQ; } +\< { return '<'; } +\>= { return GE; } +\>\> { return SHR; } +\>\>= { return SHREQ; } +\> { return '>'; } + +\x27 { BEGIN(ltorchar); yymore(); } +<ltorchar>static { BEGIN(INITIAL); return STATIC_LIFETIME; } +<ltorchar>{ident} { BEGIN(INITIAL); return LIFETIME; } +<ltorchar>\\[nrt\\\x27\x220]\x27 { BEGIN(suffix); return LIT_CHAR; } +<ltorchar>\\x[0-9a-fA-F]{2}\x27 { BEGIN(suffix); return LIT_CHAR; } +<ltorchar>\\u\{([0-9a-fA-F]_*){1,6}\}\x27 { BEGIN(suffix); return LIT_CHAR; } +<ltorchar>.\x27 { BEGIN(suffix); return LIT_CHAR; } +<ltorchar>[\x80-\xff]{2,4}\x27 { BEGIN(suffix); return LIT_CHAR; } +<ltorchar><<EOF>> { BEGIN(INITIAL); return -1; } + +b\x22 { BEGIN(bytestr); yymore(); } +<bytestr>\x22 { BEGIN(suffix); return LIT_BYTE_STR; } + +<bytestr><<EOF>> { return -1; } +<bytestr>\\[n\nrt\\\x27\x220] { yymore(); } +<bytestr>\\x[0-9a-fA-F]{2} { yymore(); } +<bytestr>\\u\{([0-9a-fA-F]_*){1,6}\} { yymore(); } +<bytestr>\\[^n\nrt\\\x27\x220] { return -1; } +<bytestr>(.|\n) { yymore(); } + +br\x22 { BEGIN(rawbytestr_nohash); yymore(); } +<rawbytestr_nohash>\x22 { BEGIN(suffix); return LIT_BYTE_STR_RAW; } +<rawbytestr_nohash>(.|\n) { yymore(); } +<rawbytestr_nohash><<EOF>> { return -1; } + +br/# { + BEGIN(rawbytestr); + yymore(); + num_hashes = 0; + saw_non_hash = 0; + end_hashes = 0; +} +<rawbytestr># { + if (!saw_non_hash) { + num_hashes++; + } else if (end_hashes != 0) { + end_hashes++; + if (end_hashes == num_hashes) { + BEGIN(INITIAL); + return LIT_BYTE_STR_RAW; + } + } + yymore(); +} +<rawbytestr>\x22# { + end_hashes = 1; + if (end_hashes == num_hashes) { + BEGIN(INITIAL); + return LIT_BYTE_STR_RAW; + } + yymore(); +} +<rawbytestr>(.|\n) { + if (!saw_non_hash) { + saw_non_hash = 1; + } + if (end_hashes != 0) { + end_hashes = 0; + } + yymore(); +} +<rawbytestr><<EOF>> { return -1; } + +b\x27 { BEGIN(byte); yymore(); } +<byte>\\[nrt\\\x27\x220]\x27 { BEGIN(INITIAL); return LIT_BYTE; } +<byte>\\x[0-9a-fA-F]{2}\x27 { BEGIN(INITIAL); return LIT_BYTE; } +<byte>\\u([0-9a-fA-F]_*){4}\x27 { BEGIN(INITIAL); return LIT_BYTE; } +<byte>\\U([0-9a-fA-F]_*){8}\x27 { BEGIN(INITIAL); return LIT_BYTE; } +<byte>.\x27 { BEGIN(INITIAL); return LIT_BYTE; } +<byte><<EOF>> { BEGIN(INITIAL); return -1; } + +r\x22 { BEGIN(rawstr); yymore(); } +<rawstr>\x22 { BEGIN(suffix); return LIT_STR_RAW; } +<rawstr>(.|\n) { yymore(); } +<rawstr><<EOF>> { return -1; } + +r/# { + BEGIN(rawstr_esc_begin); + yymore(); + num_hashes = 0; + saw_non_hash = 0; + end_hashes = 0; +} + +<rawstr_esc_begin># { + num_hashes++; + yymore(); +} +<rawstr_esc_begin>\x22 { + BEGIN(rawstr_esc_body); + yymore(); +} +<rawstr_esc_begin>(.|\n) { return -1; } + +<rawstr_esc_body>\x22/# { + BEGIN(rawstr_esc_end); + yymore(); + } +<rawstr_esc_body>(.|\n) { + yymore(); + } + +<rawstr_esc_end># { + end_hashes++; + if (end_hashes == num_hashes) { + BEGIN(INITIAL); + return LIT_STR_RAW; + } + yymore(); + } +<rawstr_esc_end>[^#] { + end_hashes = 0; + BEGIN(rawstr_esc_body); + yymore(); + } + +<rawstr_esc_begin,rawstr_esc_body,rawstr_esc_end><<EOF>> { return -1; } + +\x22 { BEGIN(str); yymore(); } +<str>\x22 { BEGIN(suffix); return LIT_STR; } + +<str><<EOF>> { return -1; } +<str>\\[n\nr\rt\\\x27\x220] { yymore(); } +<str>\\x[0-9a-fA-F]{2} { yymore(); } +<str>\\u\{([0-9a-fA-F]_*){1,6}\} { yymore(); } +<str>\\[^n\nrt\\\x27\x220] { return -1; } +<str>(.|\n) { yymore(); } + +\<- { return LARROW; } +-\> { return RARROW; } +- { return '-'; } +-= { return MINUSEQ; } +&& { return ANDAND; } +& { return '&'; } +&= { return ANDEQ; } +\|\| { return OROR; } +\| { return '|'; } +\|= { return OREQ; } +\+ { return '+'; } +\+= { return PLUSEQ; } +\* { return '*'; } +\*= { return STAREQ; } +\/ { return '/'; } +\/= { return SLASHEQ; } +\^ { return '^'; } +\^= { return CARETEQ; } +% { return '%'; } +%= { return PERCENTEQ; } + +<<EOF>> { return 0; } + +%% + diff --git a/gcc/rust/rustfrontend/rs-parser.y b/gcc/rust/rustfrontend/rs-parser.y new file mode 100644 index 0000000..17fff37 --- /dev/null +++ b/gcc/rust/rustfrontend/rs-parser.y @@ -0,0 +1,1977 @@ +%{ +#include "rust-system.h" +#include "node.h" + +#define YYERROR_VERBOSE +#define YYSTYPE Node + +extern int yylineno; +extern char *yytext; +extern int yylex (void); +extern void yyerror (const char *); +%} + +// borrowed/stolen from rust-lang repo since removed in PR: +// https://github.com/rust-lang/rust/pull/64896/commits/96c8049b201fa0b87b8074e139921fbc33a2db1d + +%debug + +%token SHL +%token SHR +%token LE +%token EQEQ +%token NE +%token GE +%token ANDAND +%token OROR +%token SHLEQ +%token SHREQ +%token MINUSEQ +%token ANDEQ +%token OREQ +%token PLUSEQ +%token STAREQ +%token SLASHEQ +%token CARETEQ +%token PERCENTEQ +%token DOTDOT +%token DOTDOTDOT +%token MOD_SEP +%token RARROW +%token LARROW +%token FAT_ARROW +%token LIT_BYTE +%token LIT_CHAR +%token LIT_INTEGER +%token LIT_FLOAT +%token LIT_STR +%token LIT_STR_RAW +%token LIT_BYTE_STR +%token LIT_BYTE_STR_RAW +%token IDENT +%token UNDERSCORE +%token LIFETIME + +// keywords +%token SELF +%token STATIC +%token ABSTRACT +%token ALIGNOF +%token AS +%token BECOME +%token BREAK +%token CATCH +%token CRATE +%token DO +%token ELSE +%token ENUM +%token EXTERN +%token XFALSE +%token FINAL +%token FN +%token FOR +%token IF +%token IMPL +%token IN +%token LET +%token LOOP +%token MACRO +%token MATCH +%token MOD +%token MOVE +%token MUT +%token OFFSETOF +%token OVERRIDE +%token PRIV +%token PUB +%token PURE +%token REF +%token RETURN +%token SIZEOF +%token STRUCT +%token SUPER +%token UNION +%token UNSIZED +%token XTRUE +%token TRAIT +%token TYPE +%token UNSAFE +%token VIRTUAL +%token YIELD +%token DEFAULT +%token USE +%token WHILE +%token CONTINUE +%token PROC +%token BOX +%token CONST +%token WHERE +%token TYPEOF +%token INNER_DOC_COMMENT +%token OUTER_DOC_COMMENT + +%token SHEBANG +%token SHEBANG_LINE +%token STATIC_LIFETIME + + /* + Quoting from the Bison manual: + "Finally, the resolution of conflicts works by comparing the precedence + of the rule being considered with that of the lookahead token. If the + token's precedence is higher, the choice is to shift. If the rule's + precedence is higher, the choice is to reduce. If they have equal + precedence, the choice is made based on the associativity of that + precedence level. The verbose output file made by ‘-v’ (see Invoking + Bison) says how each conflict was resolved" + */ + +// We expect no shift/reduce or reduce/reduce conflicts in this grammar; +// all potential ambiguities are scrutinized and eliminated manually. +%expect 0 + +// fake-precedence symbol to cause '|' bars in lambda context to parse +// at low precedence, permit things like |x| foo = bar, where '=' is +// otherwise lower-precedence than '|'. Also used for proc() to cause +// things like proc() a + b to parse as proc() { a + b }. +%precedence LAMBDA + +%precedence SELF + +// MUT should be lower precedence than IDENT so that in the pat rule, +// "& MUT pat" has higher precedence than "binding_mode ident [@ pat]" +%precedence MUT + +// IDENT needs to be lower than '{' so that 'foo {' is shifted when +// trying to decide if we've got a struct-construction expr (esp. in +// contexts like 'if foo { .') +// +// IDENT also needs to be lower precedence than '<' so that '<' in +// 'foo:bar . <' is shifted (in a trait reference occurring in a +// bounds list), parsing as foo:(bar<baz>) rather than (foo:bar)<baz>. +%precedence IDENT + // Put the weak keywords that can be used as idents here as well +%precedence CATCH +%precedence DEFAULT +%precedence UNION + +// A couple fake-precedence symbols to use in rules associated with + +// and < in trailing type contexts. These come up when you have a type +// in the RHS of operator-AS, such as "foo as bar<baz>". The "<" there +// has to be shifted so the parser keeps trying to parse a type, even +// though it might well consider reducing the type "bar" and then +// going on to "<" as a subsequent binop. The "+" case is with +// trailing type-bounds ("foo as bar:A+B"), for the same reason. +%precedence SHIFTPLUS +%precedence MOD_SEP +%precedence RARROW ':' +// In where clauses, "for" should have greater precedence when used as +// a higher ranked constraint than when used as the beginning of a +// for_in_type (which is a ty) +%precedence FORTYPE +%precedence FOR +// Binops & unops, and their precedences +%precedence '?' +%precedence BOX +%nonassoc DOTDOT +// RETURN needs to be lower-precedence than tokens that start +// prefix_exprs +%precedence RETURN YIELD +%right '=' SHLEQ SHREQ MINUSEQ ANDEQ OREQ PLUSEQ STAREQ SLASHEQ CARETEQ PERCENTEQ +%right LARROW +%left OROR +%left ANDAND +%left EQEQ NE +%left '<' '>' LE GE +%left '|' +%left '^' +%left '&' +%left SHL SHR +%left '+' '-' +%precedence AS +%left '*' '/' '%' +%precedence '!' + +%precedence '{' '[' '(' '.' + +%precedence RANGE + +%start crate + +%% + +/////////////////////////////////////////////////////////////////////// +// Part 1: Items and attributes +//////////////////////////////////////////////////////////////////////// + +crate +: maybe_shebang inner_attrs maybe_mod_items { mk_node(NN_crate, 2, $2, $3); } +| maybe_shebang maybe_mod_items { mk_node(NN_crate, 1, $2); } +; + +maybe_shebang +: SHEBANG_LINE +| %empty +; + +maybe_inner_attrs +: inner_attrs +| %empty { $$ = mk_none(); } +; + +inner_attrs +: inner_attr { $$ = mk_node(NN_InnerAttrs, 1, $1); } +| inner_attrs inner_attr { $$ = ext_node($1, 1, $2); } +; + +inner_attr +: SHEBANG '[' meta_item ']' { $$ = mk_node(NN_InnerAttr, 1, $3); } +| INNER_DOC_COMMENT { $$ = mk_node(NN_InnerAttr, 1, mk_atom(NN_INNER_DOC_COMMENT, yytext)); } +; + +maybe_outer_attrs +: outer_attrs +| %empty { $$ = mk_none(); } +; + +outer_attrs +: outer_attr { $$ = mk_node(NN_OuterAttrs, 1, $1); } +| outer_attrs outer_attr { $$ = ext_node($1, 1, $2); } +; + +outer_attr +: '#' '[' meta_item ']' { $$ = $3; } +| OUTER_DOC_COMMENT { $$ = mk_atom(NN_OUTER_DOC_COMMENT, yytext); } +; + +meta_item +: ident { $$ = mk_node(NN_MetaWord, 1, $1); } +| ident '=' lit { $$ = mk_node(NN_MetaNameValue, 2, $1, $3); } +| ident '(' meta_seq ')' { $$ = mk_node(NN_MetaList, 2, $1, $3); } +| ident '(' meta_seq ',' ')' { $$ = mk_node(NN_MetaList, 2, $1, $3); } +; + +meta_seq +: %empty { $$ = mk_none(); } +| meta_item { $$ = mk_node(NN_MetaItems, 1, $1); } +| meta_seq ',' meta_item { $$ = ext_node($1, 1, $3); } +; + +maybe_mod_items +: mod_items +| %empty { $$ = mk_none(); } +; + +mod_items +: mod_item { $$ = mk_node(NN_Items, 1, $1); } +| mod_items mod_item { $$ = ext_node($1, 1, $2); } +; + +attrs_and_vis +: maybe_outer_attrs visibility { $$ = mk_node(NN_AttrsAndVis, 2, $1, $2); } +; + +mod_item +: attrs_and_vis item { $$ = mk_node(NN_Item, 2, $1, $2); } +; + +// items that can appear outside of a fn block +item +: stmt_item +| item_macro +; + +// items that can appear in "stmts" +stmt_item +: item_static +| item_const +| item_type +| block_item +| view_item +; + +item_static +: STATIC ident ':' ty '=' expr ';' { $$ = mk_node(NN_ItemStatic, 3, $2, $4, $6); } +| STATIC MUT ident ':' ty '=' expr ';' { $$ = mk_node(NN_ItemStatic, 3, $3, $5, $7); } +; + +item_const +: CONST ident ':' ty '=' expr ';' { $$ = mk_node(NN_ItemConst, 3, $2, $4, $6); } +; + +item_macro +: path_expr '!' maybe_ident parens_delimited_token_trees ';' { $$ = mk_node(NN_ItemMacro, 3, $1, $3, $4); } +| path_expr '!' maybe_ident braces_delimited_token_trees { $$ = mk_node(NN_ItemMacro, 3, $1, $3, $4); } +| path_expr '!' maybe_ident brackets_delimited_token_trees ';'{ $$ = mk_node(NN_ItemMacro, 3, $1, $3, $4); } +; + +view_item +: use_item +| extern_fn_item +| EXTERN CRATE ident ';' { $$ = mk_node(NN_ViewItemExternCrate, 1, $3); } +| EXTERN CRATE ident AS ident ';' { $$ = mk_node(NN_ViewItemExternCrate, 2, $3, $5); } +; + +extern_fn_item +: EXTERN maybe_abi item_fn { $$ = mk_node(NN_ViewItemExternFn, 2, $2, $3); } +; + +use_item +: USE view_path ';' { $$ = mk_node(NN_ViewItemUse, 1, $2); } +; + +view_path +: path_no_types_allowed { $$ = mk_node(NN_ViewPathSimple, 1, $1); } +| path_no_types_allowed MOD_SEP '{' '}' { $$ = mk_node(NN_ViewPathList, 2, $1, mk_empty_atom(NN_ViewPathListEmpty)); } +| MOD_SEP '{' '}' { $$ = mk_node(NN_ViewPathList, 1, mk_empty_atom(NN_ViewPathListEmpty)); } +| path_no_types_allowed MOD_SEP '{' idents_or_self '}' { $$ = mk_node(NN_ViewPathList, 2, $1, $4); } +| MOD_SEP '{' idents_or_self '}' { $$ = mk_node(NN_ViewPathList, 1, $3); } +| path_no_types_allowed MOD_SEP '{' idents_or_self ',' '}' { $$ = mk_node(NN_ViewPathList, 2, $1, $4); } +| MOD_SEP '{' idents_or_self ',' '}' { $$ = mk_node(NN_ViewPathList, 1, $3); } +| path_no_types_allowed MOD_SEP '*' { $$ = mk_node(NN_ViewPathGlob, 1, $1); } +| MOD_SEP '*' { $$ = mk_empty_atom(NN_ViewPathGlob); } +| '*' { $$ = mk_empty_atom(NN_ViewPathGlob); } +| '{' '}' { $$ = mk_empty_atom(NN_ViewPathListEmpty); } +| '{' idents_or_self '}' { $$ = mk_node(NN_ViewPathList, 1, $2); } +| '{' idents_or_self ',' '}' { $$ = mk_node(NN_ViewPathList, 1, $2); } +| path_no_types_allowed AS ident { $$ = mk_node(NN_ViewPathSimple, 2, $1, $3); } +; + +block_item +: item_fn +| item_unsafe_fn +| item_mod +| item_foreign_mod { $$ = mk_node(NN_ItemForeignMod, 1, $1); } +| item_struct +| item_enum +| item_union +| item_trait +| item_impl +; + +maybe_ty_ascription +: ':' ty_sum { $$ = $2; } +| %empty { $$ = mk_none(); } +; + +maybe_init_expr +: '=' expr { $$ = $2; } +| %empty { $$ = mk_none(); } +; + +// structs +item_struct +: STRUCT ident generic_params maybe_where_clause struct_decl_args +{ + $$ = mk_node(NN_ItemStruct, 4, $2, $3, $4, $5); +} +| STRUCT ident generic_params struct_tuple_args maybe_where_clause ';' +{ + $$ = mk_node(NN_ItemStruct, 4, $2, $3, $4, $5); +} +| STRUCT ident generic_params maybe_where_clause ';' +{ + $$ = mk_node(NN_ItemStruct, 3, $2, $3, $4); +} +; + +struct_decl_args +: '{' struct_decl_fields '}' { $$ = $2; } +| '{' struct_decl_fields ',' '}' { $$ = $2; } +; + +struct_tuple_args +: '(' struct_tuple_fields ')' { $$ = $2; } +| '(' struct_tuple_fields ',' ')' { $$ = $2; } +; + +struct_decl_fields +: struct_decl_field { $$ = mk_node(NN_StructFields, 1, $1); } +| struct_decl_fields ',' struct_decl_field { $$ = ext_node($1, 1, $3); } +| %empty { $$ = mk_none(); } +; + +struct_decl_field +: attrs_and_vis ident ':' ty_sum { $$ = mk_node(NN_StructField, 3, $1, $2, $4); } +; + +struct_tuple_fields +: struct_tuple_field { $$ = mk_node(NN_StructFields, 1, $1); } +| struct_tuple_fields ',' struct_tuple_field { $$ = ext_node($1, 1, $3); } +| %empty { $$ = mk_none(); } +; + +struct_tuple_field +: attrs_and_vis ty_sum { $$ = mk_node(NN_StructField, 2, $1, $2); } +; + +// enums +item_enum +: ENUM ident generic_params maybe_where_clause '{' enum_defs '}' { $$ = mk_node(NN_ItemEnum, 0); } +| ENUM ident generic_params maybe_where_clause '{' enum_defs ',' '}' { $$ = mk_node(NN_ItemEnum, 0); } +; + +enum_defs +: enum_def { $$ = mk_node(NN_EnumDefs, 1, $1); } +| enum_defs ',' enum_def { $$ = ext_node($1, 1, $3); } +| %empty { $$ = mk_none(); } +; + +enum_def +: attrs_and_vis ident enum_args { $$ = mk_node(NN_EnumDef, 3, $1, $2, $3); } +; + +enum_args +: '{' struct_decl_fields '}' { $$ = mk_node(NN_EnumArgs, 1, $2); } +| '{' struct_decl_fields ',' '}' { $$ = mk_node(NN_EnumArgs, 1, $2); } +| '(' maybe_ty_sums ')' { $$ = mk_node(NN_EnumArgs, 1, $2); } +| '=' expr { $$ = mk_node(NN_EnumArgs, 1, $2); } +| %empty { $$ = mk_none(); } +; + +// unions +item_union +: UNION ident generic_params maybe_where_clause '{' struct_decl_fields '}' { $$ = mk_node(NN_ItemUnion, 0); } +| UNION ident generic_params maybe_where_clause '{' struct_decl_fields ',' '}' { $$ = mk_node(NN_ItemUnion, 0); } + +item_mod +: MOD ident ';' { $$ = mk_node(NN_ItemMod, 1, $2); } +| MOD ident '{' maybe_mod_items '}' { $$ = mk_node(NN_ItemMod, 2, $2, $4); } +| MOD ident '{' inner_attrs maybe_mod_items '}' { $$ = mk_node(NN_ItemMod, 3, $2, $4, $5); } +; + +item_foreign_mod +: EXTERN maybe_abi '{' maybe_foreign_items '}' { $$ = mk_node(NN_ItemForeignMod, 1, $4); } +| EXTERN maybe_abi '{' inner_attrs maybe_foreign_items '}' { $$ = mk_node(NN_ItemForeignMod, 2, $4, $5); } +; + +maybe_abi +: str +| %empty { $$ = mk_none(); } +; + +maybe_foreign_items +: foreign_items +| %empty { $$ = mk_none(); } +; + +foreign_items +: foreign_item { $$ = mk_node(NN_ForeignItems, 1, $1); } +| foreign_items foreign_item { $$ = ext_node($1, 1, $2); } +; + +foreign_item +: attrs_and_vis STATIC item_foreign_static { $$ = mk_node(NN_ForeignItem, 2, $1, $3); } +| attrs_and_vis item_foreign_fn { $$ = mk_node(NN_ForeignItem, 2, $1, $2); } +| attrs_and_vis UNSAFE item_foreign_fn { $$ = mk_node(NN_ForeignItem, 2, $1, $3); } +; + +item_foreign_static +: maybe_mut ident ':' ty ';' { $$ = mk_node(NN_StaticItem, 3, $1, $2, $4); } +; + +item_foreign_fn +: FN ident generic_params fn_decl_allow_variadic maybe_where_clause ';' { $$ = mk_node(NN_ForeignFn, 4, $2, $3, $4, $5); } +; + +fn_decl_allow_variadic +: fn_params_allow_variadic ret_ty { $$ = mk_node(NN_FnDecl, 2, $1, $2); } +; + +fn_params_allow_variadic +: '(' ')' { $$ = mk_none(); } +| '(' params ')' { $$ = $2; } +| '(' params ',' ')' { $$ = $2; } +| '(' params ',' DOTDOTDOT ')' { $$ = $2; } +; + +visibility +: PUB { $$ = mk_empty_atom(NN_Public); } +| %empty { $$ = mk_empty_atom(NN_Inherited); } +; + +idents_or_self +: ident_or_self { $$ = mk_node(NN_IdentsOrSelf, 1, $1); } +| idents_or_self AS ident { $$ = mk_node(NN_IdentsOrSelf, 2, $1, $3); } +| idents_or_self ',' ident_or_self { $$ = ext_node($1, 1, $3); } +; + +ident_or_self +: ident +| SELF { $$ = mk_empty_atom(NN_SELF); } +; + +item_type +: TYPE ident generic_params maybe_where_clause '=' ty_sum ';' { $$ = mk_node(NN_ItemTy, 4, $2, $3, $4, $6); } +; + +for_sized +: FOR '?' ident { $$ = mk_node(NN_ForSized, 1, $3); } +| FOR ident '?' { $$ = mk_node(NN_ForSized, 1, $2); } +| %empty { $$ = mk_none(); } +; + +item_trait +: maybe_unsafe TRAIT ident generic_params for_sized maybe_ty_param_bounds maybe_where_clause '{' maybe_trait_items '}' +{ + $$ = mk_node(NN_ItemTrait, 7, $1, $3, $4, $5, $6, $7, $9); +} +; + +maybe_trait_items +: trait_items +| %empty { $$ = mk_none(); } +; + +trait_items +: trait_item { $$ = mk_node(NN_TraitItems, 1, $1); } +| trait_items trait_item { $$ = ext_node($1, 1, $2); } +; + +trait_item +: trait_const +| trait_type +| trait_method +| maybe_outer_attrs item_macro { $$ = mk_node(NN_TraitMacroItem, 2, $1, $2); } +; + +trait_const +: maybe_outer_attrs CONST ident maybe_ty_ascription maybe_const_default ';' { $$ = mk_node(NN_ConstTraitItem, 4, $1, $3, $4, $5); } +; + +maybe_const_default +: '=' expr { $$ = mk_node(NN_ConstDefault, 1, $2); } +| %empty { $$ = mk_none(); } +; + +trait_type +: maybe_outer_attrs TYPE ty_param ';' { $$ = mk_node(NN_TypeTraitItem, 2, $1, $3); } +; + +maybe_unsafe +: UNSAFE { $$ = mk_empty_atom(NN_Unsafe); } +| %empty { $$ = mk_none(); } +; + +maybe_default_maybe_unsafe +: DEFAULT UNSAFE { $$ = mk_empty_atom(NN_DefaultUnsafe); } +| DEFAULT { $$ = mk_empty_atom(NN_Default); } +| UNSAFE { $$ = mk_empty_atom(NN_Unsafe); } +| %empty { $$ = mk_none(); } + +trait_method +: type_method { $$ = mk_node(NN_Required, 1, $1); } +| method { $$ = mk_node(NN_Provided, 1, $1); } +; + +type_method +: maybe_outer_attrs maybe_unsafe FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause ';' +{ + $$ = mk_node(NN_TypeMethod, 6, $1, $2, $4, $5, $6, $7); +} +| maybe_outer_attrs CONST maybe_unsafe FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause ';' +{ + $$ = mk_node(NN_TypeMethod, 6, $1, $3, $5, $6, $7, $8); +} +| maybe_outer_attrs maybe_unsafe EXTERN maybe_abi FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause ';' +{ + $$ = mk_node(NN_TypeMethod, 7, $1, $2, $4, $6, $7, $8, $9); +} +; + +method +: maybe_outer_attrs maybe_unsafe FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause inner_attrs_and_block +{ + $$ = mk_node(NN_Method, 7, $1, $2, $4, $5, $6, $7, $8); +} +| maybe_outer_attrs CONST maybe_unsafe FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause inner_attrs_and_block +{ + $$ = mk_node(NN_Method, 7, $1, $3, $5, $6, $7, $8, $9); +} +| maybe_outer_attrs maybe_unsafe EXTERN maybe_abi FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause inner_attrs_and_block +{ + $$ = mk_node(NN_Method, 8, $1, $2, $4, $6, $7, $8, $9, $10); +} +; + +impl_method +: attrs_and_vis maybe_default maybe_unsafe FN ident generic_params fn_decl_with_self maybe_where_clause inner_attrs_and_block +{ + $$ = mk_node(NN_Method, 8, $1, $2, $3, $5, $6, $7, $8, $9); +} +| attrs_and_vis maybe_default CONST maybe_unsafe FN ident generic_params fn_decl_with_self maybe_where_clause inner_attrs_and_block +{ + $$ = mk_node(NN_Method, 8, $1, $2, $4, $6, $7, $8, $9, $10); +} +| attrs_and_vis maybe_default maybe_unsafe EXTERN maybe_abi FN ident generic_params fn_decl_with_self maybe_where_clause inner_attrs_and_block +{ + $$ = mk_node(NN_Method, 9, $1, $2, $3, $5, $7, $8, $9, $10, $11); +} +; + +// There are two forms of impl: +// +// impl (<...>)? TY { ... } +// impl (<...>)? TRAIT for TY { ... } +// +// Unfortunately since TY can begin with '<' itself -- as part of a +// TyQualifiedPath type -- there's an s/r conflict when we see '<' after IMPL: +// should we reduce one of the early rules of TY (such as maybe_once) +// or shall we continue shifting into the generic_params list for the +// impl? +// +// The production parser disambiguates a different case here by +// permitting / requiring the user to provide parens around types when +// they are ambiguous with traits. We do the same here, regrettably, +// by splitting ty into ty and ty_prim. +item_impl +: maybe_default_maybe_unsafe IMPL generic_params ty_prim_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' +{ + $$ = mk_node(NN_ItemImpl, 6, $1, $3, $4, $5, $7, $8); +} +| maybe_default_maybe_unsafe IMPL generic_params '(' ty ')' maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' +{ + $$ = mk_node(NN_ItemImpl, 6, $1, $3, 5, $6, $9, $10); +} +| maybe_default_maybe_unsafe IMPL generic_params trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' +{ + $$ = mk_node(NN_ItemImpl, 6, $3, $4, $6, $7, $9, $10); +} +| maybe_default_maybe_unsafe IMPL generic_params '!' trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' +{ + $$ = mk_node(NN_ItemImplNeg, 7, $1, $3, $5, $7, $8, $10, $11); +} +| maybe_default_maybe_unsafe IMPL generic_params trait_ref FOR DOTDOT '{' '}' +{ + $$ = mk_node(NN_ItemImplDefault, 3, $1, $3, $4); +} +| maybe_default_maybe_unsafe IMPL generic_params '!' trait_ref FOR DOTDOT '{' '}' +{ + $$ = mk_node(NN_ItemImplDefaultNeg, 3, $1, $3, $4); +} +; + +maybe_impl_items +: impl_items +| %empty { $$ = mk_none(); } +; + +impl_items +: impl_item { $$ = mk_node(NN_ImplItems, 1, $1); } +| impl_item impl_items { $$ = ext_node($1, 1, $2); } +; + +impl_item +: impl_method +| attrs_and_vis item_macro { $$ = mk_node(NN_ImplMacroItem, 2, $1, $2); } +| impl_const +| impl_type +; + +maybe_default +: DEFAULT { $$ = mk_empty_atom(NN_Default); } +| %empty { $$ = mk_none(); } +; + +impl_const +: attrs_and_vis maybe_default item_const { $$ = mk_node(NN_ImplConst, 3, $1, $2, $3); } +; + +impl_type +: attrs_and_vis maybe_default TYPE ident generic_params '=' ty_sum ';' { $$ = mk_node(NN_ImplType, 5, $1, $2, $4, $5, $7); } +; + +item_fn +: FN ident generic_params fn_decl maybe_where_clause inner_attrs_and_block +{ + $$ = mk_node(NN_ItemFn, 5, $2, $3, $4, $5, $6); +} +| CONST FN ident generic_params fn_decl maybe_where_clause inner_attrs_and_block +{ + $$ = mk_node(NN_ItemFn, 5, $3, $4, $5, $6, $7); +} +; + +item_unsafe_fn +: UNSAFE FN ident generic_params fn_decl maybe_where_clause inner_attrs_and_block +{ + $$ = mk_node(NN_ItemUnsafeFn, 5, $3, $4, $5, $6, $7); +} +| CONST UNSAFE FN ident generic_params fn_decl maybe_where_clause inner_attrs_and_block +{ + $$ = mk_node(NN_ItemUnsafeFn, 5, $4, $5, $6, $7, $8); +} +| UNSAFE EXTERN maybe_abi FN ident generic_params fn_decl maybe_where_clause inner_attrs_and_block +{ + $$ = mk_node(NN_ItemUnsafeFn, 6, $3, $5, $6, $7, $8, $9); +} +; + +fn_decl +: fn_params ret_ty { $$ = mk_node(NN_FnDecl, 2, $1, $2); } +; + +fn_decl_with_self +: fn_params_with_self ret_ty { $$ = mk_node(NN_FnDecl, 2, $1, $2); } +; + +fn_decl_with_self_allow_anon_params +: fn_anon_params_with_self ret_ty { $$ = mk_node(NN_FnDecl, 2, $1, $2); } +; + +fn_params +: '(' maybe_params ')' { $$ = $2; } +; + +fn_anon_params +: '(' anon_param anon_params_allow_variadic_tail ')' { $$ = ext_node($2, 1, $3); } +| '(' ')' { $$ = mk_none(); } +; + +fn_params_with_self +: '(' maybe_mut SELF maybe_ty_ascription maybe_comma_params ')' { $$ = mk_node(NN_SelfLower, 3, $2, $4, $5); } +| '(' '&' maybe_mut SELF maybe_ty_ascription maybe_comma_params ')' { $$ = mk_node(NN_SelfRegion, 3, $3, $5, $6); } +| '(' '&' lifetime maybe_mut SELF maybe_ty_ascription maybe_comma_params ')' { $$ = mk_node(NN_SelfRegion, 4, $3, $4, $6, $7); } +| '(' maybe_params ')' { $$ = mk_node(NN_SelfStatic, 1, $2); } +; + +fn_anon_params_with_self +: '(' maybe_mut SELF maybe_ty_ascription maybe_comma_anon_params ')' { $$ = mk_node(NN_SelfLower, 3, $2, $4, $5); } +| '(' '&' maybe_mut SELF maybe_ty_ascription maybe_comma_anon_params ')' { $$ = mk_node(NN_SelfRegion, 3, $3, $5, $6); } +| '(' '&' lifetime maybe_mut SELF maybe_ty_ascription maybe_comma_anon_params ')' { $$ = mk_node(NN_SelfRegion, 4, $3, $4, $6, $7); } +| '(' maybe_anon_params ')' { $$ = mk_node(NN_SelfStatic, 1, $2); } +; + +maybe_params +: params +| params ',' +| %empty { $$ = mk_none(); } +; + +params +: param { $$ = mk_node(NN_Args, 1, $1); } +| params ',' param { $$ = ext_node($1, 1, $3); } +; + +param +: pat ':' ty_sum { $$ = mk_node(NN_Arg, 2, $1, $3); } +; + +inferrable_params +: inferrable_param { $$ = mk_node(NN_InferrableParams, 1, $1); } +| inferrable_params ',' inferrable_param { $$ = ext_node($1, 1, $3); } +; + +inferrable_param +: pat maybe_ty_ascription { $$ = mk_node(NN_InferrableParam, 2, $1, $2); } +; + +maybe_comma_params +: ',' { $$ = mk_none(); } +| ',' params { $$ = $2; } +| ',' params ',' { $$ = $2; } +| %empty { $$ = mk_none(); } +; + +maybe_comma_anon_params +: ',' { $$ = mk_none(); } +| ',' anon_params { $$ = $2; } +| ',' anon_params ',' { $$ = $2; } +| %empty { $$ = mk_none(); } +; + +maybe_anon_params +: anon_params +| anon_params ',' +| %empty { $$ = mk_none(); } +; + +anon_params +: anon_param { $$ = mk_node(NN_Args, 1, $1); } +| anon_params ',' anon_param { $$ = ext_node($1, 1, $3); } +; + +// anon means it's allowed to be anonymous (type-only), but it can +// still have a name +anon_param +: named_arg ':' ty { $$ = mk_node(NN_Arg, 2, $1, $3); } +| ty +; + +anon_params_allow_variadic_tail +: ',' DOTDOTDOT { $$ = mk_none(); } +| ',' anon_param anon_params_allow_variadic_tail { $$ = mk_node(NN_Args, 2, $2, $3); } +| %empty { $$ = mk_none(); } +; + +named_arg +: ident +| UNDERSCORE { $$ = mk_empty_atom(NN_PatWild); } +| '&' ident { $$ = $2; } +| '&' UNDERSCORE { $$ = mk_empty_atom(NN_PatWild); } +| ANDAND ident { $$ = $2; } +| ANDAND UNDERSCORE { $$ = mk_empty_atom(NN_PatWild); } +| MUT ident { $$ = $2; } +; + +ret_ty +: RARROW '!' { $$ = mk_none(); } +| RARROW ty { $$ = mk_node(NN_RetTy, 1, $2); } +| %prec IDENT %empty { $$ = mk_none(); } +; + +generic_params +: '<' '>' { $$ = mk_node(NN_Generics, 2, mk_none(), mk_none()); } +| '<' lifetimes '>' { $$ = mk_node(NN_Generics, 2, $2, mk_none()); } +| '<' lifetimes ',' '>' { $$ = mk_node(NN_Generics, 2, $2, mk_none()); } +| '<' lifetimes SHR { push_back('>'); $$ = mk_node(NN_Generics, 2, $2, mk_none()); } +| '<' lifetimes ',' SHR { push_back('>'); $$ = mk_node(NN_Generics, 2, $2, mk_none()); } +| '<' lifetimes ',' ty_params '>' { $$ = mk_node(NN_Generics, 2, $2, $4); } +| '<' lifetimes ',' ty_params ',' '>' { $$ = mk_node(NN_Generics, 2, $2, $4); } +| '<' lifetimes ',' ty_params SHR { push_back('>'); $$ = mk_node(NN_Generics, 2, $2, $4); } +| '<' lifetimes ',' ty_params ',' SHR { push_back('>'); $$ = mk_node(NN_Generics, 2, $2, $4); } +| '<' ty_params '>' { $$ = mk_node(NN_Generics, 2, mk_none(), $2); } +| '<' ty_params ',' '>' { $$ = mk_node(NN_Generics, 2, mk_none(), $2); } +| '<' ty_params SHR { push_back('>'); $$ = mk_node(NN_Generics, 2, mk_none(), $2); } +| '<' ty_params ',' SHR { push_back('>'); $$ = mk_node(NN_Generics, 2, mk_none(), $2); } +| %empty { $$ = mk_none(); } +; + +maybe_where_clause +: %empty { $$ = mk_none(); } +| where_clause +; + +where_clause +: WHERE where_predicates { $$ = mk_node(NN_WhereClause, 1, $2); } +| WHERE where_predicates ',' { $$ = mk_node(NN_WhereClause, 1, $2); } +; + +where_predicates +: where_predicate { $$ = mk_node(NN_WherePredicates, 1, $1); } +| where_predicates ',' where_predicate { $$ = ext_node($1, 1, $3); } +; + +where_predicate +: maybe_for_lifetimes lifetime ':' bounds { $$ = mk_node(NN_WherePredicate, 3, $1, $2, $4); } +| maybe_for_lifetimes ty ':' ty_param_bounds { $$ = mk_node(NN_WherePredicate, 3, $1, $2, $4); } +; + +maybe_for_lifetimes +: FOR '<' lifetimes '>' { $$ = mk_none(); } +| %prec FORTYPE %empty { $$ = mk_none(); } + +ty_params +: ty_param { $$ = mk_node(NN_TyParams, 1, $1); } +| ty_params ',' ty_param { $$ = ext_node($1, 1, $3); } +; + +// A path with no type parameters; e.g. `foo::bar::Baz` +// +// These show up in 'use' view-items, because these are processed +// without respect to types. +path_no_types_allowed +: ident { $$ = mk_node(NN_ViewPath, 1, $1); } +| MOD_SEP ident { $$ = mk_node(NN_ViewPath, 1, $2); } +| SELF { $$ = mk_node(NN_ViewPath, 1, mk_empty_atom(NN_SELF)); } +| MOD_SEP SELF { $$ = mk_node(NN_ViewPath, 1, mk_empty_atom(NN_SELF)); } +| SUPER { $$ = mk_node(NN_ViewPath, 1, mk_empty_atom(NN_SUPER)); } +| MOD_SEP SUPER { $$ = mk_node(NN_ViewPath, 1, mk_empty_atom(NN_SUPER)); } +| path_no_types_allowed MOD_SEP ident { $$ = ext_node($1, 1, $3); } +; + +// A path with a lifetime and type parameters, with no double colons +// before the type parameters; e.g. `foo::bar<'a>::Baz<T>` +// +// These show up in "trait references", the components of +// type-parameter bounds lists, as well as in the prefix of the +// path_generic_args_and_bounds rule, which is the full form of a +// named typed expression. +// +// They do not have (nor need) an extra '::' before '<' because +// unlike in expr context, there are no "less-than" type exprs to +// be ambiguous with. +path_generic_args_without_colons +: %prec IDENT + ident { $$ = mk_node(NN_components, 1, $1); } +| %prec IDENT + ident generic_args { $$ = mk_node(NN_components, 2, $1, $2); } +| %prec IDENT + ident '(' maybe_ty_sums ')' ret_ty { $$ = mk_node(NN_components, 2, $1, $3); } +| %prec IDENT + path_generic_args_without_colons MOD_SEP ident { $$ = ext_node($1, 1, $3); } +| %prec IDENT + path_generic_args_without_colons MOD_SEP ident generic_args { $$ = ext_node($1, 2, $3, $4); } +| %prec IDENT + path_generic_args_without_colons MOD_SEP ident '(' maybe_ty_sums ')' ret_ty { $$ = ext_node($1, 2, $3, $5); } +; + +generic_args +: '<' generic_values '>' { $$ = $2; } +| '<' generic_values SHR { push_back('>'); $$ = $2; } +| '<' generic_values GE { push_back('='); $$ = $2; } +| '<' generic_values SHREQ { push_back('>'); push_back('='); $$ = $2; } +// If generic_args starts with "<<", the first arg must be a +// TyQualifiedPath because that's the only type that can start with a +// '<'. This rule parses that as the first ty_sum and then continues +// with the rest of generic_values. +| SHL ty_qualified_path_and_generic_values '>' { $$ = $2; } +| SHL ty_qualified_path_and_generic_values SHR { push_back('>'); $$ = $2; } +| SHL ty_qualified_path_and_generic_values GE { push_back('='); $$ = $2; } +| SHL ty_qualified_path_and_generic_values SHREQ { push_back('>'); push_back('='); $$ = $2; } +; + +generic_values +: maybe_ty_sums_and_or_bindings { $$ = mk_node(NN_GenericValues, 1, $1); } +; + +maybe_ty_sums_and_or_bindings +: ty_sums +| ty_sums ',' +| ty_sums ',' bindings { $$ = mk_node(NN_TySumsAndBindings, 2, $1, $3); } +| bindings +| bindings ',' +| %empty { $$ = mk_none(); } +; + +maybe_bindings +: ',' bindings { $$ = $2; } +| %empty { $$ = mk_none(); } +; + +//////////////////////////////////////////////////////////////////////// +// Part 2: Patterns +//////////////////////////////////////////////////////////////////////// + +pat +: UNDERSCORE { $$ = mk_empty_atom(NN_PatWild); } +| '&' pat { $$ = mk_node(NN_PatRegion, 1, $2); } +| '&' MUT pat { $$ = mk_node(NN_PatRegion, 1, $3); } +| ANDAND pat { $$ = mk_node(NN_PatRegion, 1, mk_node(NN_PatRegion, 1, $2)); } +| '(' ')' { $$ = mk_empty_atom(NN_PatUnit); } +| '(' pat_tup ')' { $$ = mk_node(NN_PatTup, 1, $2); } +| '[' pat_vec ']' { $$ = mk_node(NN_PatVec, 1, $2); } +| lit_or_path +| lit_or_path DOTDOTDOT lit_or_path { $$ = mk_node(NN_PatRange, 2, $1, $3); } +| path_expr '{' pat_struct '}' { $$ = mk_node(NN_PatStruct, 2, $1, $3); } +| path_expr '(' ')' { $$ = mk_node(NN_PatEnum, 2, $1, mk_none()); } +| path_expr '(' pat_tup ')' { $$ = mk_node(NN_PatEnum, 2, $1, $3); } +| path_expr '!' maybe_ident delimited_token_trees { $$ = mk_node(NN_PatMac, 3, $1, $3, $4); } +| binding_mode ident { $$ = mk_node(NN_PatIdent, 2, $1, $2); } +| ident '@' pat { $$ = mk_node(NN_PatIdent, 3, mk_node(NN_BindByValue, 1, mk_empty_atom(NN_MutImmutable)), $1, $3); } +| binding_mode ident '@' pat { $$ = mk_node(NN_PatIdent, 3, $1, $2, $4); } +| BOX pat { $$ = mk_node(NN_PatUniq, 1, $2); } +| '<' ty_sum maybe_as_trait_ref '>' MOD_SEP ident { $$ = mk_node(NN_PatQualifiedPath, 3, $2, $3, $6); } +| SHL ty_sum maybe_as_trait_ref '>' MOD_SEP ident maybe_as_trait_ref '>' MOD_SEP ident +{ + $$ = mk_node(NN_PatQualifiedPath, 3, mk_node(NN_PatQualifiedPath, 3, $2, $3, $6), $7, $10); +} +; + +pats_or +: pat { $$ = mk_node(NN_Pats, 1, $1); } +| pats_or '|' pat { $$ = ext_node($1, 1, $3); } +; + +binding_mode +: REF { $$ = mk_node(NN_BindByRef, 1, mk_empty_atom(NN_MutImmutable)); } +| REF MUT { $$ = mk_node(NN_BindByRef, 1, mk_empty_atom(NN_MutMutable)); } +| MUT { $$ = mk_node(NN_BindByValue, 1, mk_empty_atom(NN_MutMutable)); } +; + +lit_or_path +: path_expr { $$ = mk_node(NN_PatLit, 1, $1); } +| lit { $$ = mk_node(NN_PatLit, 1, $1); } +| '-' lit { $$ = mk_node(NN_PatLit, 1, $2); } +; + +pat_field +: ident { $$ = mk_node(NN_PatField, 1, $1); } +| binding_mode ident { $$ = mk_node(NN_PatField, 2, $1, $2); } +| BOX ident { $$ = mk_node(NN_PatField, 2, mk_empty_atom(NN_BOX), $2); } +| BOX binding_mode ident { $$ = mk_node(NN_PatField, 3, mk_empty_atom(NN_BOX), $2, $3); } +| ident ':' pat { $$ = mk_node(NN_PatField, 2, $1, $3); } +| binding_mode ident ':' pat { $$ = mk_node(NN_PatField, 3, $1, $2, $4); } +| LIT_INTEGER ':' pat { $$ = mk_node(NN_PatField, 2, mk_atom(NN_LitInteger, yytext), $3); } +; + +pat_fields +: pat_field { $$ = mk_node(NN_PatFields, 1, $1); } +| pat_fields ',' pat_field { $$ = ext_node($1, 1, $3); } +; + +pat_struct +: pat_fields { $$ = mk_node(NN_PatStruct, 2, $1, mk_atom(NN_LitBool, "false")); } +| pat_fields ',' { $$ = mk_node(NN_PatStruct, 2, $1, mk_atom(NN_LitBool, "false")); } +| pat_fields ',' DOTDOT { $$ = mk_node(NN_PatStruct, 2, $1, mk_atom(NN_LitBool, "true")); } +| DOTDOT { $$ = mk_node(NN_PatStruct, 1, mk_atom(NN_LitBool, "true")); } +| %empty { $$ = mk_node(NN_PatStruct, 1, mk_none()); } +; + +pat_tup +: pat_tup_elts { $$ = mk_node(NN_PatTup, 2, $1, mk_none()); } +| pat_tup_elts ',' { $$ = mk_node(NN_PatTup, 2, $1, mk_none()); } +| pat_tup_elts DOTDOT { $$ = mk_node(NN_PatTup, 2, $1, mk_none()); } +| pat_tup_elts ',' DOTDOT { $$ = mk_node(NN_PatTup, 2, $1, mk_none()); } +| pat_tup_elts DOTDOT ',' pat_tup_elts { $$ = mk_node(NN_PatTup, 2, $1, $4); } +| pat_tup_elts DOTDOT ',' pat_tup_elts ',' { $$ = mk_node(NN_PatTup, 2, $1, $4); } +| pat_tup_elts ',' DOTDOT ',' pat_tup_elts { $$ = mk_node(NN_PatTup, 2, $1, $5); } +| pat_tup_elts ',' DOTDOT ',' pat_tup_elts ',' { $$ = mk_node(NN_PatTup, 2, $1, $5); } +| DOTDOT ',' pat_tup_elts { $$ = mk_node(NN_PatTup, 2, mk_none(), $3); } +| DOTDOT ',' pat_tup_elts ',' { $$ = mk_node(NN_PatTup, 2, mk_none(), $3); } +| DOTDOT { $$ = mk_node(NN_PatTup, 2, mk_none(), mk_none()); } +; + +pat_tup_elts +: pat { $$ = mk_node(NN_PatTupElts, 1, $1); } +| pat_tup_elts ',' pat { $$ = ext_node($1, 1, $3); } +; + +pat_vec +: pat_vec_elts { $$ = mk_node(NN_PatVec, 2, $1, mk_none()); } +| pat_vec_elts ',' { $$ = mk_node(NN_PatVec, 2, $1, mk_none()); } +| pat_vec_elts DOTDOT { $$ = mk_node(NN_PatVec, 2, $1, mk_none()); } +| pat_vec_elts ',' DOTDOT { $$ = mk_node(NN_PatVec, 2, $1, mk_none()); } +| pat_vec_elts DOTDOT ',' pat_vec_elts { $$ = mk_node(NN_PatVec, 2, $1, $4); } +| pat_vec_elts DOTDOT ',' pat_vec_elts ',' { $$ = mk_node(NN_PatVec, 2, $1, $4); } +| pat_vec_elts ',' DOTDOT ',' pat_vec_elts { $$ = mk_node(NN_PatVec, 2, $1, $5); } +| pat_vec_elts ',' DOTDOT ',' pat_vec_elts ',' { $$ = mk_node(NN_PatVec, 2, $1, $5); } +| DOTDOT ',' pat_vec_elts { $$ = mk_node(NN_PatVec, 2, mk_none(), $3); } +| DOTDOT ',' pat_vec_elts ',' { $$ = mk_node(NN_PatVec, 2, mk_none(), $3); } +| DOTDOT { $$ = mk_node(NN_PatVec, 2, mk_none(), mk_none()); } +| %empty { $$ = mk_node(NN_PatVec, 2, mk_none(), mk_none()); } +; + +pat_vec_elts +: pat { $$ = mk_node(NN_PatVecElts, 1, $1); } +| pat_vec_elts ',' pat { $$ = ext_node($1, 1, $3); } +; + +//////////////////////////////////////////////////////////////////////// +// Part 3: Types +//////////////////////////////////////////////////////////////////////// + +ty +: ty_prim +| ty_closure +| '<' ty_sum maybe_as_trait_ref '>' MOD_SEP ident { $$ = mk_node(NN_TyQualifiedPath, 3, $2, $3, $6); } +| SHL ty_sum maybe_as_trait_ref '>' MOD_SEP ident maybe_as_trait_ref '>' MOD_SEP ident { $$ = mk_node(NN_TyQualifiedPath, 3, mk_node(NN_TyQualifiedPath, 3, $2, $3, $6), $7, $10); } +| '(' ty_sums ')' { $$ = mk_node(NN_TyTup, 1, $2); } +| '(' ty_sums ',' ')' { $$ = mk_node(NN_TyTup, 1, $2); } +| '(' ')' { $$ = mk_empty_atom(NN_TyNil); } +; + +ty_prim +: %prec IDENT path_generic_args_without_colons { $$ = mk_node(NN_TyPath, 2, mk_node(NN_GLOBAL, 1, mk_atom(NN_LitBool, "false")), $1); } +| %prec IDENT MOD_SEP path_generic_args_without_colons { $$ = mk_node(NN_TyPath, 2, mk_node(NN_GLOBAL, 1, mk_atom(NN_LitBool, "true")), $2); } +| %prec IDENT SELF MOD_SEP path_generic_args_without_colons { $$ = mk_node(NN_TyPath, 2, mk_node(NN_SELF, 1, mk_atom(NN_LitBool, "true")), $3); } +| %prec IDENT path_generic_args_without_colons '!' maybe_ident delimited_token_trees { $$ = mk_node(NN_TyMacro, 3, $1, $3, $4); } +| %prec IDENT MOD_SEP path_generic_args_without_colons '!' maybe_ident delimited_token_trees { $$ = mk_node(NN_TyMacro, 3, $2, $4, $5); } +| BOX ty { $$ = mk_node(NN_TyBox, 1, $2); } +| '*' maybe_mut_or_const ty { $$ = mk_node(NN_TyPtr, 2, $2, $3); } +| '&' ty { $$ = mk_node(NN_TyRptr, 2, mk_empty_atom(NN_MutImmutable), $2); } +| '&' MUT ty { $$ = mk_node(NN_TyRptr, 2, mk_empty_atom(NN_MutMutable), $3); } +| ANDAND ty { $$ = mk_node(NN_TyRptr, 1, mk_node(NN_TyRptr, 2, mk_empty_atom(NN_MutImmutable), $2)); } +| ANDAND MUT ty { $$ = mk_node(NN_TyRptr, 1, mk_node(NN_TyRptr, 2, mk_empty_atom(NN_MutMutable), $3)); } +| '&' lifetime maybe_mut ty { $$ = mk_node(NN_TyRptr, 3, $2, $3, $4); } +| ANDAND lifetime maybe_mut ty { $$ = mk_node(NN_TyRptr, 1, mk_node(NN_TyRptr, 3, $2, $3, $4)); } +| '[' ty ']' { $$ = mk_node(NN_TyVec, 1, $2); } +| '[' ty ',' DOTDOT expr ']' { $$ = mk_node(NN_TyFixedLengthVec, 2, $2, $5); } +| '[' ty ';' expr ']' { $$ = mk_node(NN_TyFixedLengthVec, 2, $2, $4); } +| TYPEOF '(' expr ')' { $$ = mk_node(NN_TyTypeof, 1, $3); } +| UNDERSCORE { $$ = mk_empty_atom(NN_TyInfer); } +| ty_bare_fn +| for_in_type +; + +ty_bare_fn +: FN ty_fn_decl { $$ = $2; } +| UNSAFE FN ty_fn_decl { $$ = $3; } +| EXTERN maybe_abi FN ty_fn_decl { $$ = $4; } +| UNSAFE EXTERN maybe_abi FN ty_fn_decl { $$ = $5; } +; + +ty_fn_decl +: generic_params fn_anon_params ret_ty { $$ = mk_node(NN_TyFnDecl, 3, $1, $2, $3); } +; + +ty_closure +: UNSAFE '|' anon_params '|' maybe_bounds ret_ty { $$ = mk_node(NN_TyClosure, 3, $3, $5, $6); } +| '|' anon_params '|' maybe_bounds ret_ty { $$ = mk_node(NN_TyClosure, 3, $2, $4, $5); } +| UNSAFE OROR maybe_bounds ret_ty { $$ = mk_node(NN_TyClosure, 2, $3, $4); } +| OROR maybe_bounds ret_ty { $$ = mk_node(NN_TyClosure, 2, $2, $3); } +; + +for_in_type +: FOR '<' maybe_lifetimes '>' for_in_type_suffix { $$ = mk_node(NN_ForInType, 2, $3, $5); } +; + +for_in_type_suffix +: ty_bare_fn +| trait_ref +| ty_closure +; + +maybe_mut +: MUT { $$ = mk_empty_atom(NN_MutMutable); } +| %prec MUT %empty { $$ = mk_empty_atom(NN_MutImmutable); } +; + +maybe_mut_or_const +: MUT { $$ = mk_empty_atom(NN_MutMutable); } +| CONST { $$ = mk_empty_atom(NN_MutImmutable); } +| %empty { $$ = mk_empty_atom(NN_MutImmutable); } +; + +ty_qualified_path_and_generic_values +: ty_qualified_path maybe_bindings +{ + $$ = mk_node(NN_GenericValues, 3, mk_none(), mk_node(NN_TySums, 1, mk_node(NN_TySum, 1, $1)), $2); +} +| ty_qualified_path ',' ty_sums maybe_bindings +{ + $$ = mk_node(NN_GenericValues, 3, mk_none(), mk_node(NN_TySums, 2, $1, $3), $4); +} +; + +ty_qualified_path +: ty_sum AS trait_ref '>' MOD_SEP ident { $$ = mk_node(NN_TyQualifiedPath, 3, $1, $3, $6); } +| ty_sum AS trait_ref '>' MOD_SEP ident '+' ty_param_bounds { $$ = mk_node(NN_TyQualifiedPath, 3, $1, $3, $6); } +; + +maybe_ty_sums +: ty_sums +| ty_sums ',' +| %empty { $$ = mk_none(); } +; + +ty_sums +: ty_sum { $$ = mk_node(NN_TySums, 1, $1); } +| ty_sums ',' ty_sum { $$ = ext_node($1, 1, $3); } +; + +ty_sum +: ty_sum_elt { $$ = mk_node(NN_TySum, 1, $1); } +| ty_sum '+' ty_sum_elt { $$ = ext_node($1, 1, $3); } +; + +ty_sum_elt +: ty +| lifetime +; + +ty_prim_sum +: ty_prim_sum_elt { $$ = mk_node(NN_TySum, 1, $1); } +| ty_prim_sum '+' ty_prim_sum_elt { $$ = ext_node($1, 1, $3); } +; + +ty_prim_sum_elt +: ty_prim +| lifetime +; + +maybe_ty_param_bounds +: ':' ty_param_bounds { $$ = $2; } +| %empty { $$ = mk_none(); } +; + +ty_param_bounds +: boundseq +| %empty { $$ = mk_none(); } +; + +boundseq +: polybound +| boundseq '+' polybound { $$ = ext_node($1, 1, $3); } +; + +polybound +: FOR '<' maybe_lifetimes '>' bound { $$ = mk_node(NN_PolyBound, 2, $3, $5); } +| bound +| '?' FOR '<' maybe_lifetimes '>' bound { $$ = mk_node(NN_PolyBound, 2, $4, $6); } +| '?' bound { $$ = $2; } +; + +bindings +: binding { $$ = mk_node(NN_Binding, 1, $1); } +| bindings ',' binding { $$ = ext_node($1, 1, $3); } +; + +binding +: ident '=' ty { mk_node(NN_Binding, 2, $1, $3); } +; + +ty_param +: ident maybe_ty_param_bounds maybe_ty_default { $$ = mk_node(NN_TyParam, 3, $1, $2, $3); } +| ident '?' ident maybe_ty_param_bounds maybe_ty_default { $$ = mk_node(NN_TyParam, 4, $1, $3, $4, $5); } +; + +maybe_bounds +: %prec SHIFTPLUS + ':' bounds { $$ = $2; } +| %prec SHIFTPLUS %empty { $$ = mk_none(); } +; + +bounds +: bound { $$ = mk_node(NN_bounds, 1, $1); } +| bounds '+' bound { $$ = ext_node($1, 1, $3); } +; + +bound +: lifetime +| trait_ref +; + +maybe_ltbounds +: %prec SHIFTPLUS + ':' ltbounds { $$ = $2; } +| %empty { $$ = mk_none(); } +; + +ltbounds +: lifetime { $$ = mk_node(NN_ltbounds, 1, $1); } +| ltbounds '+' lifetime { $$ = ext_node($1, 1, $3); } +; + +maybe_ty_default +: '=' ty_sum { $$ = mk_node(NN_TyDefault, 1, $2); } +| %empty { $$ = mk_none(); } +; + +maybe_lifetimes +: lifetimes +| lifetimes ',' +| %empty { $$ = mk_none(); } +; + +lifetimes +: lifetime_and_bounds { $$ = mk_node(NN_Lifetimes, 1, $1); } +| lifetimes ',' lifetime_and_bounds { $$ = ext_node($1, 1, $3); } +; + +lifetime_and_bounds +: LIFETIME maybe_ltbounds { $$ = mk_node(NN_lifetime, 2, mk_atom(NN_lifetime, yytext), $2); } +| STATIC_LIFETIME { $$ = mk_empty_atom(NN_static_lifetime); } +; + +lifetime +: LIFETIME { $$ = mk_atom(NN_lifetime, yytext); } +| STATIC_LIFETIME { $$ = mk_empty_atom(NN_static_lifetime); } +; + +trait_ref +: %prec IDENT path_generic_args_without_colons +| %prec IDENT MOD_SEP path_generic_args_without_colons { $$ = $2; } +; + +//////////////////////////////////////////////////////////////////////// +// Part 4: Blocks, statements, and expressions +//////////////////////////////////////////////////////////////////////// + +inner_attrs_and_block +: '{' maybe_inner_attrs maybe_stmts '}' { $$ = mk_node(NN_ExprBlock, 2, $2, $3); } +; + +block +: '{' maybe_stmts '}' { $$ = mk_node(NN_ExprBlock, 1, $2); } +; + +maybe_stmts +: stmts +| stmts nonblock_expr { $$ = ext_node($1, 1, $2); } +| nonblock_expr +| %empty { $$ = mk_none(); } +; + +// There are two sub-grammars within a "stmts: exprs" derivation +// depending on whether each stmt-expr is a block-expr form; this is to +// handle the "semicolon rule" for stmt sequencing that permits +// writing +// +// if foo { bar } 10 +// +// as a sequence of two stmts (one if-expr stmt, one lit-10-expr +// stmt). Unfortunately by permitting juxtaposition of exprs in +// sequence like that, the non-block expr grammar has to have a +// second limited sub-grammar that excludes the prefix exprs that +// are ambiguous with binops. That is to say: +// +// {10} - 1 +// +// should parse as (progn (progn 10) (- 1)) not (- (progn 10) 1), that +// is to say, two statements rather than one, at least according to +// the mainline rust parser. +// +// So we wind up with a 3-way split in exprs that occur in stmt lists: +// block, nonblock-prefix, and nonblock-nonprefix. +// +// In non-stmts contexts, expr can relax this trichotomy. + +stmts +: stmt { $$ = mk_node(NN_stmts, 1, $1); } +| stmts stmt { $$ = ext_node($1, 1, $2); } +; + +stmt +: maybe_outer_attrs let { $$ = $2; } +| stmt_item +| PUB stmt_item { $$ = $2; } +| outer_attrs stmt_item { $$ = $2; } +| outer_attrs PUB stmt_item { $$ = $3; } +| full_block_expr +| maybe_outer_attrs block { $$ = $2; } +| nonblock_expr ';' +| outer_attrs nonblock_expr ';' { $$ = $2; } +| ';' { $$ = mk_none(); } +; + +maybe_exprs +: exprs +| exprs ',' +| %empty { $$ = mk_none(); } +; + +maybe_expr +: expr +| %empty { $$ = mk_none(); } +; + +exprs +: expr { $$ = mk_node(NN_exprs, 1, $1); } +| exprs ',' expr { $$ = ext_node($1, 1, $3); } +; + +path_expr +: path_generic_args_with_colons +| MOD_SEP path_generic_args_with_colons { $$ = $2; } +| SELF MOD_SEP path_generic_args_with_colons { $$ = mk_node(NN_SelfPath, 1, $3); } +; + +// A path with a lifetime and type parameters with double colons before +// the type parameters; e.g. `foo::bar::<'a>::Baz::<T>` +// +// These show up in expr context, in order to disambiguate from "less-than" +// expressions. +path_generic_args_with_colons +: ident { $$ = mk_node(NN_components, 1, $1); } +| SUPER { $$ = mk_empty_atom(NN_Super); } +| path_generic_args_with_colons MOD_SEP ident { $$ = ext_node($1, 1, $3); } +| path_generic_args_with_colons MOD_SEP SUPER { $$ = ext_node($1, 1, mk_empty_atom(NN_Super)); } +| path_generic_args_with_colons MOD_SEP generic_args { $$ = ext_node($1, 1, $3); } +; + +// the braces-delimited macro is a block_expr so it doesn't appear here +macro_expr +: path_expr '!' maybe_ident parens_delimited_token_trees { $$ = mk_node(NN_MacroExpr, 3, $1, $3, $4); } +| path_expr '!' maybe_ident brackets_delimited_token_trees { $$ = mk_node(NN_MacroExpr, 3, $1, $3, $4); } +; + +nonblock_expr +: lit { $$ = mk_node(NN_ExprLit, 1, $1); } +| %prec IDENT + path_expr { $$ = mk_node(NN_ExprPath, 1, $1); } +| SELF { $$ = mk_node(NN_ExprPath, 1, mk_empty_atom(NN_SELF)); } +| macro_expr { $$ = mk_node(NN_ExprMac, 1, $1); } +| path_expr '{' struct_expr_fields '}' { $$ = mk_node(NN_ExprStruct, 2, $1, $3); } +| nonblock_expr '?' { $$ = mk_node(NN_ExprTry, 1, $1); } +| nonblock_expr '.' path_generic_args_with_colons { $$ = mk_node(NN_ExprField, 2, $1, $3); } +| nonblock_expr '.' LIT_INTEGER { $$ = mk_node(NN_ExprTupleIndex, 1, $1); } +| nonblock_expr '[' maybe_expr ']' { $$ = mk_node(NN_ExprIndex, 2, $1, $3); } +| nonblock_expr '(' maybe_exprs ')' { $$ = mk_node(NN_ExprCall, 2, $1, $3); } +| '[' vec_expr ']' { $$ = mk_node(NN_ExprVec, 1, $2); } +| '(' maybe_exprs ')' { $$ = mk_node(NN_ExprParen, 1, $2); } +| CONTINUE { $$ = mk_node(NN_ExprAgain, 0); } +| CONTINUE lifetime { $$ = mk_node(NN_ExprAgain, 1, $2); } +| RETURN { $$ = mk_node(NN_ExprRet, 0); } +| RETURN expr { $$ = mk_node(NN_ExprRet, 1, $2); } +| BREAK { $$ = mk_node(NN_ExprBreak, 0); } +| BREAK lifetime { $$ = mk_node(NN_ExprBreak, 1, $2); } +| YIELD { $$ = mk_node(NN_ExprYield, 0); } +| YIELD expr { $$ = mk_node(NN_ExprYield, 1, $2); } +| nonblock_expr '=' expr { $$ = mk_node(NN_ExprAssign, 2, $1, $3); } +| nonblock_expr SHLEQ expr { $$ = mk_node(NN_ExprAssignShl, 2, $1, $3); } +| nonblock_expr SHREQ expr { $$ = mk_node(NN_ExprAssignShr, 2, $1, $3); } +| nonblock_expr MINUSEQ expr { $$ = mk_node(NN_ExprAssignSub, 2, $1, $3); } +| nonblock_expr ANDEQ expr { $$ = mk_node(NN_ExprAssignBitAnd, 2, $1, $3); } +| nonblock_expr OREQ expr { $$ = mk_node(NN_ExprAssignBitOr, 2, $1, $3); } +| nonblock_expr PLUSEQ expr { $$ = mk_node(NN_ExprAssignAdd, 2, $1, $3); } +| nonblock_expr STAREQ expr { $$ = mk_node(NN_ExprAssignMul, 2, $1, $3); } +| nonblock_expr SLASHEQ expr { $$ = mk_node(NN_ExprAssignDiv, 2, $1, $3); } +| nonblock_expr CARETEQ expr { $$ = mk_node(NN_ExprAssignBitXor, 2, $1, $3); } +| nonblock_expr PERCENTEQ expr { $$ = mk_node(NN_ExprAssignRem, 2, $1, $3); } +| nonblock_expr OROR expr { $$ = mk_node(NN_BiOr, 2,$1, $3); } +| nonblock_expr ANDAND expr { $$ = mk_node(NN_BiAnd, 2,$1, $3); } +| nonblock_expr EQEQ expr { $$ = mk_node(NN_BiEq, 2,$1, $3); } +| nonblock_expr NE expr { $$ = mk_node(NN_BiNe, 2,$1, $3); } +| nonblock_expr '<' expr { $$ = mk_node(NN_BiLt, 2,$1, $3); } +| nonblock_expr '>' expr { $$ = mk_node(NN_BiGt, 2,$1, $3); } +| nonblock_expr LE expr { $$ = mk_node(NN_BiLe, 2,$1, $3); } +| nonblock_expr GE expr { $$ = mk_node(NN_BiGe, 2,$1, $3); } +| nonblock_expr '|' expr { $$ = mk_node(NN_BiBitOr, 2,$1, $3); } +| nonblock_expr '^' expr { $$ = mk_node(NN_BiBitXor, 2,$1, $3); } +| nonblock_expr '&' expr { $$ = mk_node(NN_BiBitAnd, 2,$1, $3); } +| nonblock_expr SHL expr { $$ = mk_node(NN_BiShl, 2,$1, $3); } +| nonblock_expr SHR expr { $$ = mk_node(NN_BiShr, 2,$1, $3); } +| nonblock_expr '+' expr { $$ = mk_node(NN_BiAdd, 2,$1, $3); } +| nonblock_expr '-' expr { $$ = mk_node(NN_BiSub, 2,$1, $3); } +| nonblock_expr '*' expr { $$ = mk_node(NN_BiMul, 2,$1, $3); } +| nonblock_expr '/' expr { $$ = mk_node(NN_BiDiv, 2,$1, $3); } +| nonblock_expr '%' expr { $$ = mk_node(NN_BiRem, 2,$1, $3); } +| nonblock_expr DOTDOT { $$ = mk_node(NN_ExprRange, 2, $1, mk_none()); } +| nonblock_expr DOTDOT expr { $$ = mk_node(NN_ExprRange, 2, $1, $3); } +| DOTDOT expr { $$ = mk_node(NN_ExprRange, 2, mk_none(), $2); } +| DOTDOT { $$ = mk_node(NN_ExprRange, 2, mk_none(), mk_none()); } +| nonblock_expr AS ty { $$ = mk_node(NN_ExprCast, 2, $1, $3); } +| nonblock_expr ':' ty { $$ = mk_node(NN_ExprTypeAscr, 2, $1, $3); } +| BOX expr { $$ = mk_node(NN_ExprBox, 1, $2); } +| expr_qualified_path +| nonblock_prefix_expr +; + +expr +: lit { $$ = mk_node(NN_ExprLit, 1, $1); } +| %prec IDENT + path_expr { $$ = mk_node(NN_ExprPath, 1, $1); } +| SELF { $$ = mk_node(NN_ExprPath, 1, mk_empty_atom(NN_SELF)); } +| macro_expr { $$ = mk_node(NN_ExprMac, 1, $1); } +| path_expr '{' struct_expr_fields '}' { $$ = mk_node(NN_ExprStruct, 2, $1, $3); } +| expr '?' { $$ = mk_node(NN_ExprTry, 1, $1); } +| expr '.' path_generic_args_with_colons { $$ = mk_node(NN_ExprField, 2, $1, $3); } +| expr '.' LIT_INTEGER { $$ = mk_node(NN_ExprTupleIndex, 1, $1); } +| expr '[' maybe_expr ']' { $$ = mk_node(NN_ExprIndex, 2, $1, $3); } +| expr '(' maybe_exprs ')' { $$ = mk_node(NN_ExprCall, 2, $1, $3); } +| '(' maybe_exprs ')' { $$ = mk_node(NN_ExprParen, 1, $2); } +| '[' vec_expr ']' { $$ = mk_node(NN_ExprVec, 1, $2); } +| CONTINUE { $$ = mk_node(NN_ExprAgain, 0); } +| CONTINUE ident { $$ = mk_node(NN_ExprAgain, 1, $2); } +| RETURN { $$ = mk_node(NN_ExprRet, 0); } +| RETURN expr { $$ = mk_node(NN_ExprRet, 1, $2); } +| BREAK { $$ = mk_node(NN_ExprBreak, 0); } +| BREAK ident { $$ = mk_node(NN_ExprBreak, 1, $2); } +| YIELD { $$ = mk_node(NN_ExprYield, 0); } +| YIELD expr { $$ = mk_node(NN_ExprYield, 1, $2); } +| expr '=' expr { $$ = mk_node(NN_ExprAssign, 2, $1, $3); } +| expr SHLEQ expr { $$ = mk_node(NN_ExprAssignShl, 2, $1, $3); } +| expr SHREQ expr { $$ = mk_node(NN_ExprAssignShr, 2, $1, $3); } +| expr MINUSEQ expr { $$ = mk_node(NN_ExprAssignSub, 2, $1, $3); } +| expr ANDEQ expr { $$ = mk_node(NN_ExprAssignBitAnd, 2, $1, $3); } +| expr OREQ expr { $$ = mk_node(NN_ExprAssignBitOr, 2, $1, $3); } +| expr PLUSEQ expr { $$ = mk_node(NN_ExprAssignAdd, 2, $1, $3); } +| expr STAREQ expr { $$ = mk_node(NN_ExprAssignMul, 2, $1, $3); } +| expr SLASHEQ expr { $$ = mk_node(NN_ExprAssignDiv, 2, $1, $3); } +| expr CARETEQ expr { $$ = mk_node(NN_ExprAssignBitXor, 2, $1, $3); } +| expr PERCENTEQ expr { $$ = mk_node(NN_ExprAssignRem, 2, $1, $3); } +| expr OROR expr { $$ = mk_node(NN_BiOr, 2,$1, $3); } +| expr ANDAND expr { $$ = mk_node(NN_BiAnd, 2,$1, $3); } +| expr EQEQ expr { $$ = mk_node(NN_BiEq, 2,$1, $3); } +| expr NE expr { $$ = mk_node(NN_BiNe, 2,$1, $3); } +| expr '<' expr { $$ = mk_node(NN_BiLt, 2,$1, $3); } +| expr '>' expr { $$ = mk_node(NN_BiGt, 2,$1, $3); } +| expr LE expr { $$ = mk_node(NN_BiLe, 2,$1, $3); } +| expr GE expr { $$ = mk_node(NN_BiGe, 2,$1, $3); } +| expr '|' expr { $$ = mk_node(NN_BiBitOr, 2,$1, $3); } +| expr '^' expr { $$ = mk_node(NN_BiBitXor, 2,$1, $3); } +| expr '&' expr { $$ = mk_node(NN_BiBitAnd, 2,$1, $3); } +| expr SHL expr { $$ = mk_node(NN_BiShl, 2,$1, $3); } +| expr SHR expr { $$ = mk_node(NN_BiShr, 2,$1, $3); } +| expr '+' expr { $$ = mk_node(NN_BiAdd, 2,$1, $3); } +| expr '-' expr { $$ = mk_node(NN_BiSub, 2,$1, $3); } +| expr '*' expr { $$ = mk_node(NN_BiMul, 2,$1, $3); } +| expr '/' expr { $$ = mk_node(NN_BiDiv, 2,$1, $3); } +| expr '%' expr { $$ = mk_node(NN_BiRem, 2,$1, $3); } +| expr DOTDOT { $$ = mk_node(NN_ExprRange, 2, $1, mk_none()); } +| expr DOTDOT expr { $$ = mk_node(NN_ExprRange, 2, $1, $3); } +| DOTDOT expr { $$ = mk_node(NN_ExprRange, 2, mk_none(), $2); } +| DOTDOT { $$ = mk_node(NN_ExprRange, 2, mk_none(), mk_none()); } +| expr AS ty { $$ = mk_node(NN_ExprCast, 2, $1, $3); } +| expr ':' ty { $$ = mk_node(NN_ExprTypeAscr, 2, $1, $3); } +| BOX expr { $$ = mk_node(NN_ExprBox, 1, $2); } +| expr_qualified_path +| block_expr +| block +| nonblock_prefix_expr +; + +expr_nostruct +: lit { $$ = mk_node(NN_ExprLit, 1, $1); } +| %prec IDENT + path_expr { $$ = mk_node(NN_ExprPath, 1, $1); } +| SELF { $$ = mk_node(NN_ExprPath, 1, mk_empty_atom(NN_SELF)); } +| macro_expr { $$ = mk_node(NN_ExprMac, 1, $1); } +| expr_nostruct '?' { $$ = mk_node(NN_ExprTry, 1, $1); } +| expr_nostruct '.' path_generic_args_with_colons { $$ = mk_node(NN_ExprField, 2, $1, $3); } +| expr_nostruct '.' LIT_INTEGER { $$ = mk_node(NN_ExprTupleIndex, 1, $1); } +| expr_nostruct '[' maybe_expr ']' { $$ = mk_node(NN_ExprIndex, 2, $1, $3); } +| expr_nostruct '(' maybe_exprs ')' { $$ = mk_node(NN_ExprCall, 2, $1, $3); } +| '[' vec_expr ']' { $$ = mk_node(NN_ExprVec, 1, $2); } +| '(' maybe_exprs ')' { $$ = mk_node(NN_ExprParen, 1, $2); } +| CONTINUE { $$ = mk_node(NN_ExprAgain, 0); } +| CONTINUE ident { $$ = mk_node(NN_ExprAgain, 1, $2); } +| RETURN { $$ = mk_node(NN_ExprRet, 0); } +| RETURN expr { $$ = mk_node(NN_ExprRet, 1, $2); } +| BREAK { $$ = mk_node(NN_ExprBreak, 0); } +| BREAK ident { $$ = mk_node(NN_ExprBreak, 1, $2); } +| YIELD { $$ = mk_node(NN_ExprYield, 0); } +| YIELD expr { $$ = mk_node(NN_ExprYield, 1, $2); } +| expr_nostruct '=' expr_nostruct { $$ = mk_node(NN_ExprAssign, 2, $1, $3); } +| expr_nostruct SHLEQ expr_nostruct { $$ = mk_node(NN_ExprAssignShl, 2, $1, $3); } +| expr_nostruct SHREQ expr_nostruct { $$ = mk_node(NN_ExprAssignShr, 2, $1, $3); } +| expr_nostruct MINUSEQ expr_nostruct { $$ = mk_node(NN_ExprAssignSub, 2, $1, $3); } +| expr_nostruct ANDEQ expr_nostruct { $$ = mk_node(NN_ExprAssignBitAnd, 2, $1, $3); } +| expr_nostruct OREQ expr_nostruct { $$ = mk_node(NN_ExprAssignBitOr, 2, $1, $3); } +| expr_nostruct PLUSEQ expr_nostruct { $$ = mk_node(NN_ExprAssignAdd, 2, $1, $3); } +| expr_nostruct STAREQ expr_nostruct { $$ = mk_node(NN_ExprAssignMul, 2, $1, $3); } +| expr_nostruct SLASHEQ expr_nostruct { $$ = mk_node(NN_ExprAssignDiv, 2, $1, $3); } +| expr_nostruct CARETEQ expr_nostruct { $$ = mk_node(NN_ExprAssignBitXor, 2, $1, $3); } +| expr_nostruct PERCENTEQ expr_nostruct { $$ = mk_node(NN_ExprAssignRem, 2, $1, $3); } +| expr_nostruct OROR expr_nostruct { $$ = mk_node(NN_ExprBinary, 3, mk_empty_atom(NN_BiOr), $1, $3); } +| expr_nostruct ANDAND expr_nostruct { $$ = mk_node(NN_ExprBinary, 3, mk_empty_atom(NN_BiAnd), $1, $3); } +| expr_nostruct EQEQ expr_nostruct { $$ = mk_node(NN_ExprBinary, 3, mk_empty_atom(NN_BiEq), $1, $3); } +| expr_nostruct NE expr_nostruct { $$ = mk_node(NN_ExprBinary, 3, mk_empty_atom(NN_BiNe), $1, $3); } +| expr_nostruct '<' expr_nostruct { $$ = mk_node(NN_ExprBinary, 3, mk_empty_atom(NN_BiLt), $1, $3); } +| expr_nostruct '>' expr_nostruct { $$ = mk_node(NN_ExprBinary, 3, mk_empty_atom(NN_BiGt), $1, $3); } +| expr_nostruct LE expr_nostruct { $$ = mk_node(NN_ExprBinary, 3, mk_empty_atom(NN_BiLe), $1, $3); } +| expr_nostruct GE expr_nostruct { $$ = mk_node(NN_ExprBinary, 3, mk_empty_atom(NN_BiGe), $1, $3); } +| expr_nostruct '|' expr_nostruct { $$ = mk_node(NN_ExprBinary, 3, mk_empty_atom(NN_BiBitOr), $1, $3); } +| expr_nostruct '^' expr_nostruct { $$ = mk_node(NN_ExprBinary, 3, mk_empty_atom(NN_BiBitXor), $1, $3); } +| expr_nostruct '&' expr_nostruct { $$ = mk_node(NN_ExprBinary, 3, mk_empty_atom(NN_BiBitAnd), $1, $3); } +| expr_nostruct SHL expr_nostruct { $$ = mk_node(NN_ExprBinary, 3, mk_empty_atom(NN_BiShl), $1, $3); } +| expr_nostruct SHR expr_nostruct { $$ = mk_node(NN_ExprBinary, 3, mk_empty_atom(NN_BiShr), $1, $3); } +| expr_nostruct '+' expr_nostruct { $$ = mk_node(NN_ExprBinary, 3, mk_empty_atom(NN_BiAdd), $1, $3); } +| expr_nostruct '-' expr_nostruct { $$ = mk_node(NN_ExprBinary, 3, mk_empty_atom(NN_BiSub), $1, $3); } +| expr_nostruct '*' expr_nostruct { $$ = mk_node(NN_ExprBinary, 3, mk_empty_atom(NN_BiMul), $1, $3); } +| expr_nostruct '/' expr_nostruct { $$ = mk_node(NN_ExprBinary, 3, mk_empty_atom(NN_BiDiv), $1, $3); } +| expr_nostruct '%' expr_nostruct { $$ = mk_node(NN_ExprBinary, 3, mk_empty_atom(NN_BiRem), $1, $3); } +| expr_nostruct DOTDOT %prec RANGE { $$ = mk_node(NN_ExprRange, 2, $1, mk_none()); } +| expr_nostruct DOTDOT expr_nostruct { $$ = mk_node(NN_ExprRange, 2, $1, $3); } +| DOTDOT expr_nostruct { $$ = mk_node(NN_ExprRange, 2, mk_none(), $2); } +| DOTDOT { $$ = mk_node(NN_ExprRange, 2, mk_none(), mk_none()); } +| expr_nostruct AS ty { $$ = mk_node(NN_ExprCast, 2, $1, $3); } +| expr_nostruct ':' ty { $$ = mk_node(NN_ExprTypeAscr, 2, $1, $3); } +| BOX expr { $$ = mk_node(NN_ExprBox, 1, $2); } +| expr_qualified_path +| block_expr +| block +| nonblock_prefix_expr_nostruct +; + +nonblock_prefix_expr_nostruct +: '-' expr_nostruct { $$ = mk_node(NN_ExprUnary, 2, mk_empty_atom(NN_UnNeg), $2); } +| '!' expr_nostruct { $$ = mk_node(NN_ExprUnary, 2, mk_empty_atom(NN_UnNot), $2); } +| '*' expr_nostruct { $$ = mk_node(NN_ExprUnary, 2, mk_empty_atom(NN_UnDeref), $2); } +| '&' maybe_mut expr_nostruct { $$ = mk_node(NN_ExprAddrOf, 2, $2, $3); } +| ANDAND maybe_mut expr_nostruct { $$ = mk_node(NN_ExprAddrOf, 1, mk_node(NN_ExprAddrOf, 2, $2, $3)); } +| lambda_expr_nostruct +| MOVE lambda_expr_nostruct { $$ = $2; } +; + +nonblock_prefix_expr +: '-' expr { $$ = mk_node(NN_ExprUnary, 2, mk_empty_atom(NN_UnNeg), $2); } +| '!' expr { $$ = mk_node(NN_ExprUnary, 2, mk_empty_atom(NN_UnNot), $2); } +| '*' expr { $$ = mk_node(NN_ExprUnary, 2, mk_empty_atom(NN_UnDeref), $2); } +| '&' maybe_mut expr { $$ = mk_node(NN_ExprAddrOf, 2, $2, $3); } +| ANDAND maybe_mut expr { $$ = mk_node(NN_ExprAddrOf, 1, mk_node(NN_ExprAddrOf, 2, $2, $3)); } +| lambda_expr +| MOVE lambda_expr { $$ = $2; } +; + +expr_qualified_path +: '<' ty_sum maybe_as_trait_ref '>' MOD_SEP ident maybe_qpath_params +{ + $$ = mk_node(NN_ExprQualifiedPath, 4, $2, $3, $6, $7); +} +| SHL ty_sum maybe_as_trait_ref '>' MOD_SEP ident maybe_as_trait_ref '>' MOD_SEP ident +{ + $$ = mk_node(NN_ExprQualifiedPath, 3, mk_node(NN_ExprQualifiedPath, 3, $2, $3, $6), $7, $10); +} +| SHL ty_sum maybe_as_trait_ref '>' MOD_SEP ident generic_args maybe_as_trait_ref '>' MOD_SEP ident +{ + $$ = mk_node(NN_ExprQualifiedPath, 3, mk_node(NN_ExprQualifiedPath, 4, $2, $3, $6, $7), $8, $11); +} +| SHL ty_sum maybe_as_trait_ref '>' MOD_SEP ident maybe_as_trait_ref '>' MOD_SEP ident generic_args +{ + $$ = mk_node(NN_ExprQualifiedPath, 4, mk_node(NN_ExprQualifiedPath, 3, $2, $3, $6), $7, $10, $11); +} +| SHL ty_sum maybe_as_trait_ref '>' MOD_SEP ident generic_args maybe_as_trait_ref '>' MOD_SEP ident generic_args +{ + $$ = mk_node(NN_ExprQualifiedPath, 4, mk_node(NN_ExprQualifiedPath, 4, $2, $3, $6, $7), $8, $11, $12); +} + +maybe_qpath_params +: MOD_SEP generic_args { $$ = $2; } +| %empty { $$ = mk_none(); } +; + +maybe_as_trait_ref +: AS trait_ref { $$ = $2; } +| %empty { $$ = mk_none(); } +; + +lambda_expr +: %prec LAMBDA + OROR ret_ty expr { $$ = mk_node(NN_ExprFnBlock, 3, mk_none(), $2, $3); } +| %prec LAMBDA + '|' '|' ret_ty expr { $$ = mk_node(NN_ExprFnBlock, 3, mk_none(), $3, $4); } +| %prec LAMBDA + '|' inferrable_params '|' ret_ty expr { $$ = mk_node(NN_ExprFnBlock, 3, $2, $4, $5); } +| %prec LAMBDA + '|' inferrable_params OROR lambda_expr_no_first_bar { $$ = mk_node(NN_ExprFnBlock, 3, $2, mk_none(), $4); } +; + +lambda_expr_no_first_bar +: %prec LAMBDA + '|' ret_ty expr { $$ = mk_node(NN_ExprFnBlock, 3, mk_none(), $2, $3); } +| %prec LAMBDA + inferrable_params '|' ret_ty expr { $$ = mk_node(NN_ExprFnBlock, 3, $1, $3, $4); } +| %prec LAMBDA + inferrable_params OROR lambda_expr_no_first_bar { $$ = mk_node(NN_ExprFnBlock, 3, $1, mk_none(), $3); } +; + +lambda_expr_nostruct +: %prec LAMBDA + OROR expr_nostruct { $$ = mk_node(NN_ExprFnBlock, 2, mk_none(), $2); } +| %prec LAMBDA + '|' '|' ret_ty expr_nostruct { $$ = mk_node(NN_ExprFnBlock, 3, mk_none(), $3, $4); } +| %prec LAMBDA + '|' inferrable_params '|' expr_nostruct { $$ = mk_node(NN_ExprFnBlock, 2, $2, $4); } +| %prec LAMBDA + '|' inferrable_params OROR lambda_expr_nostruct_no_first_bar { $$ = mk_node(NN_ExprFnBlock, 3, $2, mk_none(), $4); } +; + +lambda_expr_nostruct_no_first_bar +: %prec LAMBDA + '|' ret_ty expr_nostruct { $$ = mk_node(NN_ExprFnBlock, 3, mk_none(), $2, $3); } +| %prec LAMBDA + inferrable_params '|' ret_ty expr_nostruct { $$ = mk_node(NN_ExprFnBlock, 3, $1, $3, $4); } +| %prec LAMBDA + inferrable_params OROR lambda_expr_nostruct_no_first_bar { $$ = mk_node(NN_ExprFnBlock, 3, $1, mk_none(), $3); } +; + +vec_expr +: maybe_exprs +| exprs ';' expr { $$ = mk_node(NN_VecRepeat, 2, $1, $3); } +; + +struct_expr_fields +: field_inits +| field_inits ',' +| maybe_field_inits default_field_init { $$ = ext_node($1, 1, $2); } +| %empty { $$ = mk_none(); } +; + +maybe_field_inits +: field_inits +| field_inits ',' +| %empty { $$ = mk_none(); } +; + +field_inits +: field_init { $$ = mk_node(NN_FieldInits, 1, $1); } +| field_inits ',' field_init { $$ = ext_node($1, 1, $3); } +; + +field_init +: ident { $$ = mk_node(NN_FieldInit, 1, $1); } +| ident ':' expr { $$ = mk_node(NN_FieldInit, 2, $1, $3); } +| LIT_INTEGER ':' expr { $$ = mk_node(NN_FieldInit, 2, mk_atom(NN_LitInteger, yytext), $3); } +; + +default_field_init +: DOTDOT expr { $$ = mk_node(NN_DefaultFieldInit, 1, $2); } +; + +block_expr +: expr_match +| expr_if +| expr_if_let +| expr_while +| expr_while_let +| expr_loop +| expr_for +| UNSAFE block { $$ = mk_node(NN_UnsafeBlock, 1, $2); } +| path_expr '!' maybe_ident braces_delimited_token_trees { $$ = mk_node(NN_Macro, 3, $1, $3, $4); } +; + +full_block_expr +: block_expr +| block_expr_dot +; + +block_expr_dot +: block_expr '.' path_generic_args_with_colons %prec IDENT { $$ = mk_node(NN_ExprField, 2, $1, $3); } +| block_expr_dot '.' path_generic_args_with_colons %prec IDENT { $$ = mk_node(NN_ExprField, 2, $1, $3); } +| block_expr '.' path_generic_args_with_colons '[' maybe_expr ']' { $$ = mk_node(NN_ExprIndex, 3, $1, $3, $5); } +| block_expr_dot '.' path_generic_args_with_colons '[' maybe_expr ']' { $$ = mk_node(NN_ExprIndex, 3, $1, $3, $5); } +| block_expr '.' path_generic_args_with_colons '(' maybe_exprs ')' { $$ = mk_node(NN_ExprCall, 3, $1, $3, $5); } +| block_expr_dot '.' path_generic_args_with_colons '(' maybe_exprs ')' { $$ = mk_node(NN_ExprCall, 3, $1, $3, $5); } +| block_expr '.' LIT_INTEGER { $$ = mk_node(NN_ExprTupleIndex, 1, $1); } +| block_expr_dot '.' LIT_INTEGER { $$ = mk_node(NN_ExprTupleIndex, 1, $1); } +; + +expr_match +: MATCH expr_nostruct '{' '}' { $$ = mk_node(NN_ExprMatch, 1, $2); } +| MATCH expr_nostruct '{' match_clauses '}' { $$ = mk_node(NN_ExprMatch, 2, $2, $4); } +| MATCH expr_nostruct '{' match_clauses nonblock_match_clause '}' { $$ = mk_node(NN_ExprMatch, 2, $2, ext_node($4, 1, $5)); } +| MATCH expr_nostruct '{' nonblock_match_clause '}' { $$ = mk_node(NN_ExprMatch, 2, $2, mk_node(NN_Arms, 1, $4)); } +; + +match_clauses +: match_clause { $$ = mk_node(NN_Arms, 1, $1); } +| match_clauses match_clause { $$ = ext_node($1, 1, $2); } +; + +match_clause +: nonblock_match_clause ',' +| block_match_clause +| block_match_clause ',' +; + +nonblock_match_clause +: maybe_outer_attrs pats_or maybe_guard FAT_ARROW nonblock_expr { $$ = mk_node(NN_ArmNonblock, 4, $1, $2, $3, $5); } +| maybe_outer_attrs pats_or maybe_guard FAT_ARROW block_expr_dot { $$ = mk_node(NN_ArmNonblock, 4, $1, $2, $3, $5); } +; + +block_match_clause +: maybe_outer_attrs pats_or maybe_guard FAT_ARROW block { $$ = mk_node(NN_ArmBlock, 4, $1, $2, $3, $5); } +| maybe_outer_attrs pats_or maybe_guard FAT_ARROW block_expr { $$ = mk_node(NN_ArmBlock, 4, $1, $2, $3, $5); } +; + +maybe_guard +: IF expr_nostruct { $$ = $2; } +| %empty { $$ = mk_none(); } +; + +expr_if +: IF expr_nostruct block { $$ = mk_node(NN_ExprIf, 2, $2, $3); } +| IF expr_nostruct block ELSE block_or_if { $$ = mk_node(NN_ExprIf, 3, $2, $3, $5); } +; + +expr_if_let +: IF LET pat '=' expr_nostruct block { $$ = mk_node(NN_ExprIfLet, 3, $3, $5, $6); } +| IF LET pat '=' expr_nostruct block ELSE block_or_if { $$ = mk_node(NN_ExprIfLet, 4, $3, $5, $6, $8); } +; + +block_or_if +: block +| expr_if +| expr_if_let +; + +expr_while +: maybe_label WHILE expr_nostruct block { $$ = mk_node(NN_ExprWhile, 3, $1, $3, $4); } +; + +expr_while_let +: maybe_label WHILE LET pat '=' expr_nostruct block { $$ = mk_node(NN_ExprWhileLet, 4, $1, $4, $6, $7); } +; + +expr_loop +: maybe_label LOOP block { $$ = mk_node(NN_ExprLoop, 2, $1, $3); } +; + +expr_for +: maybe_label FOR pat IN expr_nostruct block { $$ = mk_node(NN_ExprForLoop, 4, $1, $3, $5, $6); } +; + +maybe_label +: lifetime ':' +| %empty { $$ = mk_none(); } +; + +let +: LET pat maybe_ty_ascription maybe_init_expr ';' { $$ = mk_node(NN_DeclLocal, 3, $2, $3, $4); } +; + +//////////////////////////////////////////////////////////////////////// +// Part 5: Macros and misc. rules +//////////////////////////////////////////////////////////////////////// + +lit +: LIT_BYTE { $$ = mk_atom(NN_LitByte, yytext); } +| LIT_CHAR { $$ = mk_atom(NN_LitChar, yytext); } +| LIT_INTEGER { $$ = mk_atom(NN_LitInteger, yytext); } +| LIT_FLOAT { $$ = mk_atom(NN_LitFloat, yytext); } +| XTRUE { $$ = mk_atom(NN_LitBool, yytext); } +| XFALSE { $$ = mk_atom(NN_LitBool, yytext); } +| str +; + +str +: LIT_STR { $$ = mk_atom(NN_LIT_STR, yytext); } +| LIT_STR_RAW { $$ = mk_atom(NN_LIT_STR_RAW, yytext); } +| LIT_BYTE_STR { $$ = mk_atom(NN_LIT_BYTE_STR, yytext); } +| LIT_BYTE_STR_RAW { $$ = mk_atom(NN_LIT_BYTE_STR_RAW, yytext); } +; + +maybe_ident +: %empty { $$ = mk_none(); } +| ident +; + +ident +: IDENT { $$ = mk_node(NN_ident, 1, mk_atom(NN_IDENT, yytext)); } +// Weak keywords that can be used as identifiers +| CATCH { $$ = mk_node(NN_ident, 1, mk_atom(NN_CATCH, yytext)); } +| DEFAULT { $$ = mk_node(NN_ident, 1, mk_atom(NN_DEFAULT, yytext)); } +| UNION { $$ = mk_node(NN_ident, 1, mk_atom(NN_UNION, yytext)); } +; + +unpaired_token +: SHL { $$ = mk_empty_atom(NN_SHL); } +| SHR { $$ = mk_empty_atom(NN_SHR); } +| LE { $$ = mk_empty_atom(NN_LE); } +| EQEQ { $$ = mk_empty_atom(NN_EQEQ); } +| NE { $$ = mk_empty_atom(NN_NE); } +| GE { $$ = mk_empty_atom(NN_GE); } +| ANDAND { $$ = mk_empty_atom(NN_ANDAND); } +| OROR { $$ = mk_empty_atom(NN_OROR); } +| LARROW { $$ = mk_empty_atom(NN_LARROW); } +| SHLEQ { $$ = mk_empty_atom(NN_SHLEQ); } +| SHREQ { $$ = mk_empty_atom(NN_SHREQ); } +| MINUSEQ { $$ = mk_empty_atom(NN_MINUSEQ); } +| ANDEQ { $$ = mk_empty_atom(NN_ANDEQ); } +| OREQ { $$ = mk_empty_atom(NN_OREQ); } +| PLUSEQ { $$ = mk_empty_atom(NN_PLUSEQ); } +| STAREQ { $$ = mk_empty_atom(NN_STAREQ); } +| SLASHEQ { $$ = mk_empty_atom(NN_SLASHEQ); } +| CARETEQ { $$ = mk_empty_atom(NN_CARETEQ); } +| PERCENTEQ { $$ = mk_empty_atom(NN_PERCENTEQ); } +| DOTDOT { $$ = mk_empty_atom(NN_DOTDOT); } +| DOTDOTDOT { $$ = mk_empty_atom(NN_DOTDOTDOT); } +| MOD_SEP { $$ = mk_empty_atom(NN_MOD_SEP); } +| RARROW { $$ = mk_empty_atom(NN_RARROW); } +| FAT_ARROW { $$ = mk_empty_atom(NN_FAT_ARROW); } +| LIT_BYTE { $$ = mk_atom(NN_LIT_BYTE, yytext); } +| LIT_CHAR { $$ = mk_atom(NN_LIT_CHAR, yytext); } +| LIT_INTEGER { $$ = mk_atom(NN_LIT_INTEGER, yytext); } +| LIT_FLOAT { $$ = mk_atom(NN_LIT_FLOAT, yytext); } +| LIT_STR { $$ = mk_atom(NN_LIT_STR, yytext); } +| LIT_STR_RAW { $$ = mk_atom(NN_LIT_STR_RAW, yytext); } +| LIT_BYTE_STR { $$ = mk_atom(NN_LIT_BYTE_STR, yytext); } +| LIT_BYTE_STR_RAW { $$ = mk_atom(NN_LIT_BYTE_STR_RAW, yytext); } +| IDENT { $$ = mk_atom(NN_IDENT, yytext); } +| UNDERSCORE { $$ = mk_empty_atom(NN_UNDERSCORE); } +| LIFETIME { $$ = mk_empty_atom(NN_LIFETIME); } +| SELF { $$ = mk_empty_atom(NN_SELF); } +| STATIC { $$ = mk_empty_atom(NN_STATIC); } +| ABSTRACT { $$ = mk_empty_atom(NN_ABSTRACT); } +| ALIGNOF { $$ = mk_empty_atom(NN_ALIGNOF); } +| AS { $$ = mk_empty_atom(NN_AS); } +| BECOME { $$ = mk_empty_atom(NN_BECOME); } +| BREAK { $$ = mk_empty_atom(NN_BREAK); } +| CATCH { $$ = mk_empty_atom(NN_CATCH); } +| CRATE { $$ = mk_empty_atom(NN_CRATE); } +| DEFAULT { $$ = mk_empty_atom(NN_DEFAULT); } +| DO { $$ = mk_empty_atom(NN_DO); } +| ELSE { $$ = mk_empty_atom(NN_ELSE); } +| ENUM { $$ = mk_empty_atom(NN_ENUM); } +| EXTERN { $$ = mk_empty_atom(NN_EXTERN); } +| XFALSE { $$ = mk_empty_atom(NN_XFALSE); } +| FINAL { $$ = mk_empty_atom(NN_FINAL); } +| FN { $$ = mk_empty_atom(NN_FN); } +| FOR { $$ = mk_empty_atom(NN_FOR); } +| IF { $$ = mk_empty_atom(NN_IF); } +| IMPL { $$ = mk_empty_atom(NN_IMPL); } +| IN { $$ = mk_empty_atom(NN_IN); } +| LET { $$ = mk_empty_atom(NN_LET); } +| LOOP { $$ = mk_empty_atom(NN_LOOP); } +| MACRO { $$ = mk_empty_atom(NN_MACRO); } +| MATCH { $$ = mk_empty_atom(NN_MATCH); } +| MOD { $$ = mk_empty_atom(NN_MOD); } +| MOVE { $$ = mk_empty_atom(NN_MOVE); } +| MUT { $$ = mk_empty_atom(NN_MUT); } +| OFFSETOF { $$ = mk_empty_atom(NN_OFFSETOF); } +| OVERRIDE { $$ = mk_empty_atom(NN_OVERRIDE); } +| PRIV { $$ = mk_empty_atom(NN_PRIV); } +| PUB { $$ = mk_empty_atom(NN_PUB); } +| PURE { $$ = mk_empty_atom(NN_PURE); } +| REF { $$ = mk_empty_atom(NN_REF); } +| RETURN { $$ = mk_empty_atom(NN_RETURN); } +| STRUCT { $$ = mk_empty_atom(NN_STRUCT); } +| SIZEOF { $$ = mk_empty_atom(NN_SIZEOF); } +| SUPER { $$ = mk_empty_atom(NN_SUPER); } +| XTRUE { $$ = mk_empty_atom(NN_XTRUE); } +| TRAIT { $$ = mk_empty_atom(NN_TRAIT); } +| TYPE { $$ = mk_empty_atom(NN_TYPE); } +| UNION { $$ = mk_empty_atom(NN_UNION); } +| UNSAFE { $$ = mk_empty_atom(NN_UNSAFE); } +| UNSIZED { $$ = mk_empty_atom(NN_UNSIZED); } +| USE { $$ = mk_empty_atom(NN_USE); } +| VIRTUAL { $$ = mk_empty_atom(NN_VIRTUAL); } +| WHILE { $$ = mk_empty_atom(NN_WHILE); } +| YIELD { $$ = mk_empty_atom(NN_YIELD); } +| CONTINUE { $$ = mk_empty_atom(NN_CONTINUE); } +| PROC { $$ = mk_empty_atom(NN_PROC); } +| BOX { $$ = mk_empty_atom(NN_BOX); } +| CONST { $$ = mk_empty_atom(NN_CONST); } +| WHERE { $$ = mk_empty_atom(NN_WHERE); } +| TYPEOF { $$ = mk_empty_atom(NN_TYPEOF); } +| INNER_DOC_COMMENT { $$ = mk_empty_atom(NN_INNER_DOC_COMMENT); } +| OUTER_DOC_COMMENT { $$ = mk_empty_atom(NN_OUTER_DOC_COMMENT); } +| SHEBANG { $$ = mk_empty_atom(NN_SHEBANG); } +| STATIC_LIFETIME { $$ = mk_empty_atom(NN_STATIC_LIFETIME); } +| ';' { $$ = mk_empty_atom(NN_SEMI_COLON); } +| ',' { $$ = mk_empty_atom(NN_COMMA); } +| '.' { $$ = mk_empty_atom(NN_SINGLE_DOT); } +| '@' { $$ = mk_empty_atom(NN_AT); } +| '#' { $$ = mk_empty_atom(NN_HASH); } +| '~' { $$ = mk_empty_atom(NN_TILDA); } +| ':' { $$ = mk_empty_atom(NN_COLON); } +| '$' { $$ = mk_empty_atom(NN_DOLLAR); } +| '=' { $$ = mk_empty_atom(NN_EQUALS); } +| '?' { $$ = mk_empty_atom(NN_QUESTION); } +| '!' { $$ = mk_empty_atom(NN_EXCLAIM); } +| '<' { $$ = mk_empty_atom(NN_LESS_THAN); } +| '>' { $$ = mk_empty_atom(NN_GREATER_THAN); } +| '-' { $$ = mk_empty_atom(NN_MINUS); } +| '&' { $$ = mk_empty_atom(NN_AMPERSAND); } +| '|' { $$ = mk_empty_atom(NN_PIPE); } +| '+' { $$ = mk_empty_atom(NN_PLUS); } +| '*' { $$ = mk_empty_atom(NN_MULT); } +| '/' { $$ = mk_empty_atom(NN_DIVIDE); } +| '^' { $$ = mk_empty_atom(NN_HAT); } +| '%' { $$ = mk_empty_atom(NN_PERCENTAGE); } +; + +token_trees +: %empty { $$ = mk_node(NN_TokenTrees, 0); } +| token_trees token_tree { $$ = ext_node($1, 1, $2); } +; + +token_tree +: delimited_token_trees +| unpaired_token { $$ = mk_node(NN_TTTok, 1, $1); } +; + +delimited_token_trees +: parens_delimited_token_trees +| braces_delimited_token_trees +| brackets_delimited_token_trees +; + +parens_delimited_token_trees +: '(' token_trees ')' +{ + $$ = mk_node(NN_TTDelim, 1, $2); +} +; + +braces_delimited_token_trees +: '{' token_trees '}' +{ + $$ = mk_node(NN_TTDelim, 1, $2); +} +; + +brackets_delimited_token_trees +: '[' token_trees ']' +{ + $$ = mk_node(NN_TTDelim, 1, $2); +} +; + +%% + +void yyerror (const char* msg) +{ + fatal_error (UNKNOWN_LOCATION, "%s at line %i\n", msg, yylineno); +} diff --git a/gcc/rust/rustfrontend/rustly.cc b/gcc/rust/rustfrontend/rustly.cc new file mode 100644 index 0000000..eb14194 --- /dev/null +++ b/gcc/rust/rustfrontend/rustly.cc @@ -0,0 +1,83 @@ +#include "rustly.h" +#include "node.h" + +extern FILE* yyin; +static Rustly* rustly; + + +Rustly::Rustly (bool only_check_syntax, Linemap* linemap) + : mSyntaxOnly(only_check_syntax), + mLinemap(linemap) +{ + +} + +Rustly::~Rustly () +{ + +} + +void Rustly::parse_input_files (size_t n, const char** in) +{ + int verbose = 1; + parser_init(verbose); + + int ret = 0; + + size_t i; + for (i = 0; i < n; ++i) + { + yyin = fopen(in[i], "rb"); + if (yyin == NULL) { + fatal_error(UNKNOWN_LOCATION, "FAILED TO OPEN %s", in[i]); + return; + } + + ret = yyparse(); + } + + + printf("--- PARSE COMPLETE: ret:%d, n_nodes:%d ---\n", ret, n_nodes); + if (nodes) { + print_node(nodes, 0); + } + + // FIXME double-free exists here + // struct node *tmp; + // while (nodes) { + // tmp = nodes; + // nodes = tmp->next; + // if (tmp->own_string) { + // free((void*)tmp->name); + // } + // free(tmp); + // } + + if (mSyntaxOnly) + return; + + + // do type inferance + + // convert to GENERIC tree's +} + + +void Rustly::do_compile() +{ + // TODO +} + +// C INTERFACE THIS NEEDS CLEANUP AT SOMEPOINT + +void +rust_create_rustly(bool only_check_syntax, Linemap* linemap) +{ + rustly = new Rustly(only_check_syntax, linemap); +} + +void +rust_parse_input_files (const char** in, unsigned int n) +{ + rustly->parse_input_files(n, in); +} diff --git a/gcc/rust/rustfrontend/rustly.h b/gcc/rust/rustfrontend/rustly.h new file mode 100644 index 0000000..db7455f --- /dev/null +++ b/gcc/rust/rustfrontend/rustly.h @@ -0,0 +1,26 @@ +#pragma once + +#include "rust-linemap.h" +#include "rust-system.h" +#include "rust-c.h" + +#include "rs-parser.h" +#include "node.h" + +class Rustly +{ +public: + Rustly(bool only_check_syntax, Linemap* mLinemap); + + ~Rustly(); + + void parse_input_files (size_t n, const char** in); + + void do_compile(); + +private: + bool mSyntaxOnly; + Linemap* mLinemap; +}; + + diff --git a/gcc/rust/rustspec.cc b/gcc/rust/rustspec.cc index f83705f..101237d 100644 --- a/gcc/rust/rustspec.cc +++ b/gcc/rust/rustspec.cc @@ -44,7 +44,10 @@ along with GCC; see the file COPYING3. If not see #define THREAD_LIBRARY "pthread" #define THREAD_LIBRARY_PROFILE THREAD_LIBRARY +<<<<<<< HEAD // Refers to compiler driver: handles calling the compiler (i.e. options, libraries to use) +======= +>>>>>>> c611d209696bd5983b4b777be0beea80351dee46 void lang_specific_driver (struct cl_decoded_option **in_decoded_options, unsigned int *in_decoded_options_count, diff --git a/gcc/rust/test/test1..s b/gcc/rust/test/test1..s new file mode 100644 index 0000000..32e351a --- /dev/null +++ b/gcc/rust/test/test1..s @@ -0,0 +1 @@ + .file "test1." diff --git a/gcc/rust/test/test1.rs b/gcc/rust/test/test1.rs new file mode 100644 index 0000000..e6cfaae --- /dev/null +++ b/gcc/rust/test/test1.rs @@ -0,0 +1,4 @@ +fn main() { + let x = 1; + let y = x; +} diff --git a/gcc/rust/test/test1.s b/gcc/rust/test/test1.s new file mode 100644 index 0000000..d3126f9 --- /dev/null +++ b/gcc/rust/test/test1.s @@ -0,0 +1,17 @@ + .file "test1.rs" + .text +.Ltext0: + .section .note.GNU-split-stack,"",@progbits + .text +.Letext0: + .section .debug_line,"",@progbits +.Ldebug_line0: + .section .debug_str,"MS",@progbits,1 +.LASF0: + .string "../gccrs/gcc/rust/test/test1.rs" +.LASF1: + .string "/home/redbrain/workspace/gccrs-build" +.LASF2: + .string "GNU Rust 10.0.0 20191127 (experimental) -O0" + .ident "GCC: (GNU) 10.0.0 20191127 (experimental)" + .section .note.GNU-stack,"",@progbits diff --git a/gcc/rust/test/test2-minimal.rs b/gcc/rust/test/test2-minimal.rs new file mode 100644 index 0000000..3999215 --- /dev/null +++ b/gcc/rust/test/test2-minimal.rs @@ -0,0 +1,25 @@ +macro_rules! println { + () => { ... }; + ($($arg:tt)*) => { ... }; +} + +// if macro stuff is commented out, parses fine. +// if everything but macro stuff is commented out, segfault. so segfault occurs due to macro stuff + +// Function that returns a boolean value +/*fn is_divisible_by(lhs: u32, rhs: u32) -> bool { + // Corner case, early return + if rhs == 0 { + return false; + } + + // This is an expression, the `return` keyword is not necessary here + lhs % rhs == 0 +} + + + +fn main() { + let mut x = is_divisible(3, 12); +}*/ + diff --git a/gcc/rust/test/test2.rs b/gcc/rust/test/test2.rs new file mode 100644 index 0000000..976f1f3 --- /dev/null +++ b/gcc/rust/test/test2.rs @@ -0,0 +1,18 @@ + +// Function that returns a boolean value +fn is_divisible_by(lhs: u32, rhs: u32) -> bool { + // Corner case, early return + if rhs == 0 { + return false; + } + + // This is an expression, the `return` keyword is not necessary here + lhs % rhs == 0 +} + + + +fn main() { + let mut x:i32 = is_divisible(3, 12); +} + diff --git a/gcc/rust/test/test2.s b/gcc/rust/test/test2.s new file mode 100644 index 0000000..75ff5c4 --- /dev/null +++ b/gcc/rust/test/test2.s @@ -0,0 +1,17 @@ + .file "test2.rs" + .text +.Ltext0: + .section .note.GNU-split-stack,"",@progbits + .text +.Letext0: + .section .debug_line,"",@progbits +.Ldebug_line0: + .section .debug_str,"MS",@progbits,1 +.LASF0: + .string "/home/redbrain/workspace/gccrs-build" +.LASF1: + .string "../gccrs/gcc/rust/test/test2.rs" +.LASF2: + .string "GNU Rust 10.0.0 20191127 (experimental)" + .ident "GCC: (GNU) 10.0.0 20191127 (experimental)" + .section .note.GNU-stack,"",@progbits diff --git a/gcc/rust/test3/Make-lang.in b/gcc/rust/test3/Make-lang.in index 4d4e331..36d908c 100644 --- a/gcc/rust/test3/Make-lang.in +++ b/gcc/rust/test3/Make-lang.in @@ -77,6 +77,7 @@ GRS_OBJS = \ rust/rust-scope.o \ rust/rust-misc-convert.o \ rust/rust-ast-full-test.o \ + rust/rust-session-manager.o \ $(END) # removed object files from here @@ -219,6 +220,7 @@ RUST_INCLUDES = -I $(srcdir)/rust -I $(srcdir)/rust/lex -I $(srcdir)/rust/parse CFLAGS-rust/rust-lang.o += $(RUST_INCLUDES) CFLAGS-rust/rust-lex.o += $(RUST_INCLUDES) CFLAGS-rust/rust-parse.o += $(RUST_INCLUDES) +CFLAGS-rust/rust-session-manager.o += $(RUST_INCLUDES) # TODO: possibly find a way to ensure C++11 compilation level here? diff --git a/gcc/rust/test3/ast/rust-ast-full-decls.h b/gcc/rust/test3/ast/rust-ast-full-decls.h new file mode 100644 index 0000000..a76a599 --- /dev/null +++ b/gcc/rust/test3/ast/rust-ast-full-decls.h @@ -0,0 +1,265 @@ +#ifndef RUST_AST_FULL_DECLS_H +#define RUST_AST_FULL_DECLS_H +// Forward declarations for all AST classes. Useful for not having to include all definitions. + +namespace Rust { + namespace AST { + // rust-ast.h + class AttrInput; + class TokenTree; + class MacroMatch; + class Token; + struct Literal; + class DelimTokenTree; + class PathSegment; + class SimplePathSegment; + class SimplePath; + struct Attribute; + class MetaItemInner; + class AttrInputMetaItemContainer; + class MetaItem; + class Stmt; + class Item; + class Expr; + class ExprWithoutBlock; + class IdentifierExpr; + class Pattern; + class Type; + class TypeNoBounds; + class TypeParamBound; + class Lifetime; + class GenericParam; + class LifetimeParam; + class MacroItem; + class TraitItem; + class InherentImplItem; + class TraitImplItem; + class MacroInvocationSemi; + struct Crate; + class PathExpr; + + // rust-path.h + class PathIdentSegment; + struct GenericArgsBinding; + struct GenericArgs; + class PathExprSegment; + class PathPattern; + class PathInExpression; + class TypePathSegment; + class TypePathSegmentGeneric; + struct TypePathFunction; + class TypePathSegmentFunction; + class TypePath; + struct QualifiedPathType; + class QualifiedPathInExpression; + class QualifiedPathInType; + + // rust-expr.h + class ExprWithBlock; + class LiteralExpr; + class AttrInputLiteral; + class MetaItemLitExpr; + class MetaItemPathLit; + class OperatorExpr; + class BorrowExpr; + class DereferenceExpr; + class ErrorPropagationExpr; + class NegationExpr; + class ArithmeticOrLogicalExpr; + class ComparisonExpr; + class LazyBooleanExpr; + class TypeCastExpr; + class AssignmentExpr; + class CompoundAssignmentExpr; + class GroupedExpr; + class ArrayElems; + class ArrayElemsValues; + class ArrayElemsCopied; + class ArrayExpr; + class ArrayIndexExpr; + class TupleExpr; + class TupleIndexExpr; + class StructExpr; + class StructExprStruct; + struct StructBase; + class StructExprField; + class StructExprFieldIdentifier; + class StructExprFieldWithVal; + class StructExprFieldIdentifierValue; + class StructExprFieldIndexValue; + class StructExprStructFields; + class StructExprStructBase; + class StructExprTuple; + class StructExprUnit; + class EnumVariantExpr; + class EnumExprField; + class EnumExprFieldIdentifier; + class EnumExprFieldWithVal; + class EnumExprFieldIdentifierValue; + class EnumExprFieldIndexValue; + class EnumExprStruct; + class EnumExprTuple; + class EnumExprFieldless; + class CallExpr; + class MethodCallExpr; + class FieldAccessExpr; + struct ClosureParam; + class ClosureExpr; + class ClosureExprInner; + class BlockExpr; + class ClosureExprInnerTyped; + class ContinueExpr; + class BreakExpr; + class RangeExpr; + class RangeFromToExpr; + class RangeFromExpr; + class RangeToExpr; + class RangeFullExpr; + class RangeFromToInclExpr; + class RangeToInclExpr; + class ReturnExpr; + class UnsafeBlockExpr; + class LoopLabel; + class BaseLoopExpr; + class LoopExpr; + class WhileLoopExpr; + class WhileLetLoopExpr; + class ForLoopExpr; + class IfExpr; + class IfExprConseqElse; + class IfExprConseqIf; + class IfLetExpr; + class IfExprConseqIfLet; + class IfLetExprConseqElse; + class IfLetExprConseqIf; + class IfLetExprConseqIfLet; + struct MatchArm; + class MatchCase; + class MatchCaseBlockExpr; + class MatchCaseExpr; + class MatchExpr; + class AwaitExpr; + class AsyncBlockExpr; + + // rust-stmt.h + class EmptyStmt; + class LetStmt; + class ExprStmt; + class ExprStmtWithoutBlock; + class ExprStmtWithBlock; + + // rust-item.h + class TypeParam; + class WhereClauseItem; + class LifetimeWhereClauseItem; + class TypeBoundWhereClauseItem; + struct WhereClause; + struct SelfParam; + struct FunctionQualifiers; + struct FunctionParam; + struct Visibility; + class Method; + class VisItem; + class Module; + class ModuleBodied; + class ModuleNoBody; + class ExternCrate; + class UseTree; + class UseTreeGlob; + class UseTreeList; + class UseTreeRebind; + class UseDeclaration; + class Function; + class TypeAlias; + class Struct; + struct StructField; + class StructStruct; + struct TupleField; + class TupleStruct; + class EnumItem; + class EnumItemTuple; + class EnumItemStruct; + class EnumItemDiscriminant; + class Enum; + class Union; + class ConstantItem; + class StaticItem; + struct TraitFunctionDecl; + class TraitItemFunc; + struct TraitMethodDecl; + class TraitItemMethod; + class TraitItemConst; + class TraitItemType; + class Trait; + class Impl; + class InherentImpl; + class TraitImpl; + class ExternalItem; + class ExternalStaticItem; + struct NamedFunctionParam; + class ExternalFunctionItem; + class ExternBlock; + + // rust-macro.h + class MacroMatchFragment; + class MacroMatchRepetition; + class MacroMatcher; + struct MacroTranscriber; + struct MacroRule; + class MacroRulesDefinition; + class MacroInvocation; + class MetaItemPath; + class MetaItemSeq; + class MetaWord; + class MetaNameValueStr; + class MetaListPaths; + class MetaListNameValueStr; + + // rust-pattern.h + class LiteralPattern; + class IdentifierPattern; + class WildcardPattern; + class RangePatternBound; + class RangePatternBoundLiteral; + class RangePatternBoundPath; + class RangePatternBoundQualPath; + class RangePattern; + class ReferencePattern; + struct StructPatternEtc; + class StructPatternField; + class StructPatternFieldTuplePat; + class StructPatternFieldIdentPat; + class StructPatternFieldIdent; + struct StructPatternElements; + class StructPattern; + class TupleStructItems; + class TupleStructItemsNoRange; + class TupleStructItemsRange; + class TupleStructPattern; + class TuplePatternItems; + class TuplePatternItemsMultiple; + class TuplePatternItemsRanged; + class TuplePattern; + class GroupedPattern; + class SlicePattern; + + // rust-type.h + class TraitBound; + class ImplTraitType; + class TraitObjectType; + class ParenthesisedType; + class ImplTraitTypeOneBound; + class TraitObjectTypeOneBound; + class TupleType; + class NeverType; + class RawPointerType; + class ReferenceType; + class ArrayType; + class SliceType; + class InferredType; + struct MaybeNamedParam; + class BareFunctionType; + } +} + +#endif
\ No newline at end of file diff --git a/gcc/rust/test3/ast/rust-ast-full-test.cc b/gcc/rust/test3/ast/rust-ast-full-test.cc index 9afa95b..6eb48cc 100644 --- a/gcc/rust/test3/ast/rust-ast-full-test.cc +++ b/gcc/rust/test3/ast/rust-ast-full-test.cc @@ -1,9 +1,70 @@ #include "rust-ast-full.h" -// Dummy implementations of as_string() for now - will complete later for debugging purposes +#include "diagnostic.h" + +#include "rust-ast-visitor.h" + +#include "rust-session-manager.h" + +/* Compilation unit used for various AST-related functions that would make the headers too long if + * they were defined inline and don't receive any benefits from being defined inline because they are + * virtual. Also used for various other stuff. */ namespace Rust { namespace AST { + // Gets a string in a certain delim type. + ::std::string get_string_in_delims(::std::string str_input, DelimType delim_type) { + switch (delim_type) { + case PARENS: + return "(" + str_input + ")"; + case SQUARE: + return "[" + str_input + "]"; + case CURLY: + return "{" + str_input + "}"; + default: + return "ERROR-MARK-STRING (delims)"; + } + gcc_unreachable(); + } + + // Converts a frag spec enum item to a string form. + ::std::string frag_spec_to_str(MacroFragSpec frag_spec) { + switch (frag_spec) { + case BLOCK: + return "block"; + case EXPR: + return "expr"; + case IDENT: + return "ident"; + case ITEM: + return "item"; + case LIFETIME: + return "lifetime"; + case LITERAL: + return "literal"; + case META: + return "meta"; + case PAT: + return "pat"; + case PATH: + return "path"; + case STMT: + return "stmt"; + case TT: + return "tt"; + case TY: + return "ty"; + case VIS: + return "vis"; + case INVALID: + return "INVALID_FRAG_SPEC"; + default: + return "ERROR_MARK_STRING - unknown frag spec"; + } + } + ::std::string Crate::as_string() const { + fprintf(stderr, "beginning crate recursive as-string\n"); + ::std::string str("Crate: "); // add utf8bom and shebang if (has_utf8bom) { @@ -30,6 +91,13 @@ namespace Rust { str += "none"; } else { for (const auto& item : items) { + // DEBUG: null pointer check + if (item == NULL) { + fprintf(stderr, + "something really terrible has gone wrong - null pointer item in crate."); + return "NULL_POINTER_MARK"; + } + str += "\n " + item->as_string(); } } @@ -71,6 +139,13 @@ namespace Rust { str += "none"; } else { for (const auto& tree : token_trees) { + // DEBUG: null pointer check + if (tree == NULL) { + fprintf(stderr, "something really terrible has gone wrong - null pointer " + "token tree in delim token tree."); + return "NULL_POINTER_MARK"; + } + str += tree->as_string() + ", "; } } @@ -82,7 +157,7 @@ namespace Rust { ::std::string Token::as_string() const { /* FIXME: only works when not identifier or literal or whatever, i.e. when doesn't store * string value */ - //return get_token_description(token_id); + // return get_token_description(token_id); // maybe fixed - stores everything as string though, so storage-inefficient return str; @@ -110,7 +185,10 @@ namespace Rust { // DEBUG: remove later. Checks for path error. if (segment.is_error()) { - fprintf(stderr, "segment in path is error - this should've been filtered out. first segment was '%s' \n", segments.at(0).as_string().c_str()); + fprintf(stderr, + "segment in path is error - this should've been filtered out. first segment " + "was '%s' \n", + segments.at(0).as_string().c_str()); } } @@ -136,7 +214,7 @@ namespace Rust { // Creates a string that reflects the visibility stored. ::std::string VisItem::as_string() const { - // FIXME: can't do formatting on string to make identation occur. + // FIXME: can't do formatting on string to make identation occur. ::std::string str = Item::as_string(); if (has_visibility()) { @@ -149,7 +227,7 @@ namespace Rust { // Creates a string that reflects the outer attributes stored. ::std::string Item::as_string() const { ::std::string str; - + if (!outer_attrs.empty()) { for (const auto& attr : outer_attrs) { str += attr.as_string() + "\n"; @@ -159,43 +237,327 @@ namespace Rust { return str; } - ::std::string ModuleBodied::as_string() const { + ::std::string Module::as_string() const { ::std::string vis_item = VisItem::as_string(); - return ::std::string("not implemented"); + return vis_item + "mod " + module_name; + } + + ::std::string ModuleBodied::as_string() const { + // get module string for "[vis] mod [name]" + ::std::string str = Module::as_string(); + + // inner attributes + str += "\n inner attributes: "; + if (inner_attrs.empty()) { + str += "none"; + } else { + // note that this does not print them with "inner attribute" syntax - just the body + for (const auto& attr : inner_attrs) { + str += "\n " + attr.as_string(); + } + } + + // items + str += "\n items: "; + if (items.empty()) { + str += "none"; + } else { + for (const auto& item : items) { + // DEBUG: null pointer check + if (item == NULL) { + fprintf(stderr, + "something really terrible has gone wrong - null pointer item in crate."); + return "NULL_POINTER_MARK"; + } + + str += "\n " + item->as_string(); + } + } + + return str + "\n"; } ::std::string ModuleNoBody::as_string() const { - return ::std::string("not implemented"); + ::std::string str = Module::as_string(); + + str += "\n no body (reference to external file)"; + + return str + "\n"; } ::std::string StaticItem::as_string() const { - return ::std::string("not implemented"); + ::std::string str = VisItem::as_string(); + + str += "static"; + + if (has_mut) { + str += " mut"; + } + + str += name; + + // DEBUG: null pointer check + if (type == NULL) { + fprintf(stderr, + "something really terrible has gone wrong - null pointer type in static item."); + return "NULL_POINTER_MARK"; + } + str += "\n Type: " + type->as_string(); + + // DEBUG: null pointer check + if (expr == NULL) { + fprintf(stderr, + "something really terrible has gone wrong - null pointer expr in static item."); + return "NULL_POINTER_MARK"; + } + str += "\n Expression: " + expr->as_string(); + + return str + "\n"; } ::std::string ExternCrate::as_string() const { - return ::std::string("not implemented"); + ::std::string str = VisItem::as_string(); + + str += "extern crate " + referenced_crate; + + if (has_as_clause()) { + str += " as " + as_clause_name; + } + + return str; } ::std::string TupleStruct::as_string() const { - return ::std::string("not implemented"); + ::std::string str = VisItem::as_string(); + + str += "struct " + struct_name; + + // generic params + str += "\n Generic params: "; + if (generic_params.empty()) { + str += "none"; + } else { + for (const auto& param : generic_params) { + // DEBUG: null pointer check + if (param == NULL) { + fprintf(stderr, "something really terrible has gone wrong - null pointer " + "generic param in enum."); + return "NULL_POINTER_MARK"; + } + + str += "\n " + param->as_string(); + } + } + + // tuple fields + str += "\n Tuple fields: "; + if (fields.empty()) { + str += "none"; + } else { + for (const auto& field : fields) { + str += "\n " + field.as_string(); + } + } + + str += "\n Where clause: "; + if (has_where_clause()) { + str += where_clause.as_string(); + } else { + str += "none"; + } + + return str; } ::std::string ConstantItem::as_string() const { - return ::std::string("not implemented"); + ::std::string str = VisItem::as_string(); + + str += "const " + identifier; + + // DEBUG: null pointer check + if (type == NULL) { + fprintf(stderr, + "something really terrible has gone wrong - null pointer type in const item."); + return "NULL_POINTER_MARK"; + } + str += "\n Type: " + type->as_string(); + + // DEBUG: null pointer check + if (const_expr == NULL) { + fprintf(stderr, + "something really terrible has gone wrong - null pointer expr in const item."); + return "NULL_POINTER_MARK"; + } + str += "\n Expression: " + const_expr->as_string(); + + return str + "\n"; } ::std::string InherentImpl::as_string() const { - return ::std::string("not implemented"); + ::std::string str = VisItem::as_string(); + + str += "impl "; + + // generic params + str += "\n Generic params: "; + if (generic_params.empty()) { + str += "none"; + } else { + for (const auto& param : generic_params) { + // DEBUG: null pointer check + if (param == NULL) { + fprintf(stderr, "something really terrible has gone wrong - null pointer " + "generic param in inherent impl."); + return "NULL_POINTER_MARK"; + } + + str += "\n " + param->as_string(); + } + } + + str += "\n Type: " + trait_type->as_string(); + + str += "\n Where clause: "; + if (has_where_clause()) { + str += where_clause.as_string(); + } else { + str += "none"; + } + + // inner attributes + str += "\n inner attributes: "; + if (inner_attrs.empty()) { + str += "none"; + } else { + // note that this does not print them with "inner attribute" syntax - just the body + for (const auto& attr : inner_attrs) { + str += "\n " + attr.as_string(); + } + } + + // inherent impl items + str += "\n Inherent impl items: "; + if (!has_impl_items()) { + str += "none"; + } else { + for (const auto& item : impl_items) { + str += "\n " + item->as_string(); + } + } + + return str; + } + + ::std::string Method::as_string() const { + ::std::string str("Method: \n "); + + str += vis.as_string() + " " + qualifiers.as_string(); + + str += " fn " + method_name; + + // generic params + str += "\n Generic params: "; + if (generic_params.empty()) { + str += "none"; + } else { + for (const auto& param : generic_params) { + // DEBUG: null pointer check + if (param == NULL) { + fprintf(stderr, "something really terrible has gone wrong - null pointer " + "generic param in method."); + return "NULL_POINTER_MARK"; + } + + str += "\n " + param->as_string(); + } + } + + str += "\n Self param: " + self_param.as_string(); + + str += "\n Function params: "; + if (function_params.empty()) { + str += "none"; + } else { + for (const auto& param : function_params) { + str += "\n " + param.as_string(); + } + } + + str += "\n Return type: "; + if (has_return_type()) { + str += return_type->as_string(); + } else { + str += "none (void)"; + } + + str += "\n Where clause: "; + if (has_where_clause()) { + str += where_clause.as_string(); + } else { + str += "none"; + } + + str += "\n Block expr (body): \n "; + str += expr->as_string(); + + return str; } ::std::string StructStruct::as_string() const { - return ::std::string("not implemented"); + ::std::string str = VisItem::as_string(); + + str += "struct " + struct_name; + + // generic params + str += "\n Generic params: "; + if (generic_params.empty()) { + str += "none"; + } else { + for (const auto& param : generic_params) { + // DEBUG: null pointer check + if (param == NULL) { + fprintf(stderr, "something really terrible has gone wrong - null pointer " + "generic param in enum."); + return "NULL_POINTER_MARK"; + } + + str += "\n " + param->as_string(); + } + } + + str += "\n Where clause: "; + if (has_where_clause()) { + str += where_clause.as_string(); + } else { + str += "none"; + } + + // struct fields + str += "\n Struct fields: "; + if (is_unit) { + str += "none (unit)"; + } else if (fields.empty()) { + str += "none (non-unit)"; + } else { + for (const auto& field : fields) { + str += "\n " + field.as_string(); + } + } + + return str; } ::std::string UseDeclaration::as_string() const { ::std::string str = VisItem::as_string(); + // DEBUG: null pointer check + if (use_tree == NULL) { + fprintf(stderr, "something really terrible has gone wrong - null pointer use tree in " + "use declaration."); + return "NULL_POINTER_MARK"; + } + str += "use " + use_tree->as_string(); return str; @@ -238,6 +600,13 @@ namespace Rust { if (has_trees()) { for (const auto& tree : trees) { + // DEBUG: null pointer check + if (tree == NULL) { + fprintf(stderr, "something really terrible has gone wrong - null pointer " + "tree in use tree list."); + return "NULL_POINTER_MARK"; + } + path_str += tree->as_string() + ", "; } } else { @@ -269,24 +638,177 @@ namespace Rust { } ::std::string Enum::as_string() const { - return ::std::string("not implemented"); + ::std::string str = VisItem::as_string(); + str += enum_name; + + // generic params + str += "\n Generic params: "; + if (generic_params.empty()) { + str += "none"; + } else { + for (const auto& param : generic_params) { + // DEBUG: null pointer check + if (param == NULL) { + fprintf(stderr, "something really terrible has gone wrong - null pointer " + "generic param in enum."); + return "NULL_POINTER_MARK"; + } + + str += "\n " + param->as_string(); + } + } + + str += "\n Where clause: "; + if (has_where_clause()) { + str += where_clause.as_string(); + } else { + str += "none"; + } + + // items + str += "\n Items: "; + if (items.empty()) { + str += "none"; + } else { + for (const auto& item : items) { + // DEBUG: null pointer check + if (item == NULL) { + fprintf(stderr, "something really terrible has gone wrong - null pointer " + "enum item in enum."); + return "NULL_POINTER_MARK"; + } + + str += "\n " + item->as_string(); + } + } + + return str; } ::std::string Trait::as_string() const { - return ::std::string("not implemented"); + ::std::string str = VisItem::as_string(); + + if (has_unsafe) { + str += "unsafe "; + } + + str += "trait " + name; + + // generic params + str += "\n Generic params: "; + if (generic_params.empty()) { + str += "none"; + } else { + for (const auto& param : generic_params) { + // DEBUG: null pointer check + if (param == NULL) { + fprintf(stderr, "something really terrible has gone wrong - null pointer " + "generic param in trait."); + return "NULL_POINTER_MARK"; + } + + str += "\n " + param->as_string(); + } + } + + str += "\n Type param bounds: "; + if (!has_type_param_bounds()) { + str += "none"; + } else { + for (const auto& bound : type_param_bounds) { + // DEBUG: null pointer check + if (bound == NULL) { + fprintf(stderr, "something really terrible has gone wrong - null pointer " + "type param bound in trait."); + return "NULL_POINTER_MARK"; + } + + str += "\n " + bound->as_string(); + } + } + + str += "\n Where clause: "; + if (!has_where_clause()) { + str += "none"; + } else { + str += where_clause.as_string(); + } + + str += "\n Trait items: "; + if (!has_trait_items()) { + str += "none"; + } else { + for (const auto& item : trait_items) { + // DEBUG: null pointer check + if (item == NULL) { + fprintf(stderr, "something really terrible has gone wrong - null pointer " + "trait item in trait."); + return "NULL_POINTER_MARK"; + } + + str += "\n " + item->as_string(); + } + } + + return str; } ::std::string Union::as_string() const { - return ::std::string("not implemented"); + ::std::string str = VisItem::as_string(); + + str += "union " + union_name; + + // generic params + str += "\n Generic params: "; + if (generic_params.empty()) { + str += "none"; + } else { + for (const auto& param : generic_params) { + // DEBUG: null pointer check + if (param == NULL) { + fprintf(stderr, "something really terrible has gone wrong - null pointer " + "generic param in union."); + return "NULL_POINTER_MARK"; + } + + str += "\n " + param->as_string(); + } + } + + str += "\n Where clause: "; + if (has_where_clause()) { + str += where_clause.as_string(); + } else { + str += "none"; + } + + // struct fields + str += "\n Struct fields (variants): "; + if (variants.empty()) { + str += "none"; + } else { + for (const auto& field : variants) { + str += "\n " + field.as_string(); + } + } + + return str; } ::std::string Function::as_string() const { ::std::string str = VisItem::as_string() + "Function: "; - ::std::string qualifiers_str = qualifiers.as_string(); + ::std::string qualifiers_str = "Qualifiers: " + qualifiers.as_string(); ::std::string generic_params_str("Generic params: "); if (has_generics()) { for (const auto& generic_param : generic_params) { + // DEBUG: null pointer check + if (generic_param == NULL) { + fprintf(stderr, "something really terrible has gone wrong - null pointer " + "generic param in function item."); + return "NULL_POINTER_MARK"; + } + generic_params_str += generic_param->as_string() + ", "; } } else { @@ -304,6 +826,13 @@ namespace Rust { ::std::string return_type_str("Return type: "); if (has_function_return_type()) { + // DEBUG: null pointer check + if (return_type == NULL) { + fprintf(stderr, "something really terrible has gone wrong - null pointer return " + "type in function."); + return "NULL_POINTER_MARK"; + } + return_type_str += return_type->as_string(); } else { return_type_str += "none (void)"; @@ -316,15 +845,34 @@ namespace Rust { where_clause_str += "none"; } + // DEBUG: null pointer check + if (function_body == NULL) { + fprintf(stderr, "something really terrible has gone wrong - null pointer function " + "body in function."); + return "NULL_POINTER_MARK"; + } ::std::string body_str = "Body: " + function_body->as_string(); - str += "\n " + qualifiers_str + "\n " + generic_params_str + "\n " + function_params_str + "\n " + return_type_str + "\n " + where_clause_str + "\n " + body_str; + str += "\n " + qualifiers_str + "\n " + generic_params_str + "\n " + + function_params_str + "\n " + return_type_str + "\n " + where_clause_str + + "\n " + body_str; return str; } ::std::string WhereClause::as_string() const { - return ::std::string("not implemented"); + // just print where clause items, don't mention "where" or "where clause" + ::std::string str; + + if (where_clause_items.empty()) { + str = "none"; + } else { + for (const auto& item : where_clause_items) { + str += "\n " + item->as_string(); + } + } + + return str; } ::std::string BlockExpr::as_string() const { @@ -332,7 +880,7 @@ namespace Rust { // get outer attributes str += "\n " + Expr::as_string(); - + // inner attributes str += "\n inner attributes: "; if (inner_attrs.empty()) { @@ -350,6 +898,13 @@ namespace Rust { str += "none"; } else { for (const auto& stmt : statements) { + // DEBUG: null pointer check + if (stmt == NULL) { + fprintf(stderr, "something really terrible has gone wrong - null pointer " + "stmt in block expr."); + return "NULL_POINTER_MARK"; + } + str += "\n " + stmt->as_string(); } } @@ -366,31 +921,204 @@ namespace Rust { } ::std::string TraitImpl::as_string() const { - return ::std::string("not implemented"); + ::std::string str = VisItem::as_string(); + + if (has_unsafe) { + str += "unsafe "; + } + + str += "impl "; + + // generic params + str += "\n Generic params: "; + if (!has_generics()) { + str += "none"; + } else { + for (const auto& param : generic_params) { + str += "\n " + param->as_string(); + } + } + + str += "\n Has exclam: "; + if (has_exclam) { + str += "true"; + } else { + str += "false"; + } + + str += "\n TypePath (to trait): " + trait_path.as_string(); + + str += "\n Type (struct to impl on): " + trait_type->as_string(); + + str += "\n Where clause: "; + if (!has_where_clause()) { + str += "none"; + } else { + str += where_clause.as_string(); + } + + // inner attributes + str += "\n inner attributes: "; + if (inner_attrs.empty()) { + str += "none"; + } else { + // note that this does not print them with "inner attribute" syntax - just the body + for (const auto& attr : inner_attrs) { + str += "\n " + attr.as_string(); + } + } + + str += "\n trait impl items: "; + if (!has_impl_items()) { + str += "none"; + } else { + for (const auto& item : impl_items) { + str += "\n " + item->as_string(); + } + } + + return str; } ::std::string TypeAlias::as_string() const { - return ::std::string("not implemented"); + ::std::string str = VisItem::as_string(); + + str += " " + new_type_name; + + // generic params + str += "\n Generic params: "; + if (!has_generics()) { + str += "none"; + } else { + for (const auto& param : generic_params) { + str += param->as_string() + ", "; + } + } + + str += "\n Where clause: "; + if (!has_where_clause()) { + str += "none"; + } else { + str += where_clause.as_string(); + } + + str += "\n Type: " + existing_type->as_string(); + + return str; } ::std::string MacroInvocationSemi::as_string() const { - return ::std::string("not implemented"); + // get outer attrs + ::std::string str = MacroItem::as_string(); + + str += "\n" + path.as_string() + "!"; + + ::std::string tok_trees; + if (token_trees.empty()) { + tok_trees = "none"; + } else { + for (const auto& tree : token_trees) { + // DEBUG: null pointer check + if (tree == NULL) { + fprintf(stderr, "something really terrible has gone wrong - null pointer " + "token tree in macro invocation semi."); + return "NULL_POINTER_MARK"; + } + + tok_trees += tree->as_string() + ", "; + } + } + + return str + get_string_in_delims(::std::move(tok_trees), delim_type); } ::std::string ExternBlock::as_string() const { - return ::std::string("not implemented"); + ::std::string str = VisItem::as_string(); + + str += "extern "; + if (has_abi()) { + str += "\"" + abi + "\" "; + } + + // inner attributes + str += "\n inner attributes: "; + if (inner_attrs.empty()) { + str += "none"; + } else { + // note that this does not print them with "inner attribute" syntax - just the body + for (const auto& attr : inner_attrs) { + str += "\n " + attr.as_string(); + } + } + + str += "\n external items: "; + if (!has_extern_items()) { + str += "none"; + } else { + for (const auto& item : extern_items) { + str += "\n " + item->as_string(); + } + } + + return str; + } + + ::std::string MacroRule::as_string() const { + ::std::string str("Macro rule: "); + + str += "\n Matcher: \n "; + str += matcher.as_string(); + + str += "\n Transcriber: \n "; + str += transcriber.as_string(); + + return str; } ::std::string MacroRulesDefinition::as_string() const { - return ::std::string("not implemented"); + ::std::string str("macro_rules!"); + + str += rule_name; + + str += "\n Macro rules: "; + if (rules.empty()) { + str += "none"; + } else { + for (const auto& rule : rules) { + str += "\n " + rule.as_string(); + } + } + + str += "\n Delim type: "; + switch (delim_type) { + case PARENS: + str += "parentheses"; + break; + case SQUARE: + str += "square"; + break; + case CURLY: + str += "curly"; + break; + default: + return "ERROR_MARK_STRING - delim type in macro invocation"; + } + + return str; } ::std::string MacroInvocation::as_string() const { - return ::std::string("not implemented"); + return path.as_string() + "!" + token_tree.as_string(); } ::std::string PathInExpression::as_string() const { - return ::std::string("not implemented"); + ::std::string str; + + if (has_opening_scope_resolution) { + str = "::"; + } + + return str + PathPattern::as_string(); } ::std::string ExprStmtWithBlock::as_string() const { @@ -405,52 +1133,162 @@ namespace Rust { return str; } + ::std::string ClosureParam::as_string() const { + ::std::string str(pattern->as_string()); + + if (has_type_given()) { + str += " : " + type->as_string(); + } + + return str; + } + + ::std::string ClosureExpr::as_string() const { + ::std::string str("ClosureExpr:\n Has move: "); + if (has_move) { + str += "true"; + } else { + str += "false"; + } + + str += "\n Params: "; + if (params.empty()) { + str += "none"; + } else { + for (const auto& param : params) { + str += "\n " + param.as_string(); + } + } + + return str; + } + ::std::string ClosureExprInnerTyped::as_string() const { - return ::std::string("not implemented"); + ::std::string str = ClosureExpr::as_string(); + + str += "\n Return type: " + return_type->as_string(); + + str += "\n Body: " + expr->as_string(); + + return str; + } + + ::std::string PathPattern::as_string() const { + ::std::string str; + + for (const auto& segment : segments) { + str += segment.as_string() + "::"; + } + + // basically a hack - remove last two characters of string (remove final ::) + str.erase(str.length() - 2); + + return str; + } + + ::std::string QualifiedPathType::as_string() const { + ::std::string str("<"); + str += type_to_invoke_on->as_string(); + + if (has_as_clause()) { + str += " as " + trait_path.as_string(); + } + + return str + ">"; } ::std::string QualifiedPathInExpression::as_string() const { - return ::std::string("not implemented"); + return path_type.as_string() + "::" + PathPattern::as_string(); } ::std::string BorrowExpr::as_string() const { - return ::std::string("not implemented"); + ::std::string str("&"); + + if (double_borrow) { + str += "&"; + } + + if (is_mut) { + str += "mut "; + } + + str += main_or_left_expr->as_string(); + + return str; } ::std::string ReturnExpr::as_string() const { - return ::std::string("not implemented"); + ::std::string str("return "); + + if (has_return_expr()) { + str += return_expr->as_string(); + } + + return str; } ::std::string GroupedExpr::as_string() const { - return ::std::string("not implemented"); + ::std::string str("Grouped expr:"); + + // inner attributes + str += "\n inner attributes: "; + if (inner_attrs.empty()) { + str += "none"; + } else { + // note that this does not print them with "inner attribute" syntax - just the body + for (const auto& attr : inner_attrs) { + str += "\n " + attr.as_string(); + } + } + + str += "\n Expr in parens: " + expr_in_parens->as_string(); + + return str; } ::std::string RangeToExpr::as_string() const { - return ::std::string("not implemented"); + return ".." + to->as_string(); } ::std::string ContinueExpr::as_string() const { - return ::std::string("not implemented"); + ::std::string str("continue "); + + if (has_label()) { + str += label.as_string(); + } + + return str; } ::std::string NegationExpr::as_string() const { - return ::std::string("not implemented"); + ::std::string str; + + switch (negation_type) { + case NEGATE: + str = "-"; + break; + case NOT: + str = "!"; + break; + default: + return "ERROR_MARK_STRING - negation expr"; + } + + str += main_or_left_expr->as_string(); + + return str; } ::std::string RangeFromExpr::as_string() const { - return ::std::string("not implemented"); + return from->as_string() + ".."; } ::std::string RangeFullExpr::as_string() const { - return ::std::string("not implemented"); - } - - ::std::string WhileLoopExpr::as_string() const { - return ::std::string("not implemented"); + return ".."; } ::std::string ArrayIndexExpr::as_string() const { - return ::std::string("not implemented"); + return array_expr->as_string() + "[" + index_expr->as_string() + "]"; } ::std::string AssignmentExpr::as_string() const { @@ -470,87 +1308,267 @@ namespace Rust { } ::std::string AsyncBlockExpr::as_string() const { - return ::std::string("not implemented"); + ::std::string str = "AsyncBlockExpr: "; + + // get outer attributes + str += "\n " + Expr::as_string(); + + str += "\n Has move: "; + str += has_move ? "true" : "false"; + + return str + "\n" + block_expr->as_string(); } ::std::string ComparisonExpr::as_string() const { - return ::std::string("not implemented"); - } + ::std::string str(main_or_left_expr->as_string()); - ::std::string IfExprConseqIf::as_string() const { - return ::std::string("not implemented"); + switch (expr_type) { + case EQUAL: + str += " == "; + break; + case NOT_EQUAL: + str += " != "; + break; + case GREATER_THAN: + str += " > "; + break; + case LESS_THAN: + str += " < "; + break; + case GREATER_OR_EQUAL: + str += " >= "; + break; + case LESS_OR_EQUAL: + str += " <= "; + break; + default: + return "ERROR_MARK_STRING - comparison expr"; + } + + str += right_expr->as_string(); + + return str; } ::std::string MethodCallExpr::as_string() const { - return ::std::string("not implemented"); + ::std::string str("MethodCallExpr: \n Object (receiver) expr: "); + + str += receiver->as_string(); + + str += "\n Method path segment: \n"; + + str += method_name.as_string(); + + str += "\n Call params:"; + if (params.empty()) { + str += "none"; + } else { + for (const auto& param : params) { + if (param == NULL) { + return "ERROR_MARK_STRING - method call expr param is null"; + } + + str += "\n " + param->as_string(); + } + } + + return str; } ::std::string TupleIndexExpr::as_string() const { - return ::std::string("not implemented"); + return tuple_expr->as_string() + "." + ::std::to_string(tuple_index); } ::std::string DereferenceExpr::as_string() const { - return ::std::string("not implemented"); + return "*" + main_or_left_expr->as_string(); } ::std::string FieldAccessExpr::as_string() const { - return ::std::string("not implemented"); + return receiver->as_string() + "." + field; } ::std::string LazyBooleanExpr::as_string() const { - return ::std::string("not implemented"); + ::std::string str(main_or_left_expr->as_string()); + + switch (expr_type) { + case LOGICAL_OR: + str += " || "; + break; + case LOGICAL_AND: + str += " && "; + break; + default: + return "ERROR_MARK_STRING - lazy boolean expr out of bounds"; + } + + str += right_expr->as_string(); + + return str; } ::std::string RangeFromToExpr::as_string() const { - return ::std::string("not implemented"); + return from->as_string() + ".." + to->as_string(); } ::std::string RangeToInclExpr::as_string() const { - return ::std::string("not implemented"); + return "..=" + to->as_string(); } ::std::string UnsafeBlockExpr::as_string() const { - return ::std::string("not implemented"); + ::std::string str = "UnsafeBlockExpr: "; + + // get outer attributes + str += "\n " + Expr::as_string(); + + return str + "\n" + expr->as_string(); } ::std::string ClosureExprInner::as_string() const { - return ::std::string("not implemented"); + ::std::string str = ClosureExpr::as_string(); + + str += "\n Expression: " + closure_inner->as_string(); + + return str; + } + + ::std::string IfExpr::as_string() const { + ::std::string str("IfExpr: "); + + str += "\n Condition expr: " + condition->as_string(); + + str += "\n If block expr: " + if_block->as_string(); + + return str; } ::std::string IfExprConseqElse::as_string() const { - return ::std::string("not implemented"); + ::std::string str = IfExpr::as_string(); + + str += "\n Else block expr: " + else_block->as_string(); + + return str; } - ::std::string WhileLetLoopExpr::as_string() const { - return ::std::string("not implemented"); + ::std::string IfExprConseqIf::as_string() const { + ::std::string str = IfExpr::as_string(); + + str += "\n Else if expr: \n " + if_expr->as_string(); + + return str; } ::std::string IfExprConseqIfLet::as_string() const { - return ::std::string("not implemented"); + ::std::string str = IfExpr::as_string(); + + str += "\n Else if let expr: \n " + if_let_expr->as_string(); + + return str; } - ::std::string IfLetExprConseqIf::as_string() const { - return ::std::string("not implemented"); + ::std::string IfLetExpr::as_string() const { + ::std::string str("IfLetExpr: "); + + str += "\n Condition match arm patterns: "; + if (match_arm_patterns.empty()) { + str += "none"; + } else { + for (const auto& pattern : match_arm_patterns) { + str += "\n " + pattern->as_string(); + } + } + + str += "\n Scrutinee expr: " + value->as_string(); + + str += "\n If let block expr: " + if_block->as_string(); + + return str; } ::std::string IfLetExprConseqElse::as_string() const { - return ::std::string("not implemented"); - } + ::std::string str = IfLetExpr::as_string(); - ::std::string RangeFromToInclExpr::as_string() const { - return ::std::string("not implemented"); + str += "\n Else block expr: " + else_block->as_string(); + + return str; } - ::std::string ErrorPropogationExpr::as_string() const { - return ::std::string("not implemented"); + ::std::string IfLetExprConseqIf::as_string() const { + ::std::string str = IfLetExpr::as_string(); + + str += "\n Else if expr: \n " + if_expr->as_string(); + + return str; } ::std::string IfLetExprConseqIfLet::as_string() const { - return ::std::string("not implemented"); + ::std::string str = IfLetExpr::as_string(); + + str += "\n Else if let expr: \n " + if_let_expr->as_string(); + + return str; + } + + ::std::string RangeFromToInclExpr::as_string() const { + return from->as_string() + "..=" + to->as_string(); + } + + ::std::string ErrorPropagationExpr::as_string() const { + return main_or_left_expr->as_string() + "?"; } ::std::string CompoundAssignmentExpr::as_string() const { - return ::std::string("not implemented"); + ::std::string operator_str; + operator_str.reserve(1); + + // get operator string + switch (expr_type) { + case ADD: + operator_str = "+"; + break; + case SUBTRACT: + operator_str = "-"; + break; + case MULTIPLY: + operator_str = "*"; + break; + case DIVIDE: + operator_str = "/"; + break; + case MODULUS: + operator_str = "%"; + break; + case BITWISE_AND: + operator_str = "&"; + break; + case BITWISE_OR: + operator_str = "|"; + break; + case BITWISE_XOR: + operator_str = "^"; + break; + case LEFT_SHIFT: + operator_str = "<<"; + break; + case RIGHT_SHIFT: + operator_str = ">>"; + break; + default: + operator_str = "invalid operator. wtf"; + break; + } + + operator_str += "="; + + ::std::string str("CompoundAssignmentExpr: "); + if (main_or_left_expr == NULL || right_expr == NULL) { + str += "error. this is probably a parsing failure."; + } else { + str += "\n left: " + main_or_left_expr->as_string(); + str += "\n right: " + right_expr->as_string(); + str += "\n operator: " + operator_str; + } + + return str; } ::std::string ArithmeticOrLogicalExpr::as_string() const { @@ -562,7 +1580,7 @@ namespace Rust { case ADD: operator_str = "+"; break; - case SUBTRACT: + case SUBTRACT: operator_str = "-"; break; case MULTIPLY: @@ -607,43 +1625,238 @@ namespace Rust { } ::std::string CallExpr::as_string() const { - return ::std::string("not implemented"); + ::std::string str("CallExpr: \n Function expr: "); + + str += function->as_string(); + + str += "\n Call params:"; + if (!has_params()) { + str += "none"; + } else { + for (const auto& param : params) { + if (param == NULL) { + return "ERROR_MARK_STRING - call expr param is null"; + } + + str += "\n " + param->as_string(); + } + } + + return str; + } + + ::std::string WhileLoopExpr::as_string() const { + ::std::string str("WhileLoopExpr: "); + + str += "\n Label: "; + if (!has_loop_label()) { + str += "none"; + } else { + str += loop_label.as_string(); + } + + str += "\n Conditional expr: " + condition->as_string(); + + str += "\n Loop block: " + loop_block->as_string(); + + return str; + } + + ::std::string WhileLetLoopExpr::as_string() const { + ::std::string str("WhileLetLoopExpr: "); + + str += "\n Label: "; + if (!has_loop_label()) { + str += "none"; + } else { + str += loop_label.as_string(); + } + + str += "\n Match arm patterns: "; + if (match_arm_patterns.empty()) { + str += "none"; + } else { + for (const auto& pattern : match_arm_patterns) { + str += "\n " + pattern->as_string(); + } + } + + str += "\n Scrutinee expr: " + condition->as_string(); + + str += "\n Loop block: " + loop_block->as_string(); + + return str; } ::std::string LoopExpr::as_string() const { - return ::std::string("not implemented"); + ::std::string str("LoopExpr: (infinite loop)"); + + str += "\n Label: "; + if (!has_loop_label()) { + str += "none"; + } else { + str += loop_label.as_string(); + } + + str += "\n Loop block: " + loop_block->as_string(); + + return str; } ::std::string ArrayExpr::as_string() const { - return ::std::string("not implemented"); + ::std::string str("ArrayExpr:"); + + // inner attributes + str += "\n inner attributes: "; + if (inner_attrs.empty()) { + str += "none"; + } else { + // note that this does not print them with "inner attribute" syntax - just the body + for (const auto& attr : inner_attrs) { + str += "\n " + attr.as_string(); + } + } + + str += "\n Array elems: "; + if (!has_array_elems()) { + str += "none"; + } else { + str += internal_elements->as_string(); + } + + return str; } ::std::string AwaitExpr::as_string() const { - return ::std::string("not implemented"); + return awaited_expr->as_string() + ".await"; } ::std::string BreakExpr::as_string() const { - return ::std::string("not implemented"); + ::std::string str("break "); + + if (has_label()) { + str += label.as_string() + " "; + } + + if (has_break_expr()) { + str += break_expr->as_string(); + } + + return str; } - ::std::string IfExpr::as_string() const { - return ::std::string("not implemented"); + ::std::string LoopLabel::as_string() const { + return label.as_string() + ": (label) "; } - ::std::string IfLetExpr::as_string() const { - return ::std::string("not implemented"); + ::std::string MatchArm::as_string() const { + // outer attributes + ::std::string str = "Outer attributes: "; + if (outer_attrs.empty()) { + str += "none"; + } else { + // note that this does not print them with "outer attribute" syntax - just the body + for (const auto& attr : outer_attrs) { + str += "\n " + attr.as_string(); + } + } + + str += "\nPatterns: "; + if (match_arm_patterns.empty()) { + str += "none"; + } else { + for (const auto& pattern : match_arm_patterns) { + str += "\n " + pattern->as_string(); + } + } + + str += "\nGuard expr: "; + if (!has_match_arm_guard()) { + str += "none"; + } else { + str += guard_expr->as_string(); + } + + return str; } - ::std::string LoopLabel::as_string() const { - return ::std::string("not implemented"); + ::std::string MatchCase::as_string() const { + ::std::string str("MatchCase: (match arm) "); + + str += "\n Match arm matcher: \n" + arm.as_string(); + + return str; + } + + ::std::string MatchCaseBlockExpr::as_string() const { + ::std::string str = MatchCase::as_string(); + + str += "\n Block expr: " + block_expr->as_string(); + + return str; + } + + ::std::string MatchCaseExpr::as_string() const { + ::std::string str = MatchCase::as_string(); + + str += "\n Expr: " + expr->as_string(); + + return str; } ::std::string MatchExpr::as_string() const { - return ::std::string("not implemented"); + ::std::string str("MatchExpr:"); + + str += "\n Scrutinee expr: " + branch_value->as_string(); + + // inner attributes + str += "\n inner attributes: "; + if (inner_attrs.empty()) { + str += "none"; + } else { + // note that this does not print them with "inner attribute" syntax - just the body + for (const auto& attr : inner_attrs) { + str += "\n " + attr.as_string(); + } + } + + // match arms + str += "\n Match arms: "; + if (match_arms.empty()) { + str += "none"; + } else { + for (const auto& arm : match_arms) { + str += "\n " + arm->as_string(); + } + } + + return str; } ::std::string TupleExpr::as_string() const { - return ::std::string("not implemented"); + ::std::string str("TupleExpr:"); + + // inner attributes + str += "\n inner attributes: "; + if (inner_attrs.empty()) { + str += "none"; + } else { + // note that this does not print them with "inner attribute" syntax - just the body + for (const auto& attr : inner_attrs) { + str += "\n " + attr.as_string(); + } + } + + str += "\n Tuple elements: "; + if (tuple_elems.empty()) { + str += "none"; + } else { + for (const auto& elem : tuple_elems) { + str += "\n " + elem->as_string(); + } + } + + return str; } ::std::string ExprStmtWithoutBlock::as_string() const { @@ -659,47 +1872,237 @@ namespace Rust { } ::std::string FunctionParam::as_string() const { - return ::std::string("not implemented"); + return param_name->as_string() + " : " + type->as_string(); } ::std::string FunctionQualifiers::as_string() const { - return ::std::string("not implemented"); + ::std::string str; + + switch (const_status) { + case NONE: + // do nothing + break; + case CONST: + str += "const "; + break; + case ASYNC: + str += "async "; + break; + default: + return "ERROR_MARK_STRING: async-const status failure"; + } + + if (has_unsafe) { + str += "unsafe "; + } + + if (has_extern) { + str += "extern"; + if (extern_abi != "") { + str += " \"" + extern_abi + "\""; + } + } + + return str; } ::std::string TraitBound::as_string() const { - return ::std::string("not implemented"); + ::std::string str("TraitBound:"); + + str += "\n Has opening question mark: "; + if (opening_question_mark) { + str += "true"; + } else { + str += "false"; + } + + str += "\n For lifetimes: "; + if (!has_for_lifetimes()) { + str += "none"; + } else { + for (const auto& lifetime : for_lifetimes) { + str += "\n " + lifetime.as_string(); + } + } + + str += "\n Type path: " + type_path.as_string(); + + return str; } ::std::string MacroMatcher::as_string() const { - return ::std::string("not implemented"); + ::std::string str("Macro matcher: "); + + str += "\n Delim type: "; + + switch (delim_type) { + case PARENS: + str += "parentheses"; + break; + case SQUARE: + str += "square"; + break; + case CURLY: + str += "curly"; + break; + default: + return "ERROR_MARK_STRING - macro matcher delim"; + } + + str += "\n Matches: "; + + if (matches.empty()) { + str += "none"; + } else { + for (const auto& match : matches) { + str += "\n " + match->as_string(); + } + } + + return str; } ::std::string LifetimeParam::as_string() const { - return ::std::string("not implemented"); + ::std::string str("LifetimeParam: "); + + str += "\n Outer attribute: "; + if (!has_outer_attribute()) { + str += "none"; + } else { + str += outer_attr.as_string(); + } + + str += "\n Lifetime: " + lifetime.as_string(); + + str += "\n Lifetime bounds: "; + if (!has_lifetime_bounds()) { + str += "none"; + } else { + for (const auto& bound : lifetime_bounds) { + str += "\n " + bound.as_string(); + } + } + + return str; } ::std::string MacroMatchFragment::as_string() const { - return ::std::string("not implemented"); + return "$" + ident + ": " + frag_spec_to_str(frag_spec); } ::std::string QualifiedPathInType::as_string() const { - return ::std::string("not implemented"); + ::std::string str = path_type.as_string(); + + for (const auto& segment : segments) { + str += "::" + segment->as_string(); + } + + return str; } ::std::string MacroMatchRepetition::as_string() const { - return ::std::string("not implemented"); + ::std::string str("Macro match repetition: "); + + str += "\n Matches: "; + if (matches.empty()) { + str += "none"; + } else { + for (const auto& match : matches) { + str += "\n " + match->as_string(); + } + } + + str += "\n Sep: "; + if (!has_sep()) { + str += "none"; + } else { + str += sep->as_string(); + } + + str += "\n Op: "; + switch (op) { + case ASTERISK: + str += "*"; + break; + case PLUS: + str += "+"; + break; + case QUESTION_MARK: + str += "?"; + break; + case NONE: + str += "no op? shouldn't be allowed"; + break; + default: + return "ERROR_MARK_STRING - unknown op in macro match repetition"; + } + + return str; } ::std::string Lifetime::as_string() const { - return ::std::string("not implemented"); + if (is_error()) { + return "error lifetime"; + } + + switch (lifetime_type) { + case NAMED: + return "'" + lifetime_name; + case STATIC: + return "'static"; + case WILDCARD: + return "'_"; + default: + return "ERROR-MARK-STRING: lifetime type failure"; + } } ::std::string TypePath::as_string() const { - return ::std::string("not implemented"); + ::std::string str; + + if (has_opening_scope_resolution) { + str = "::"; + } + + for (const auto& segment : segments) { + str += segment->as_string() + "::"; + } + + // kinda hack - remove last 2 '::' characters + str.erase(str.length() - 2); + + return str; } ::std::string TypeParam::as_string() const { - return ::std::string("not implemented"); + ::std::string str("TypeParam: "); + + str += "\n Outer attribute: "; + if (!has_outer_attribute()) { + str += "none"; + } else { + str += outer_attr.as_string(); + } + + str += "\n Identifier: " + type_representation; + + str += "\n Type param bounds: "; + if (!has_type_param_bounds()) { + str += "none"; + } else { + for (const auto& bound : type_param_bounds) { + str += "\n " + bound->as_string(); + } + } + + str += "\n Type: "; + if (!has_type()) { + str += "none"; + } else { + str += type->as_string(); + } + + return str; } SimplePath PathPattern::convert_to_simple_path(bool with_opening_scope_resolution) const { @@ -713,16 +2116,26 @@ namespace Rust { for (const auto& segment : segments) { // return empty path if doesn't meet simple path segment requirements - if (segment.is_error() || segment.has_generic_args() || segment.as_string() == "Self") { + if (segment.is_error() || segment.has_generic_args() + || segment.as_string() == "Self") { return SimplePath::create_empty(); } // create segment and add to vector ::std::string segment_str = segment.as_string(); - simple_segments.push_back(SimplePathSegment(::std::move(segment_str))); + simple_segments.push_back( + SimplePathSegment(::std::move(segment_str), segment.get_locus())); } - return SimplePath(::std::move(simple_segments), with_opening_scope_resolution); + // kind of a HACK to get locus depending on opening scope resolution + location_t locus = UNKNOWN_LOCATION; + if (with_opening_scope_resolution) { + locus = simple_segments[0].get_locus() - 2; // minus 2 chars for :: + } else { + locus = simple_segments[0].get_locus(); + } + + return SimplePath(::std::move(simple_segments), with_opening_scope_resolution, locus); } SimplePath TypePath::as_simple_path() const { @@ -736,70 +2149,348 @@ namespace Rust { for (const auto& segment : segments) { // return empty path if doesn't meet simple path segment requirements - if (segment == NULL || segment->is_error() || !segment->is_ident_only() || segment->as_string() == "Self") { + if (segment == NULL || segment->is_error() || !segment->is_ident_only() + || segment->as_string() == "Self") { return SimplePath::create_empty(); } // create segment and add to vector ::std::string segment_str = segment->as_string(); - simple_segments.push_back(SimplePathSegment(::std::move(segment_str))); + simple_segments.push_back( + SimplePathSegment(::std::move(segment_str), segment->get_locus())); } - return SimplePath(::std::move(simple_segments), has_opening_scope_resolution); + return SimplePath(::std::move(simple_segments), has_opening_scope_resolution, locus); } ::std::string PathExprSegment::as_string() const { ::std::string ident_str = segment_name.as_string(); if (has_generic_args()) { ident_str += "::<" + generic_args.as_string() + ">"; - } + } return ident_str; } ::std::string GenericArgs::as_string() const { - // TODO: write GenericArgs as string - return "not implemented"; + ::std::string args; + + // lifetime args + if (!lifetime_args.empty()) { + for (const auto& lifetime_arg : lifetime_args) { + args += lifetime_arg.as_string() + ", "; + } + } + + // type args + if (!type_args.empty()) { + for (const auto& type_arg : type_args) { + args += type_arg->as_string() + ", "; + } + } + + // binding args + if (!binding_args.empty()) { + for (const auto& binding_arg : binding_args) { + args += binding_arg.as_string() + ", "; + } + } + + return args; + } + + ::std::string GenericArgsBinding::as_string() const { + return identifier + " = " + type->as_string(); } ::std::string ForLoopExpr::as_string() const { - return ::std::string("not implemented"); + ::std::string str("ForLoopExpr: "); + + str += "\n Label: "; + if (!has_loop_label()) { + str += "none"; + } else { + str += loop_label.as_string(); + } + + str += "\n Pattern: " + pattern->as_string(); + + str += "\n Iterator expr: " + iterator_expr->as_string(); + + str += "\n Loop block: " + loop_block->as_string(); + + return str; } ::std::string RangePattern::as_string() const { - return ::std::string("not implemented"); + if (has_ellipsis_syntax) { + return lower->as_string() + "..." + upper->as_string(); + } else { + return lower->as_string() + "..=" + upper->as_string(); + } + } + + ::std::string RangePatternBoundLiteral::as_string() const { + ::std::string str; + + if (has_minus) { + str += "-"; + } + + str += literal.as_string(); + + return str; } ::std::string SlicePattern::as_string() const { - return ::std::string("not implemented"); + ::std::string str("SlicePattern: "); + + for (const auto& pattern : items) { + str += "\n " + pattern->as_string(); + } + + return str; + } + + ::std::string TuplePatternItemsMultiple::as_string() const { + ::std::string str; + + for (const auto& pattern : patterns) { + str += "\n " + pattern->as_string(); + } + + return str; + } + + ::std::string TuplePatternItemsRanged::as_string() const { + ::std::string str; + + str += "\n Lower patterns: "; + if (lower_patterns.empty()) { + str += "none"; + } else { + for (const auto& lower : lower_patterns) { + str += "\n " + lower->as_string(); + } + } + + str += "\n Upper patterns: "; + if (upper_patterns.empty()) { + str += "none"; + } else { + for (const auto& upper : upper_patterns) { + str += "\n " + upper->as_string(); + } + } + + return str; } ::std::string TuplePattern::as_string() const { - return ::std::string("not implemented"); + return "TuplePattern: " + items->as_string(); + } + + ::std::string StructPatternField::as_string() const { + // outer attributes + ::std::string str("Outer attributes: "); + if (outer_attrs.empty()) { + str += "none"; + } else { + // note that this does not print them with "outer attribute" syntax - just the body + for (const auto& attr : outer_attrs) { + str += "\n " + attr.as_string(); + } + } + + return str; + } + + ::std::string StructPatternFieldIdent::as_string() const { + ::std::string str = StructPatternField::as_string(); + + str += "\n"; + + if (has_ref) { + str += "ref "; + } + + if (has_mut) { + str += "mut "; + } + + str += ident; + + return str; + } + + ::std::string StructPatternFieldTuplePat::as_string() const { + ::std::string str = StructPatternField::as_string(); + + str += "\n"; + + str += ::std::to_string(index) + " : " + tuple_pattern->as_string(); + + return str; + } + + ::std::string StructPatternFieldIdentPat::as_string() const { + ::std::string str = StructPatternField::as_string(); + + str += "\n"; + + str += ident + " : " + ident_pattern->as_string(); + + return str; + } + + ::std::string StructPatternElements::as_string() const { + ::std::string str("\n Fields: "); + + if (!has_struct_pattern_fields()) { + str += "none"; + } else { + for (const auto& field : fields) { + str += "\n " + field->as_string(); + } + } + + str += "\n Etc: "; + if (has_struct_pattern_etc) { + str += "true"; + } else { + str += "false"; + } + + return str; } ::std::string StructPattern::as_string() const { - return ::std::string("not implemented"); + ::std::string str("StructPattern: \n Path: "); + + str += path.as_string(); + + str += "\n Struct pattern elems: "; + if (!has_struct_pattern_elems()) { + str += "none"; + } else { + str += elems.as_string(); + } + + return str; } ::std::string LiteralPattern::as_string() const { - return ::std::string("not implemented"); + ::std::string str; + + if (has_minus) { + str += "-"; + } + + return str + lit.as_string(); } ::std::string ReferencePattern::as_string() const { - return ::std::string("not implemented"); + ::std::string str("&"); + + if (has_two_amps) { + str += "&"; + } + + if (is_mut) { + str += "mut "; + } + + str += pattern->as_string(); + + return str; } ::std::string IdentifierPattern::as_string() const { - return ::std::string("not implemented"); + ::std::string str; + + if (is_ref) { + str += "ref "; + } + + if (is_mut) { + str += "mut "; + } + + str += variable_ident; + + if (has_pattern_to_bind()) { + str += " @ " + to_bind->as_string(); + } + + return str; + } + + ::std::string TupleStructItemsNoRange::as_string() const { + ::std::string str; + + for (const auto& pattern : patterns) { + str += "\n " + pattern->as_string(); + } + + return str; + } + + ::std::string TupleStructItemsRange::as_string() const { + ::std::string str("\n Lower patterns: "); + + if (lower_patterns.empty()) { + str += "none"; + } else { + for (const auto& lower : lower_patterns) { + str += "\n " + lower->as_string(); + } + } + + str += "\n Upper patterns: "; + if (upper_patterns.empty()) { + str += "none"; + } else { + for (const auto& upper : upper_patterns) { + str += "\n " + upper->as_string(); + } + } + + return str; } ::std::string TupleStructPattern::as_string() const { - return ::std::string("not implemented"); + ::std::string str("TupleStructPattern: \n Path: "); + + str += path.as_string(); + + str += "\n Tuple struct items: " + items->as_string(); + + return str; } ::std::string LetStmt::as_string() const { - return ::std::string("not implemented"); + // outer attributes + ::std::string str = "Outer attributes: "; + if (outer_attrs.empty()) { + str += "none"; + } else { + // note that this does not print them with "outer attribute" syntax - just the body + for (const auto& attr : outer_attrs) { + str += "\n " + attr.as_string(); + } + } + + str += "\nlet " + variables_pattern->as_string(); + + if (has_type()) { + str += " : " + type->as_string(); + } + + if (has_init_expr()) { + str += " = " + init_expr->as_string(); + } + + return str; } // Used to get outer attributes for expressions. @@ -824,5 +2515,2096 @@ namespace Rust { TypePath copy(*this); return new TraitBound(::std::move(copy), in_parens); } + + ::std::string InferredType::as_string() const { + return "_ (inferred)"; + } + + ::std::string TypeCastExpr::as_string() const { + return main_or_left_expr->as_string() + " as " + type_to_convert_to->as_string(); + } + + ::std::string ImplTraitType::as_string() const { + ::std::string str("ImplTraitType: \n TypeParamBounds: "); + + if (type_param_bounds.empty()) { + str += "none"; + } else { + for (const auto& bound : type_param_bounds) { + str += "\n " + bound->as_string(); + } + } + + return str; + } + + ::std::string ReferenceType::as_string() const { + ::std::string str("&"); + + if (has_lifetime()) { + str += lifetime.as_string() + " "; + } + + if (has_mut) { + str += "mut "; + } + + str += type->as_string(); + + return str; + } + + ::std::string RawPointerType::as_string() const { + ::std::string str("*"); + + switch (pointer_type) { + case MUT: + str += "mut "; + break; + case CONST: + str += "const "; + break; + default: + return "ERROR_MARK_STRING - unknown pointer type in raw pointer type"; + } + + str += type->as_string(); + + return str; + } + + ::std::string TraitObjectType::as_string() const { + ::std::string str("TraitObjectType: \n Has dyn dispatch: "); + + if (has_dyn) { + str += "true"; + } else { + str += "false"; + } + + str += "\n TypeParamBounds: "; + if (type_param_bounds.empty()) { + str += "none"; + } else { + for (const auto& bound : type_param_bounds) { + str += "\n " + bound->as_string(); + } + } + + return str; + } + + ::std::string BareFunctionType::as_string() const { + ::std::string str("BareFunctionType: \n For lifetimes: "); + + if (!has_for_lifetimes()) { + str += "none"; + } else { + for (const auto& for_lifetime : for_lifetimes) { + str += "\n " + for_lifetime.as_string(); + } + } + + str += "\n Qualifiers: " + function_qualifiers.as_string(); + + str += "\n Params: "; + if (params.empty()) { + str += "none"; + } else { + for (const auto& param : params) { + str += "\n " + param.as_string(); + } + } + + str += "\n Is variadic: "; + if (is_variadic) { + str += "true"; + } else { + str += "false"; + } + + str += "\n Return type: "; + if (!has_return_type()) { + str += "none (void)"; + } else { + str += return_type->as_string(); + } + + return str; + } + + ::std::string ImplTraitTypeOneBound::as_string() const { + ::std::string str("ImplTraitTypeOneBound: \n TraitBound: "); + + return str + trait_bound.as_string(); + } + + ::std::string TypePathSegmentGeneric::as_string() const { + return TypePathSegment::as_string() + "<" + generic_args.as_string() + ">"; + } + + ::std::string TraitObjectTypeOneBound::as_string() const { + ::std::string str("TraitObjectTypeOneBound: \n Has dyn dispatch: "); + + if (has_dyn) { + str += "true"; + } else { + str += "false"; + } + + str += "\n TraitBound: " + trait_bound.as_string(); + + return str; + } + + ::std::string TypePathFunction::as_string() const { + ::std::string str("("); + + if (has_inputs()) { + for (const auto& param : inputs) { + str += param->as_string() + ", "; + } + } + + str += ")"; + + if (has_return_type()) { + str += " -> " + return_type->as_string(); + } + + return str; + } + + ::std::string TypePathSegmentFunction::as_string() const { + return TypePathSegment::as_string() + function_path.as_string(); + } + + ::std::string ArrayType::as_string() const { + return "[" + elem_type->as_string() + "; " + size->as_string() + "]"; + } + + ::std::string SliceType::as_string() const { + return "[" + elem_type->as_string() + "]"; + } + + ::std::string TupleType::as_string() const { + ::std::string str("("); + + if (!is_unit_type()) { + for (const auto& elem : elems) { + str += elem->as_string() + ", "; + } + } + + str += ")"; + + return str; + } + + ::std::string StructExpr::as_string() const { + ::std::string str = ExprWithoutBlock::as_string(); + + str += "\nStructExpr"; + + str += "\n PathInExpr: " + struct_name.as_string(); + + return str; + } + + ::std::string StructExprTuple::as_string() const { + ::std::string str = StructExpr::as_string(); + + // inner attributes + str += "\n inner attributes: "; + if (inner_attrs.empty()) { + str += "none"; + } else { + // note that this does not print them with "inner attribute" syntax - just the body + for (const auto& attr : inner_attrs) { + str += "\n " + attr.as_string(); + } + } + + str += "\n Tuple fields: "; + if (exprs.empty()) { + str += "none"; + } else { + for (const auto& field : exprs) { + // debug - null pointer check + if (field == NULL) { + return "ERROR_MARK_STRING - nullptr struct expr tuple field"; + } + + str += "\n " + field->as_string(); + } + } + + return str; + } + + ::std::string StructExprStruct::as_string() const { + ::std::string str("StructExprStruct (or subclass): "); + + str += "\n Path: " + get_struct_name().as_string(); + + // inner attributes + str += "\n inner attributes: "; + if (inner_attrs.empty()) { + str += "none"; + } else { + // note that this does not print them with "inner attribute" syntax - just the body + for (const auto& attr : inner_attrs) { + str += "\n " + attr.as_string(); + } + } + + return str; + } + + ::std::string StructBase::as_string() const { + if (base_struct != NULL) { + return base_struct->as_string(); + } else { + return "ERROR_MARK_STRING - invalid struct base had as string applied"; + } + } + + ::std::string StructExprFieldWithVal::as_string() const { + // used to get value string + return value->as_string(); + } + + ::std::string StructExprFieldIdentifierValue::as_string() const { + return field_name + " : " + StructExprFieldWithVal::as_string(); + } + + ::std::string StructExprFieldIndexValue::as_string() const { + return ::std::to_string(index) + " : " + StructExprFieldWithVal::as_string(); + } + + ::std::string StructExprStructFields::as_string() const { + ::std::string str = StructExprStruct::as_string(); + + str += "\n Fields: "; + if (fields.empty()) { + str += "none"; + } else { + for (const auto& field : fields) { + str += "\n " + field->as_string(); + } + } + + str += "\n Struct base: "; + if (!has_struct_base()) { + str += "none"; + } else { + str += struct_base.as_string(); + } + + return str; + } + + ::std::string EnumItem::as_string() const { + // outer attributes + ::std::string str = "outer attributes: "; + if (outer_attrs.empty()) { + str += "none"; + } else { + // note that this does not print them with "outer attribute" syntax - just the body + for (const auto& attr : outer_attrs) { + str += "\n " + attr.as_string(); + } + } + + str += "\n" + variant_name; + + return str; + } + + ::std::string EnumItemTuple::as_string() const { + ::std::string str = EnumItem::as_string(); + + // add tuple opening parens + str += "("; + + // tuple fields + if (has_tuple_fields()) { + for (const auto& field : tuple_fields) { + str += field.as_string() + ", "; + } + } + + // add tuple closing parens + str += ")"; + + return str; + } + + ::std::string TupleField::as_string() const { + // outer attributes + ::std::string str = "outer attributes: "; + if (outer_attrs.empty()) { + str += "none"; + } else { + // note that this does not print them with "outer attribute" syntax - just the body + for (const auto& attr : outer_attrs) { + str += "\n " + attr.as_string(); + } + } + + if (has_visibility()) { + str += "\n" + visibility.as_string(); + } + + str += " " + field_type->as_string(); + + return str; + } + + ::std::string EnumItemStruct::as_string() const { + ::std::string str = EnumItem::as_string(); + + // add struct opening parens + str += "{"; + + // tuple fields + if (has_struct_fields()) { + for (const auto& field : struct_fields) { + str += field.as_string() + ", "; + } + } + + // add struct closing parens + str += "}"; + + return str; + } + + ::std::string StructField::as_string() const { + // outer attributes + ::std::string str = "outer attributes: "; + if (outer_attrs.empty()) { + str += "none"; + } else { + // note that this does not print them with "outer attribute" syntax - just the body + for (const auto& attr : outer_attrs) { + str += "\n " + attr.as_string(); + } + } + + if (has_visibility()) { + str += "\n" + visibility.as_string(); + } + + str += " " + field_name + " : " + field_type->as_string(); + + return str; + } + + ::std::string EnumItemDiscriminant::as_string() const { + ::std::string str = EnumItem::as_string(); + + // add equal and expression + str += " = " + expression->as_string(); + + return str; + } + + ::std::string ExternalItem::as_string() const { + // outer attributes + ::std::string str = "outer attributes: "; + if (outer_attrs.empty()) { + str += "none"; + } else { + // note that this does not print them with "outer attribute" syntax - just the body + for (const auto& attr : outer_attrs) { + str += "\n " + attr.as_string(); + } + } + + // start visibility on new line and with a space + str += "\n" + visibility.as_string() + " "; + + return str; + } + + ::std::string ExternalStaticItem::as_string() const { + ::std::string str = ExternalItem::as_string(); + + str += "static "; + + if (has_mut) { + str += "mut "; + } + + // add name + str += get_item_name(); + + // add type on new line + str += "\n Type: " + item_type->as_string(); + + return str; + } + + ::std::string ExternalFunctionItem::as_string() const { + ::std::string str = ExternalItem::as_string(); + + str += "fn "; + + // add name + str += get_item_name(); + + // generic params + str += "\n Generic params: "; + if (generic_params.empty()) { + str += "none"; + } else { + for (const auto& param : generic_params) { + // DEBUG: null pointer check + if (param == NULL) { + fprintf(stderr, "something really terrible has gone wrong - null pointer " + "generic param in external function item."); + return "NULL_POINTER_MARK"; + } + + str += "\n " + param->as_string(); + } + } + + // function params + str += "\n Function params: "; + if (function_params.empty()) { + str += "none"; + } else { + for (const auto& param : function_params) { + str += "\n " + param.as_string(); + } + if (has_variadics) { + str += "\n .. (variadic)"; + } + } + + // add type on new line + str += "\n (return) Type: " + return_type->as_string(); + + // where clause + str += "\n Where clause: "; + if (has_where_clause()) { + str += where_clause.as_string(); + } else { + str += "none"; + } + + return str; + } + + ::std::string NamedFunctionParam::as_string() const { + ::std::string str = name; + + str += "\n Type: " + param_type->as_string(); + + return str; + } + + /*::std::string TraitItem::as_string() const { + // outer attributes + ::std::string str = "outer attributes: "; + if (outer_attrs.empty()) { + str += "none"; + } else { + // note that this does not print them with "outer attribute" syntax - just the body + for (const auto& attr : outer_attrs) { + str += "\n " + attr.as_string(); + } + } + + return str; + }*/ + + ::std::string TraitItemFunc::as_string() const { + ::std::string str = "outer attributes: "; + if (outer_attrs.empty()) { + str += "none"; + } else { + // note that this does not print them with "outer attribute" syntax - just the body + for (const auto& attr : outer_attrs) { + str += "\n " + attr.as_string(); + } + } + + str += "\n" + decl.as_string(); + + str += "\n Definition (block expr): "; + if (has_definition()) { + str += block_expr->as_string(); + } else { + str += "none"; + } + + return str; + } + + ::std::string TraitFunctionDecl::as_string() const { + ::std::string str = qualifiers.as_string() + "fn " + function_name; + + // generic params + str += "\n Generic params: "; + if (generic_params.empty()) { + str += "none"; + } else { + for (const auto& param : generic_params) { + // DEBUG: null pointer check + if (param == NULL) { + fprintf(stderr, "something really terrible has gone wrong - null pointer " + "generic param in trait function decl."); + return "NULL_POINTER_MARK"; + } + + str += "\n " + param->as_string(); + } + } + + str += "\n Function params: "; + if (has_params()) { + for (const auto& param : function_params) { + str += "\n " + param.as_string(); + } + } else { + str += "none"; + } + + str += "\n Return type: "; + if (has_return_type()) { + str += return_type->as_string(); + } else { + str += "none (void)"; + } + + str += "\n Where clause: "; + if (has_where_clause()) { + str += where_clause.as_string(); + } else { + str += "none"; + } + + return str; + } + + ::std::string TraitItemMethod::as_string() const { + ::std::string str = "outer attributes: "; + if (outer_attrs.empty()) { + str += "none"; + } else { + // note that this does not print them with "outer attribute" syntax - just the body + for (const auto& attr : outer_attrs) { + str += "\n " + attr.as_string(); + } + } + + str += "\n" + decl.as_string(); + + str += "\n Definition (block expr): "; + if (has_definition()) { + str += block_expr->as_string(); + } else { + str += "none"; + } + + return str; + } + + ::std::string TraitMethodDecl::as_string() const { + ::std::string str = qualifiers.as_string() + "fn " + function_name; + + // generic params + str += "\n Generic params: "; + if (generic_params.empty()) { + str += "none"; + } else { + for (const auto& param : generic_params) { + // DEBUG: null pointer check + if (param == NULL) { + fprintf(stderr, "something really terrible has gone wrong - null pointer " + "generic param in trait function decl."); + return "NULL_POINTER_MARK"; + } + + str += "\n " + param->as_string(); + } + } + + str += "\n Self param: " + self_param.as_string(); + + str += "\n Function params: "; + if (has_params()) { + for (const auto& param : function_params) { + str += "\n " + param.as_string(); + } + } else { + str += "none"; + } + + str += "\n Return type: "; + if (has_return_type()) { + str += return_type->as_string(); + } else { + str += "none (void)"; + } + + str += "\n Where clause: "; + if (has_where_clause()) { + str += where_clause.as_string(); + } else { + str += "none"; + } + + return str; + } + + ::std::string TraitItemConst::as_string() const { + ::std::string str = "outer attributes: "; + if (outer_attrs.empty()) { + str += "none"; + } else { + // note that this does not print them with "outer attribute" syntax - just the body + for (const auto& attr : outer_attrs) { + str += "\n " + attr.as_string(); + } + } + + str += "\nconst " + name + " : " + type->as_string(); + + if (has_expression()) { + str += " = " + expr->as_string(); + } + + return str; + } + + ::std::string TraitItemType::as_string() const { + ::std::string str = "outer attributes: "; + if (outer_attrs.empty()) { + str += "none"; + } else { + // note that this does not print them with "outer attribute" syntax - just the body + for (const auto& attr : outer_attrs) { + str += "\n " + attr.as_string(); + } + } + + str += "\ntype " + name; + + str += "\n Type param bounds: "; + if (!has_type_param_bounds()) { + str += "none"; + } else { + for (const auto& bound : type_param_bounds) { + // DEBUG: null pointer check + if (bound == NULL) { + fprintf(stderr, "something really terrible has gone wrong - null pointer " + "type param bound in trait item type."); + return "NULL_POINTER_MARK"; + } + + str += "\n " + bound->as_string(); + } + } + + return str; + } + + ::std::string SelfParam::as_string() const { + if (is_error()) { + return "error"; + } else { + if (has_type()) { + // type (i.e. not ref, no lifetime) + ::std::string str; + + if (is_mut) { + str += "mut "; + } + + str += "self : "; + + str += type->as_string(); + + return str; + } else if (has_lifetime()) { + // ref and lifetime + ::std::string str = "&" + lifetime.as_string() + " "; + + if (is_mut) { + str += "mut "; + } + + str += "self"; + + return str; + } else if (has_ref) { + // ref with no lifetime + ::std::string str = "&"; + + if (is_mut) { + str += " mut "; + } + + str += "self"; + + return str; + } else { + // no ref, no type + ::std::string str; + + if (is_mut) { + str += "mut "; + } + + str += "self"; + + return str; + } + } + } + + ::std::string ArrayElemsCopied::as_string() const { + return elem_to_copy->as_string() + "; " + num_copies->as_string(); + } + + ::std::string LifetimeWhereClauseItem::as_string() const { + ::std::string str("Lifetime: "); + + str += lifetime.as_string(); + + str += "\nLifetime bounds: "; + + for (const auto& bound : lifetime_bounds) { + str += "\n " + bound.as_string(); + } + + return str; + } + + ::std::string TypeBoundWhereClauseItem::as_string() const { + ::std::string str("For lifetimes: "); + + if (!has_for_lifetimes()) { + str += "none"; + } else { + for (const auto& for_lifetime : for_lifetimes) { + str += "\n " + for_lifetime.as_string(); + } + } + + str += "\nType: " + bound_type->as_string(); + + str += "\nType param bounds bounds: "; + + for (const auto& bound : type_param_bounds) { + // debug null pointer check + if (bound == NULL) { + return "NULL_POINTER_MARK - type param bounds"; + } + + str += "\n " + bound->as_string(); + } + + return str; + } + + ::std::string ArrayElemsValues::as_string() const { + ::std::string str; + + for (const auto& expr : values) { + // DEBUG: null pointer check + if (expr == NULL) { + fprintf(stderr, "something really terrible has gone wrong - null pointer " + "expr in array elems values."); + return "NULL_POINTER_MARK"; + } + + str += "\n " + expr->as_string(); + } + + return str; + } + + ::std::string MaybeNamedParam::as_string() const { + ::std::string str; + + switch (param_kind) { + case UNNAMED: + break; + case IDENTIFIER: + str = name + " : "; + break; + case WILDCARD: + str = "_ : "; + break; + default: + return "ERROR_MARK_STRING - maybe named param unrecognised param kind"; + } + + str += param_type->as_string(); + + return str; + } + + ::std::string MetaItemSeq::as_string() const { + ::std::string path_str = path.as_string() + "("; + + for (const auto& item : seq) { + path_str += item->as_string() + ", "; + } + + return path_str + ")"; + } + + ::std::string MetaListPaths::as_string() const { + ::std::string str = ident + "("; + + for (const auto& path : paths) { + str += path.as_string() + ", "; + } + + return str + ")"; + } + + ::std::string MetaListNameValueStr::as_string() const { + ::std::string str = ident + "("; + + for (const auto& elem : strs) { + str += elem.as_string() + ", "; + } + + return str + ")"; + } + + ::std::string AttrInputMetaItemContainer::as_string() const { + ::std::string str = "("; + + for (const auto& item : items) { + str += item->as_string() + ", "; + } + + return str + ")"; + } + + // Override that calls the function recursively on all items contained within the module. + void ModuleBodied::add_crate_name(::std::vector< ::std::string>& names) const { + /* TODO: test whether module has been 'cfg'-ed out to determine whether to exclude it + * from search */ + + for (const auto& item : items) { + item->add_crate_name(names); + } + } + + void Attribute::parse_attr_to_meta_item() { + // only parse if has attribute input + if (!has_attr_input()) { + return; + } + + ::std::unique_ptr<AttrInput> converted_input(attr_input->parse_to_meta_item()); + + if (converted_input != NULL) { + attr_input = ::std::move(converted_input); + } + } + + AttrInput* DelimTokenTree::parse_to_meta_item() const { + // must have token trees + if (token_trees.empty()) { + return NULL; + } + + // assume top-level delim token tree in attribute - convert all nested ones to token + // stream + ::std::vector< ::std::unique_ptr<Token> > token_stream = to_token_stream(); + + // TODO: replace this with a specialised converter that the token stream is moved into + /*int i = 0; + ::std::vector< ::std::unique_ptr<MetaItemInner> > meta_items( + parse_meta_item_seq(token_stream, i));*/ + // something like: + MacroParser parser(::std::move(token_stream)); + ::std::vector< ::std::unique_ptr<MetaItemInner> > meta_items( + parser.parse_meta_item_seq()); + + return new AttrInputMetaItemContainer(::std::move(meta_items)); + } + + ::std::unique_ptr<MetaItemInner> MacroParser::parse_meta_item_inner() { + // if first tok not identifier, not a "special" case one + if (peek_token()->get_id() != IDENTIFIER) { + switch (peek_token()->get_id()) { + case CHAR_LITERAL: + case STRING_LITERAL: + case BYTE_CHAR_LITERAL: + case BYTE_STRING_LITERAL: + case INT_LITERAL: + case FLOAT_LITERAL: + case TRUE_LITERAL: + case FALSE_LITERAL: + // stream_pos++; + return parse_meta_item_lit(); + case SUPER: + case SELF: + case CRATE: + case DOLLAR_SIGN: + case SCOPE_RESOLUTION: { + return parse_path_meta_item(); + } + default: + error_at(peek_token()->get_locus(), "unrecognised token '%s' in meta item", + get_token_description(peek_token()->get_id())); + return NULL; + } + } + + // else, check for path + if (peek_token(1)->get_id() == SCOPE_RESOLUTION) { + // path + return parse_path_meta_item(); + } + + Identifier ident = peek_token()->as_string(); + if (is_end_meta_item_tok(peek_token(1)->get_id())) { + // meta word syntax + skip_token(); + return ::std::unique_ptr<MetaWord>(new MetaWord(::std::move(ident))); + } + + if (peek_token(1)->get_id() == EQUAL) { + // maybe meta name value str syntax - check next 2 tokens + if (peek_token(2)->get_id() == STRING_LITERAL + && is_end_meta_item_tok(peek_token(3)->get_id())) { + // meta name value str syntax + ::std::string value = peek_token(2)->as_string(); + + skip_token(2); + + return ::std::unique_ptr<MetaNameValueStr>( + new MetaNameValueStr(::std::move(ident), ::std::move(value))); + } else { + // just interpret as path-based meta item + return parse_path_meta_item(); + } + } + + if (peek_token(1)->get_id() != LEFT_PAREN) { + error_at(peek_token(1)->get_locus(), + "unexpected token '%s' after identifier in attribute", + get_token_description(peek_token(1)->get_id())); + return NULL; + } + + // HACK: parse parenthesised sequence, and then try conversions to other stuff + ::std::vector< ::std::unique_ptr<MetaItemInner> > meta_items = parse_meta_item_seq(); + + // pass for meta name value str + ::std::vector<MetaNameValueStr> meta_name_value_str_items; + for (const auto& item : meta_items) { + ::std::unique_ptr<MetaNameValueStr> converted_item(item->to_meta_name_value_str()); + if (converted_item == NULL) { + meta_name_value_str_items.clear(); + break; + } + meta_name_value_str_items.push_back(::std::move(*converted_item)); + } + // if valid, return this + if (!meta_name_value_str_items.empty()) { + return ::std::unique_ptr<MetaListNameValueStr>(new MetaListNameValueStr( + ::std::move(ident), ::std::move(meta_name_value_str_items))); + } + + // pass for meta list idents + /*::std::vector<Identifier> ident_items; + for (const auto& item : meta_items) { + ::std::unique_ptr<Identifier> converted_ident(item->to_ident_item()); + if (converted_ident == NULL) { + ident_items.clear(); + break; + } + ident_items.push_back(::std::move(*converted_ident)); + } + // if valid return this + if (!ident_items.empty()) { + return ::std::unique_ptr<MetaListIdents>(new MetaListIdents(::std::move(ident), + ::std::move(ident_items))); + }*/ + // as currently no meta list ident, currently no path. may change in future + + // pass for meta list paths + ::std::vector<SimplePath> path_items; + for (const auto& item : meta_items) { + SimplePath converted_path(item->to_path_item()); + if (converted_path.is_empty()) { + path_items.clear(); + break; + } + path_items.push_back(::std::move(converted_path)); + } + if (!path_items.empty()) { + return ::std::unique_ptr<MetaListPaths>( + new MetaListPaths(::std::move(ident), ::std::move(path_items))); + } + + error_at(UNKNOWN_LOCATION, "failed to parse any meta item inner"); + return NULL; + } + + bool MacroParser::is_end_meta_item_tok(TokenId id) const { + return id == COMMA || id == RIGHT_PAREN; + } + + ::std::unique_ptr<MetaItem> MacroParser::parse_path_meta_item() { + SimplePath path = parse_simple_path(); + if (path.is_empty()) { + error_at(peek_token()->get_locus(), "failed to parse simple path in attribute"); + return NULL; + } + + switch (peek_token()->get_id()) { + case LEFT_PAREN: { + ::std::vector< ::std::unique_ptr<MetaItemInner> > meta_items + = parse_meta_item_seq(); + + return ::std::unique_ptr<MetaItemSeq>( + new MetaItemSeq(::std::move(path), ::std::move(meta_items))); + } + case EQUAL: { + skip_token(); + + location_t locus = peek_token()->get_locus(); + Literal lit = parse_literal(); + if (lit.is_error()) { + error_at(peek_token()->get_locus(), "failed to parse literal in attribute"); + return NULL; + } + LiteralExpr expr(::std::move(lit), locus); + // stream_pos++; + // shouldn't be required anymore due to parsing literal actually skipping the + // token + return ::std::unique_ptr<MetaItemPathLit>( + new MetaItemPathLit(::std::move(path), ::std::move(expr))); + } + case COMMA: + // just simple path + return ::std::unique_ptr<MetaItemPath>(new MetaItemPath(::std::move(path))); + default: + error_at(peek_token()->get_locus(), "unrecognised token '%s' in meta item", + get_token_description(peek_token()->get_id())); + return NULL; + } + } + + // Parses a parenthesised sequence of meta item inners. Parentheses are required here. + ::std::vector< ::std::unique_ptr<MetaItemInner> > MacroParser::parse_meta_item_seq() { + if (stream_pos != 0) { + // warning? + fprintf(stderr, "WARNING: stream pos for parse_meta_item_seq is not 0!\n"); + } + + // int i = 0; + int vec_length = token_stream.size(); + ::std::vector< ::std::unique_ptr<MetaItemInner> > meta_items; + + if (peek_token()->get_id() != LEFT_PAREN) { + error_at(peek_token()->get_locus(), "missing left paren in delim token tree"); + return {}; + } + skip_token(); + + while (stream_pos < vec_length && peek_token()->get_id() != RIGHT_PAREN) { + ::std::unique_ptr<MetaItemInner> inner = parse_meta_item_inner(); + if (inner == NULL) { + error_at( + peek_token()->get_locus(), "failed to parse inner meta item in attribute"); + return {}; + } + meta_items.push_back(::std::move(inner)); + + if (peek_token()->get_id() != COMMA) { + break; + } + skip_token(); + } + + if (peek_token()->get_id() != RIGHT_PAREN) { + error_at(peek_token()->get_locus(), "missing right paren in delim token tree"); + return {}; + } + skip_token(); + + return meta_items; + } + + // Collects any nested token trees into a flat token stream, suitable for parsing. + ::std::vector< ::std::unique_ptr<Token> > DelimTokenTree::to_token_stream() const { + ::std::vector< ::std::unique_ptr<Token> > tokens; + + // simulate presence of delimiters + tokens.push_back(::std::unique_ptr<Token>( + new Token(LEFT_PAREN, UNKNOWN_LOCATION, "", CORETYPE_UNKNOWN))); + + for (const auto& tree : token_trees) { + ::std::vector< ::std::unique_ptr<Token> > stream = tree->to_token_stream(); + + tokens.insert(tokens.end(), ::std::make_move_iterator(stream.begin()), + ::std::make_move_iterator(stream.end())); + } + + tokens.push_back(::std::unique_ptr<Token>( + new Token(RIGHT_PAREN, UNKNOWN_LOCATION, "", CORETYPE_UNKNOWN))); + + tokens.shrink_to_fit(); + + return tokens; + } + + Literal MacroParser::parse_literal() { + const ::std::unique_ptr<Token>& tok = peek_token(); + switch (tok->get_id()) { + case CHAR_LITERAL: + skip_token(); + return Literal(tok->as_string(), Literal::CHAR); + case STRING_LITERAL: + skip_token(); + return Literal(tok->as_string(), Literal::STRING); + case BYTE_CHAR_LITERAL: + skip_token(); + return Literal(tok->as_string(), Literal::BYTE); + case BYTE_STRING_LITERAL: + skip_token(); + return Literal(tok->as_string(), Literal::BYTE_STRING); + case INT_LITERAL: + skip_token(); + return Literal(tok->as_string(), Literal::INT); + case FLOAT_LITERAL: + skip_token(); + return Literal(tok->as_string(), Literal::FLOAT); + case TRUE_LITERAL: + skip_token(); + return Literal("true", Literal::BOOL); + case FALSE_LITERAL: + skip_token(); + return Literal("false", Literal::BOOL); + default: + error_at(tok->get_locus(), "expected literal - found '%s'", + get_token_description(tok->get_id())); + return Literal::create_error(); + } + } + + SimplePath MacroParser::parse_simple_path() { + bool has_opening_scope_res = false; + if (peek_token()->get_id() == SCOPE_RESOLUTION) { + has_opening_scope_res = true; + skip_token(); + } + + ::std::vector<SimplePathSegment> segments; + + SimplePathSegment segment = parse_simple_path_segment(); + if (segment.is_error()) { + error_at(peek_token()->get_locus(), + "failed to parse simple path segment in attribute simple path"); + return SimplePath::create_empty(); + } + segments.push_back(::std::move(segment)); + + while (peek_token()->get_id() == SCOPE_RESOLUTION) { + skip_token(); + + SimplePathSegment segment = parse_simple_path_segment(); + if (segment.is_error()) { + error_at(peek_token()->get_locus(), + "failed to parse simple path segment in attribute simple path"); + return SimplePath::create_empty(); + } + segments.push_back(::std::move(segment)); + } + segments.shrink_to_fit(); + + return SimplePath(::std::move(segments), has_opening_scope_res); + } + + SimplePathSegment MacroParser::parse_simple_path_segment() { + const ::std::unique_ptr<Token>& tok = peek_token(); + switch (tok->get_id()) { + case IDENTIFIER: + skip_token(); + return SimplePathSegment(tok->as_string(), tok->get_locus()); + case SUPER: + skip_token(); + return SimplePathSegment("super", tok->get_locus()); + case SELF: + skip_token(); + return SimplePathSegment("self", tok->get_locus()); + case CRATE: + skip_token(); + return SimplePathSegment("crate", tok->get_locus()); + case DOLLAR_SIGN: + if (peek_token(1)->get_id() == CRATE) { + skip_token(1); + return SimplePathSegment("$crate", tok->get_locus()); + } + gcc_fallthrough(); + default: + error_at(tok->get_locus(), "unexpected token '%s' in simple path segment", + get_token_description(tok->get_id())); + return SimplePathSegment::create_error(); + } + } + + ::std::unique_ptr<MetaItemLitExpr> MacroParser::parse_meta_item_lit() { + location_t locus = peek_token()->get_locus(); + LiteralExpr lit_expr(parse_literal(), locus); + return ::std::unique_ptr<MetaItemLitExpr>(new MetaItemLitExpr(::std::move(lit_expr))); + } + + bool AttrInputMetaItemContainer::check_cfg_predicate(const Session& session) const { + // cfg value of container is purely based on cfg of each inner item - all must be true + for (const auto& inner_item : items) { + if (!inner_item->check_cfg_predicate(session)) { + return false; + } + } + + /* TODO: as far as I can tell, there should only be a single element to check here, so + * ensure there is only a single element in items too? */ + + return true; + } + + bool MetaItemLitExpr::check_cfg_predicate(const Session& session ATTRIBUTE_UNUSED) const { + // as far as I can tell, a literal expr can never be a valid cfg body, so false + return false; + } + + bool MetaListNameValueStr::check_cfg_predicate(const Session& session) const { + if (ident == "all") { + for (const auto& str : strs) { + if (!str.check_cfg_predicate(session)) { + return false; + } + } + return true; + } else if (ident == "any") { + for (const auto& str : strs) { + if (str.check_cfg_predicate(session)) { + return true; + } + } + return false; + } else if (ident == "not") { + if (strs.size() != 1) { + // HACK: convert vector platform-dependent size_type to string to use in printf + error_at(UNKNOWN_LOCATION, + "cfg predicate could not be checked for MetaListNameValueStr with ident of " + "'not' because there are '%s' elements, not '1'", + ::std::to_string(strs.size()).c_str()); + return false; + } + + return !strs[0].check_cfg_predicate(session); + } else { + error_at(UNKNOWN_LOCATION, + "cfg predicate could not be checked for MetaListNameValueStr with ident of " + "'%s' - ident must be 'all' or 'any'", + ident.c_str()); + return false; + } + } + + bool MetaListPaths::check_cfg_predicate(const Session& session) const { + if (ident == "all") { + for (const auto& path : paths) { + if (!check_path_exists_in_cfg(session, path)) { + return false; + } + } + return true; + } else if (ident == "any") { + for (const auto& path : paths) { + if (check_path_exists_in_cfg(session, path)) { + return true; + } + } + return false; + } else if (ident == "not") { + if (paths.size() != 1) { + // HACK: convert vector platform-dependent size_type to string to use in printf + error_at(UNKNOWN_LOCATION, + "cfg predicate could not be checked for MetaListPaths with ident of 'not' " + "because there are '%s' elements, not '1'", + ::std::to_string(paths.size()).c_str()); + return false; + } + + return !check_path_exists_in_cfg(session, paths[0]); + } else { + error_at(UNKNOWN_LOCATION, + "cfg predicate could not be checked for MetaListNameValueStr with ident of " + "'%s' - ident must be 'all' or 'any'", + ident.c_str()); + return false; + } + } + + bool MetaListPaths::check_path_exists_in_cfg( + const Session& session, const SimplePath& path) const { + auto it = session.options.target_data.features.find(path.as_string()); + if (it != session.options.target_data.features.end()) { + return true; + } + return false; + } + + bool MetaItemSeq::check_cfg_predicate(const Session& session) const { + if (path.as_string() == "all") { + for (const auto& item : seq) { + if (!item->check_cfg_predicate(session)) { + return false; + } + } + return true; + } else if (path.as_string() == "any") { + for (const auto& item : seq) { + if (item->check_cfg_predicate(session)) { + return true; + } + } + return false; + } else if (path.as_string() == "not") { + if (seq.size() != 1) { + // HACK: convert vector platform-dependent size_type to string to use in printf + error_at(UNKNOWN_LOCATION, + "cfg predicate could not be checked for MetaItemSeq with ident of 'not' " + "because there are '%s' elements, not '1'", + ::std::to_string(seq.size()).c_str()); + return false; + } + + return !seq[0]->check_cfg_predicate(session); + } else { + error_at(UNKNOWN_LOCATION, + "cfg predicate could not be checked for MetaItemSeq with path of " + "'%s' - path must be 'all' or 'any'", + path.as_string().c_str()); + return false; + } + } + + bool MetaWord::check_cfg_predicate(const Session& session) const { + auto it = session.options.target_data.features.find(ident); + if (it != session.options.target_data.features.end()) { + return true; + } + return false; + } + + bool MetaItemPath::check_cfg_predicate(const Session& session) const { + /* Strictly speaking, this should always be false, but maybe do check relating to + * SimplePath being identifier. Currently, it would return true if path as identifier + * existed, and if the path in string form existed (though this shouldn't occur). */ + auto it = session.options.target_data.features.find(path.as_string()); + if (it != session.options.target_data.features.end()) { + return true; + } + return false; + } + + bool MetaNameValueStr::check_cfg_predicate(const Session& session) const { + auto it = session.options.target_data.features.find(ident); + if (it != session.options.target_data.features.end()) { + // value must also be the same, not just the name existing + if (str == it->second) { + return true; + } + } + return false; + } + + bool MetaItemPathLit::check_cfg_predicate(const Session& session) const { + auto it = session.options.target_data.features.find(path.as_string()); + if (it != session.options.target_data.features.end()) { + // value must also be the same, not just the name existing + if (lit.as_string() == it->second) { + return true; + } + } + return false; + } + + ::std::vector< ::std::unique_ptr<Token> > Token::to_token_stream() const { + // initialisation list doesn't work as it needs copy constructor, so have to do this + ::std::vector< ::std::unique_ptr<Token> > dummy_vector; + dummy_vector.reserve(1); + dummy_vector.push_back(::std::unique_ptr<Token>(clone_token_impl())); + return dummy_vector; + } + + /* Visitor implementations - these are short but inlining can't happen anyway due to virtual + * functions and I didn't want to make the ast header includes any longer than they already + * are. */ + + void Token::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void DelimTokenTree::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void IdentifierExpr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void Lifetime::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void LifetimeParam::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void MacroInvocationSemi::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void PathInExpression::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void TypePathSegment::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void TypePathSegmentGeneric::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void TypePathSegmentFunction::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void TypePath::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void QualifiedPathInExpression::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void QualifiedPathInType::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void LiteralExpr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void AttrInputLiteral::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void MetaItemLitExpr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void MetaItemPathLit::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void BorrowExpr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void DereferenceExpr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void ErrorPropagationExpr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void NegationExpr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void ArithmeticOrLogicalExpr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void ComparisonExpr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void LazyBooleanExpr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void TypeCastExpr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void AssignmentExpr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void CompoundAssignmentExpr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void GroupedExpr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void ArrayElemsValues::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void ArrayElemsCopied::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void ArrayExpr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void ArrayIndexExpr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void TupleExpr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void TupleIndexExpr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void StructExprStruct::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void StructExprFieldIdentifier::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void StructExprFieldIdentifierValue::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void StructExprFieldIndexValue::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void StructExprStructFields::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void StructExprStructBase::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void StructExprTuple::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void StructExprUnit::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void EnumExprFieldIdentifier::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void EnumExprFieldIdentifierValue::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void EnumExprFieldIndexValue::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void EnumExprStruct::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void EnumExprTuple::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void EnumExprFieldless::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void CallExpr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void MethodCallExpr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void FieldAccessExpr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void ClosureExprInner::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void BlockExpr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void ClosureExprInnerTyped::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void ContinueExpr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void BreakExpr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void RangeFromToExpr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void RangeFromExpr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void RangeToExpr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void RangeFullExpr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void RangeFromToInclExpr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void RangeToInclExpr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void ReturnExpr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void UnsafeBlockExpr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void LoopExpr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void WhileLoopExpr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void WhileLetLoopExpr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void ForLoopExpr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void IfExpr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void IfExprConseqElse::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void IfExprConseqIf::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void IfExprConseqIfLet::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void IfLetExpr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void IfLetExprConseqElse::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void IfLetExprConseqIf::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void IfLetExprConseqIfLet::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void MatchCaseBlockExpr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void MatchCaseExpr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void MatchExpr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void AwaitExpr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void AsyncBlockExpr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void TypeParam::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void LifetimeWhereClauseItem::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void TypeBoundWhereClauseItem::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void Method::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void ModuleBodied::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void ModuleNoBody::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void ExternCrate::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void UseTreeGlob::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void UseTreeList::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void UseTreeRebind::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void UseDeclaration::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void Function::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void TypeAlias::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void StructStruct::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void TupleStruct::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void EnumItem::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void EnumItemTuple::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void EnumItemStruct::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void EnumItemDiscriminant::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void Enum::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void Union::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void ConstantItem::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void StaticItem::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void TraitItemFunc::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void TraitItemMethod::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void TraitItemConst::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void TraitItemType::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void Trait::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void InherentImpl::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void TraitImpl::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void ExternalStaticItem::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void ExternalFunctionItem::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void ExternBlock::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void MacroMatchFragment::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void MacroMatchRepetition::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void MacroMatcher::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void MacroRulesDefinition::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void MacroInvocation::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void LiteralPattern::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void IdentifierPattern::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void WildcardPattern::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void RangePatternBoundLiteral::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void RangePatternBoundPath::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void RangePatternBoundQualPath::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void RangePattern::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void ReferencePattern::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void StructPatternFieldTuplePat::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void StructPatternFieldIdentPat::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void StructPatternFieldIdent::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void StructPattern::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void TupleStructItemsNoRange::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void TupleStructItemsRange::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void TupleStructPattern::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void TuplePatternItemsMultiple::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void TuplePatternItemsRanged::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void TuplePattern::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void GroupedPattern::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void SlicePattern::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void EmptyStmt::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void LetStmt::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void ExprStmtWithoutBlock::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void ExprStmtWithBlock::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void TraitBound::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void ImplTraitType::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void TraitObjectType::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void ParenthesisedType::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void ImplTraitTypeOneBound::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void TraitObjectTypeOneBound::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void TupleType::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void NeverType::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void RawPointerType::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void ReferenceType::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void ArrayType::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void SliceType::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void InferredType::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void BareFunctionType::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void MetaItemSeq::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void MetaItemPath::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void MetaListPaths::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void MetaNameValueStr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void MetaListNameValueStr::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void AttrInputMetaItemContainer::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } + + void MetaWord::accept_vis(ASTVisitor& vis) { + vis.visit(*this); + } } }
\ No newline at end of file diff --git a/gcc/rust/test3/ast/rust-ast-visitor.h b/gcc/rust/test3/ast/rust-ast-visitor.h new file mode 100644 index 0000000..b8e92c2 --- /dev/null +++ b/gcc/rust/test3/ast/rust-ast-visitor.h @@ -0,0 +1,224 @@ +#ifndef RUST_AST_VISITOR_H +#define RUST_AST_VISITOR_H +// Visitor base for AST + +// full include not required - only forward decls +#include "rust-ast-full-decls.h" + +namespace Rust { + namespace AST { + // Pure abstract class that provides an interface for accessing different classes of the AST. + class ASTVisitor { + public: + // only concrete class overloads are required + + // rust-ast.h + //virtual void visit(AttrInput& attr_input) = 0; + //virtual void visit(TokenTree& token_tree) = 0; + //virtual void visit(MacroMatch& macro_match) = 0; + virtual void visit(Token& tok) = 0; + virtual void visit(DelimTokenTree& delim_tok_tree) = 0; + virtual void visit(AttrInputMetaItemContainer& input) = 0; + //virtual void visit(MetaItem& meta_item) = 0; + //virtual void visit(Stmt& stmt) = 0; + //virtual void visit(Expr& expr) = 0; + virtual void visit(IdentifierExpr& ident_expr) = 0; + //virtual void visit(Pattern& pattern) = 0; + //virtual void visit(Type& type) = 0; + //virtual void visit(TypeParamBound& type_param_bound) = 0; + virtual void visit(Lifetime& lifetime) = 0; + //virtual void visit(GenericParam& generic_param) = 0; + virtual void visit(LifetimeParam& lifetime_param) = 0; + //virtual void visit(TraitItem& trait_item) = 0; + //virtual void visit(InherentImplItem& inherent_impl_item) = 0; + //virtual void visit(TraitImplItem& trait_impl_item) = 0; + virtual void visit(MacroInvocationSemi& macro) = 0; + + // rust-path.h + virtual void visit(PathInExpression& path) = 0; + virtual void visit(TypePathSegment& segment) = 0; + virtual void visit(TypePathSegmentGeneric& segment) = 0; + virtual void visit(TypePathSegmentFunction& segment) = 0; + virtual void visit(TypePath& path) = 0; + virtual void visit(QualifiedPathInExpression& path) = 0; + virtual void visit(QualifiedPathInType& path) = 0; + + // rust-expr.h + virtual void visit(LiteralExpr& expr) = 0; + virtual void visit(AttrInputLiteral& attr_input) = 0; + virtual void visit(MetaItemLitExpr& meta_item) = 0; + virtual void visit(MetaItemPathLit& meta_item) = 0; + virtual void visit(BorrowExpr& expr) = 0; + virtual void visit(DereferenceExpr& expr) = 0; + virtual void visit(ErrorPropagationExpr& expr) = 0; + virtual void visit(NegationExpr& expr) = 0; + virtual void visit(ArithmeticOrLogicalExpr& expr) = 0; + virtual void visit(ComparisonExpr& expr) = 0; + virtual void visit(LazyBooleanExpr& expr) = 0; + virtual void visit(TypeCastExpr& expr) = 0; + virtual void visit(AssignmentExpr& expr) = 0; + virtual void visit(CompoundAssignmentExpr& expr) = 0; + virtual void visit(GroupedExpr& expr) = 0; + //virtual void visit(ArrayElems& elems) = 0; + virtual void visit(ArrayElemsValues& elems) = 0; + virtual void visit(ArrayElemsCopied& elems) = 0; + virtual void visit(ArrayExpr& expr) = 0; + virtual void visit(ArrayIndexExpr& expr) = 0; + virtual void visit(TupleExpr& expr) = 0; + virtual void visit(TupleIndexExpr& expr) = 0; + virtual void visit(StructExprStruct& expr) = 0; + //virtual void visit(StructExprField& field) = 0; + virtual void visit(StructExprFieldIdentifier& field) = 0; + virtual void visit(StructExprFieldIdentifierValue& field) = 0; + virtual void visit(StructExprFieldIndexValue& field) = 0; + virtual void visit(StructExprStructFields& expr) = 0; + virtual void visit(StructExprStructBase& expr) = 0; + virtual void visit(StructExprTuple& expr) = 0; + virtual void visit(StructExprUnit& expr) = 0; + //virtual void visit(EnumExprField& field) = 0; + virtual void visit(EnumExprFieldIdentifier& field) = 0; + virtual void visit(EnumExprFieldIdentifierValue& field) = 0; + virtual void visit(EnumExprFieldIndexValue& field) = 0; + virtual void visit(EnumExprStruct& expr) = 0; + virtual void visit(EnumExprTuple& expr) = 0; + virtual void visit(EnumExprFieldless& expr) = 0; + virtual void visit(CallExpr& expr) = 0; + virtual void visit(MethodCallExpr& expr) = 0; + virtual void visit(FieldAccessExpr& expr) = 0; + virtual void visit(ClosureExprInner& expr) = 0; + virtual void visit(BlockExpr& expr) = 0; + virtual void visit(ClosureExprInnerTyped& expr) = 0; + virtual void visit(ContinueExpr& expr) = 0; + virtual void visit(BreakExpr& expr) = 0; + virtual void visit(RangeFromToExpr& expr) = 0; + virtual void visit(RangeFromExpr& expr) = 0; + virtual void visit(RangeToExpr& expr) = 0; + virtual void visit(RangeFullExpr& expr) = 0; + virtual void visit(RangeFromToInclExpr& expr) = 0; + virtual void visit(RangeToInclExpr& expr) = 0; + virtual void visit(ReturnExpr& expr) = 0; + virtual void visit(UnsafeBlockExpr& expr) = 0; + virtual void visit(LoopExpr& expr) = 0; + virtual void visit(WhileLoopExpr& expr) = 0; + virtual void visit(WhileLetLoopExpr& expr) = 0; + virtual void visit(ForLoopExpr& expr) = 0; + virtual void visit(IfExpr& expr) = 0; + virtual void visit(IfExprConseqElse& expr) = 0; + virtual void visit(IfExprConseqIf& expr) = 0; + virtual void visit(IfExprConseqIfLet& expr) = 0; + virtual void visit(IfLetExpr& expr) = 0; + virtual void visit(IfLetExprConseqElse& expr) = 0; + virtual void visit(IfLetExprConseqIf& expr) = 0; + virtual void visit(IfLetExprConseqIfLet& expr) = 0; + //virtual void visit(MatchCase& match_case) = 0; + virtual void visit(MatchCaseBlockExpr& match_case) = 0; + virtual void visit(MatchCaseExpr& match_case) = 0; + virtual void visit(MatchExpr& expr) = 0; + virtual void visit(AwaitExpr& expr) = 0; + virtual void visit(AsyncBlockExpr& expr) = 0; + + // rust-item.h + virtual void visit(TypeParam& param) = 0; + //virtual void visit(WhereClauseItem& item) = 0; + virtual void visit(LifetimeWhereClauseItem& item) = 0; + virtual void visit(TypeBoundWhereClauseItem& item) = 0; + virtual void visit(Method& method) = 0; + virtual void visit(ModuleBodied& module) = 0; + virtual void visit(ModuleNoBody& module) = 0; + virtual void visit(ExternCrate& crate) = 0; + //virtual void visit(UseTree& use_tree) = 0; + virtual void visit(UseTreeGlob& use_tree) = 0; + virtual void visit(UseTreeList& use_tree) = 0; + virtual void visit(UseTreeRebind& use_tree) = 0; + virtual void visit(UseDeclaration& use_decl) = 0; + virtual void visit(Function& function) = 0; + virtual void visit(TypeAlias& type_alias) = 0; + virtual void visit(StructStruct& struct_item) = 0; + virtual void visit(TupleStruct& tuple_struct) = 0; + virtual void visit(EnumItem& item) = 0; + virtual void visit(EnumItemTuple& item) = 0; + virtual void visit(EnumItemStruct& item) = 0; + virtual void visit(EnumItemDiscriminant& item) = 0; + virtual void visit(Enum& enum_item) = 0; + virtual void visit(Union& union_item) = 0; + virtual void visit(ConstantItem& const_item) = 0; + virtual void visit(StaticItem& static_item) = 0; + virtual void visit(TraitItemFunc& item) = 0; + virtual void visit(TraitItemMethod& item) = 0; + virtual void visit(TraitItemConst& item) = 0; + virtual void visit(TraitItemType& item) = 0; + virtual void visit(Trait& trait) = 0; + virtual void visit(InherentImpl& impl) = 0; + virtual void visit(TraitImpl& impl) = 0; + //virtual void visit(ExternalItem& item) = 0; + virtual void visit(ExternalStaticItem& item) = 0; + virtual void visit(ExternalFunctionItem& item) = 0; + virtual void visit(ExternBlock& block) = 0; + + // rust-macro.h + virtual void visit(MacroMatchFragment& match) = 0; + virtual void visit(MacroMatchRepetition& match) = 0; + virtual void visit(MacroMatcher& matcher) = 0; + virtual void visit(MacroRulesDefinition& rules_def) = 0; + virtual void visit(MacroInvocation& macro_invoc) = 0; + virtual void visit(MetaItemPath& meta_item) = 0; + virtual void visit(MetaItemSeq& meta_item) = 0; + virtual void visit(MetaWord& meta_item) = 0; + virtual void visit(MetaNameValueStr& meta_item) = 0; + virtual void visit(MetaListPaths& meta_item) = 0; + virtual void visit(MetaListNameValueStr& meta_item) = 0; + + // rust-pattern.h + virtual void visit(LiteralPattern& pattern) = 0; + virtual void visit(IdentifierPattern& pattern) = 0; + virtual void visit(WildcardPattern& pattern) = 0; + //virtual void visit(RangePatternBound& bound) = 0; + virtual void visit(RangePatternBoundLiteral& bound) = 0; + virtual void visit(RangePatternBoundPath& bound) = 0; + virtual void visit(RangePatternBoundQualPath& bound) = 0; + virtual void visit(RangePattern& pattern) = 0; + virtual void visit(ReferencePattern& pattern) = 0; + //virtual void visit(StructPatternField& field) = 0; + virtual void visit(StructPatternFieldTuplePat& field) = 0; + virtual void visit(StructPatternFieldIdentPat& field) = 0; + virtual void visit(StructPatternFieldIdent& field) = 0; + virtual void visit(StructPattern& pattern) = 0; + //virtual void visit(TupleStructItems& tuple_items) = 0; + virtual void visit(TupleStructItemsNoRange& tuple_items) = 0; + virtual void visit(TupleStructItemsRange& tuple_items) = 0; + virtual void visit(TupleStructPattern& pattern) = 0; + //virtual void visit(TuplePatternItems& tuple_items) = 0; + virtual void visit(TuplePatternItemsMultiple& tuple_items) = 0; + virtual void visit(TuplePatternItemsRanged& tuple_items) = 0; + virtual void visit(TuplePattern& pattern) = 0; + virtual void visit(GroupedPattern& pattern) = 0; + virtual void visit(SlicePattern& pattern) = 0; + + // rust-stmt.h + virtual void visit(EmptyStmt& stmt) = 0; + virtual void visit(LetStmt& stmt) = 0; + virtual void visit(ExprStmtWithoutBlock& stmt) = 0; + virtual void visit(ExprStmtWithBlock& stmt) = 0; + + // rust-type.h + virtual void visit(TraitBound& bound) = 0; + virtual void visit(ImplTraitType& type) = 0; + virtual void visit(TraitObjectType& type) = 0; + virtual void visit(ParenthesisedType& type) = 0; + virtual void visit(ImplTraitTypeOneBound& type) = 0; + virtual void visit(TraitObjectTypeOneBound& type) = 0; + virtual void visit(TupleType& type) = 0; + virtual void visit(NeverType& type) = 0; + virtual void visit(RawPointerType& type) = 0; + virtual void visit(ReferenceType& type) = 0; + virtual void visit(ArrayType& type) = 0; + virtual void visit(SliceType& type) = 0; + virtual void visit(InferredType& type) = 0; + virtual void visit(BareFunctionType& type) = 0; + + // TODO: rust-cond-compilation.h visiting? not currently used + }; + } +} + +#endif
\ No newline at end of file diff --git a/gcc/rust/test3/ast/rust-ast.h b/gcc/rust/test3/ast/rust-ast.h index 87faa1a..fb0cd23 100644 --- a/gcc/rust/test3/ast/rust-ast.h +++ b/gcc/rust/test3/ast/rust-ast.h @@ -26,12 +26,17 @@ namespace Rust { typedef ::std::string Identifier; typedef int TupleIndex; + struct Session; + namespace AST { + // foward decl: ast visitor + class ASTVisitor; + // Delimiter types - used in macros and whatever. enum DelimType { PARENS, SQUARE, CURLY }; // Base AST node object - TODO is this really required or useful? Where to draw line? - class Node { + /*class Node { public: // Gets node's location_t. location_t get_locus() const { @@ -48,10 +53,13 @@ namespace Rust { virtual ~Node() {} + // TODO: constructor including location_t? Make all derived classes have location_t? + private: // The node's location. location_t loc; - }; + };*/ + // decided to not have node as a "node" would never need to be stored // Attribute body - abstract base class class AttrInput { @@ -65,11 +73,23 @@ namespace Rust { virtual ::std::string as_string() const = 0; + virtual void accept_vis(ASTVisitor& vis) = 0; + + virtual bool check_cfg_predicate(const Session& session) const = 0; + + // Parse attribute input to meta item, if possible + virtual AttrInput* parse_to_meta_item() const { + return NULL; + } + protected: // pure virtual clone implementation virtual AttrInput* clone_attr_input_impl() const = 0; }; + // forward decl for use in token tree method + class Token; + // A tree of tokens (or a single token) - abstract base class class TokenTree { public: @@ -82,6 +102,12 @@ namespace Rust { virtual ::std::string as_string() const = 0; + virtual void accept_vis(ASTVisitor& vis) = 0; + + /* Converts token tree to a flat token stream. Tokens must be pointer to avoid mutual + * dependency with Token. */ + virtual ::std::vector< ::std::unique_ptr<Token> > to_token_stream() const = 0; + protected: // pure virtual clone implementation virtual TokenTree* clone_token_tree_impl() const = 0; @@ -99,6 +125,8 @@ namespace Rust { return ::std::unique_ptr<MacroMatch>(clone_macro_match_impl()); } + virtual void accept_vis(ASTVisitor& vis) = 0; + protected: // pure virtual clone implementation virtual MacroMatch* clone_macro_match_impl() const = 0; @@ -126,6 +154,12 @@ namespace Rust { return ::std::unique_ptr<Token>(clone_token_impl()); } + // constructor from general text - avoid using if lexer const_TokenPtr is available + Token( + TokenId token_id, location_t locus, ::std::string str, PrimitiveCoreType type_hint) : + token_id(token_id), + locus(locus), str(::std::move(str)), type_hint(type_hint) {} + // Constructor from lexer const_TokenPtr /* TODO: find workaround for std::string being NULL - probably have to introduce new * method in lexer Token, or maybe make conversion method there*/ @@ -155,6 +189,19 @@ namespace Rust { ::std::string as_string() const; + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + + // Return copy of itself but in token stream form. + virtual ::std::vector< ::std::unique_ptr<Token> > to_token_stream() const OVERRIDE; + + TokenId get_id() const { + return token_id; + } + + location_t get_locus() const { + return locus; + } + protected: // No virtual for now as not polymorphic but can be in future /*virtual*/ Token* clone_token_impl() const { @@ -204,6 +251,15 @@ namespace Rust { Literal(::std::string value_as_string, LitType type) : value_as_string(::std::move(value_as_string)), type(type) {} + + static Literal create_error() { + return Literal("", CHAR); + } + + // Returns whether literal is in an invalid state. + bool is_error() const { + return value_as_string == ""; + } }; // A token tree with delimiters @@ -213,6 +269,24 @@ namespace Rust { DelimType delim_type; ::std::vector< ::std::unique_ptr<TokenTree> > token_trees; + location_t locus; + + // TODO: move all the "parse" functions into a separate class that has the token stream + // reference - will be cleaner Parse a meta item inner. + //::std::unique_ptr<MetaItemInner> parse_meta_item_inner(const ::std::vector< + //::std::unique_ptr<Token> >& token_stream, int& i) const; SimplePath + // parse_simple_path(const ::std::vector< ::std::unique_ptr<Token> >& token_stream, int& i) + // const; SimplePathSegment parse_simple_path_segment(const ::std::vector< + // ::std::unique_ptr<Token> >& token_stream, int& i) const; + //::std::unique_ptr<MetaItemLitExpr> parse_meta_item_lit(const ::std::unique_ptr<Token>& + //tok) const; + //::std::vector< ::std::unique_ptr<MetaItemInner> > parse_meta_item_seq(const + //::std::vector< ::std::unique_ptr<Token> >& token_stream, int& i) const; Literal + // parse_literal(const ::std::unique_ptr<Token>& tok) const; + //::std::unique_ptr<MetaItem> parse_path_meta_item(const ::std::vector< + //::std::unique_ptr<Token> >& token_stream, int& i) const; bool + // is_end_meta_item_tok(TokenId tok) const; + protected: // Use covariance to implement clone function as returning a DelimTokenTree object virtual DelimTokenTree* clone_attr_input_impl() const OVERRIDE { @@ -225,14 +299,16 @@ namespace Rust { } public: - DelimTokenTree( - DelimType delim_type, ::std::vector< ::std::unique_ptr<TokenTree> > token_trees - = ::std::vector< ::std::unique_ptr<TokenTree> >()) : + DelimTokenTree(DelimType delim_type, + ::std::vector< ::std::unique_ptr<TokenTree> > token_trees + = ::std::vector< ::std::unique_ptr<TokenTree> >(), + location_t locus = UNKNOWN_LOCATION) : delim_type(delim_type), - token_trees(::std::move(token_trees)) {} + token_trees(::std::move(token_trees)), locus(locus) {} // Copy constructor with vector clone - DelimTokenTree(DelimTokenTree const& other) : delim_type(other.delim_type) { + DelimTokenTree(DelimTokenTree const& other) : + delim_type(other.delim_type), locus(other.locus) { // crappy vector unique pointer clone - TODO is there a better way of doing this? token_trees.reserve(other.token_trees.size()); @@ -244,6 +320,7 @@ namespace Rust { // overloaded assignment operator with vector clone DelimTokenTree& operator=(DelimTokenTree const& other) { delim_type = other.delim_type; + locus = other.locus; // crappy vector unique pointer clone - TODO is there a better way of doing this? token_trees.reserve(other.token_trees.size()); @@ -264,28 +341,43 @@ namespace Rust { } ::std::string as_string() const; + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + + virtual bool check_cfg_predicate(const Session& session ATTRIBUTE_UNUSED) const OVERRIDE { + // this should never be called - should be converted first + return false; + } + + virtual AttrInput* parse_to_meta_item() const OVERRIDE; + + virtual ::std::vector< ::std::unique_ptr<Token> > to_token_stream() const OVERRIDE; }; // Forward decl - definition moved to rust-expr.h as it requires LiteralExpr to be defined class AttrInputLiteral; - // TODO: move applicable stuff into here + // TODO: move applicable stuff into here or just don't include it because nothing uses it // A segment of a path (maybe) class PathSegment { public: virtual ~PathSegment() {} virtual ::std::string as_string() const = 0; + + // TODO: add visitor here? }; // A segment of a simple path without generic or type arguments class SimplePathSegment : public PathSegment { ::std::string segment_name; + location_t locus; // only allow identifiers, "super", "self", "crate", or "$crate" public: // TODO: put checks in constructor to enforce this rule? - SimplePathSegment(::std::string segment_name) : segment_name(::std::move(segment_name)) {} + SimplePathSegment(::std::string segment_name, location_t locus = UNKNOWN_LOCATION) : + segment_name(::std::move(segment_name)), locus(locus) {} // Returns whether simple path segment is in an invalid state (currently, if empty). inline bool is_error() const { @@ -298,19 +390,26 @@ namespace Rust { } ::std::string as_string() const; + + inline location_t get_locus() const { + return locus; + } + + // TODO: visitor pattern? }; // A simple path without generic or type arguments class SimplePath { bool has_opening_scope_resolution; ::std::vector<SimplePathSegment> segments; + location_t locus; public: // Constructor SimplePath(::std::vector<SimplePathSegment> path_segments, - bool has_opening_scope_resolution = false) : + bool has_opening_scope_resolution = false, location_t locus = UNKNOWN_LOCATION) : has_opening_scope_resolution(has_opening_scope_resolution), - segments(::std::move(path_segments)) {} + segments(::std::move(path_segments)), locus(locus) {} // Creates an empty SimplePath. static SimplePath create_empty() { @@ -323,6 +422,28 @@ namespace Rust { } ::std::string as_string() const; + + location_t get_locus() const { + return locus; + } + + // does this need visitor if not polymorphic? probably not + + // path-to-string comparison operator + bool operator==(const ::std::string& rhs) { + return !has_opening_scope_resolution && segments.size() == 1 + && segments[0].as_string() == rhs; + } + + /* Creates a single-segment SimplePath from a string. This will not check to ensure that + * this is a valid identifier in path, so be careful. Also, this will have no location + * data. + * TODO have checks? */ + static SimplePath from_str(::std::string str) { + ::std::vector<AST::SimplePathSegment> single_segments + = { AST::SimplePathSegment(::std::move(str)) }; + return SimplePath(::std::move(single_segments)); + } }; // aka Attr @@ -335,6 +456,10 @@ namespace Rust { // AttrInput* attr_input; ::std::unique_ptr<AttrInput> attr_input; + location_t locus; + + // TODO: maybe a variable storing whether attr input is parsed or not + public: // Returns whether Attribute has AttrInput inline bool has_attr_input() const { @@ -342,12 +467,18 @@ namespace Rust { } // Constructor has pointer AttrInput for polymorphism reasons - Attribute(SimplePath path, AttrInput* input) : - path(::std::move(path)), attr_input(input) {} + Attribute(SimplePath path, ::std::unique_ptr<AttrInput> input, + location_t locus = UNKNOWN_LOCATION) : + path(::std::move(path)), + attr_input(::std::move(input)), locus(locus) {} // Copy constructor must deep copy attr_input as unique pointer - Attribute(Attribute const& other) : - path(other.path), attr_input(other.attr_input->clone_attr_input()) {} + Attribute(Attribute const& other) : path(other.path), locus(other.locus) { + // guard to protect from null pointer dereference + if (other.attr_input != NULL) { + attr_input = other.attr_input->clone_attr_input(); + } + } // default destructor ~Attribute() = default; @@ -355,7 +486,11 @@ namespace Rust { // overload assignment operator to use custom clone method Attribute& operator=(Attribute const& other) { path = other.path; - attr_input = other.attr_input->clone_attr_input(); + locus = other.locus; + // guard to protect from null pointer dereference + if (other.attr_input != NULL) { + attr_input = other.attr_input->clone_attr_input(); + } return *this; } @@ -437,6 +572,33 @@ namespace Rust { ::std::string as_string() const; + // TODO: does this require visitor pattern as not polymorphic? + + // Maybe change to const-reference in future + SimplePath get_path() const { + return path; + } + + // Call to parse attribute body to meta item syntax. + void parse_attr_to_meta_item(); + + // Determines whether cfg predicate is true and item with attribute should not be + // stripped. + bool check_cfg_predicate(const Session& session) { + // assume that cfg predicate actually can exist, i.e. attribute has cfg or cfg_attr + // path + + if (!has_attr_input()) { + return false; + } + + // TODO: maybe replace with storing a "has been parsed" variable? + parse_attr_to_meta_item(); + // can't be const because of this anyway + + return attr_input->check_cfg_predicate(session); + } + protected: // not virtual as currently no subclasses of Attribute, but could be in future /*virtual*/ Attribute* clone_attribute_impl() const { @@ -444,60 +606,129 @@ namespace Rust { } }; - // Syntax used for Attribute by most built-in attributes and the meta fragment spec - class MetaItem { - SimplePath path; + // Forward decl - defined in rust-macro.h + class MetaNameValueStr; + // abstract base meta item inner class + class MetaItemInner { protected: - MetaItem(SimplePath path) : path(::std::move(path)) {} - - // pure virtual as MetaItem is abstract? - virtual MetaItem* clone_meta_item_impl() const = 0; + // pure virtual as MetaItemInner + virtual MetaItemInner* clone_meta_item_inner_impl() const = 0; public: // Unique pointer custom clone function - ::std::unique_ptr<MetaItem> clone_meta_item() const { - return ::std::unique_ptr<MetaItem>(clone_meta_item_impl()); + ::std::unique_ptr<MetaItemInner> clone_meta_item_inner() const { + return ::std::unique_ptr<MetaItemInner>(clone_meta_item_inner_impl()); } - virtual ~MetaItem() {} + virtual ~MetaItemInner() {} virtual ::std::string as_string() const = 0; + + virtual void accept_vis(ASTVisitor& vis) = 0; + + // HACK: used to simplify parsing - creates a copy of that type, or returns null + virtual MetaNameValueStr* to_meta_name_value_str() const { + return NULL; + } + + // HACK: used to simplify parsing - same thing + virtual SimplePath to_path_item() const { + return SimplePath::create_empty(); + } + + virtual bool check_cfg_predicate(const Session& session) const = 0; }; - // Forward decl - defined in rust-expr.h - class MetaItemLit; + // Container used to store MetaItems as AttrInput (bridge-ish kinda thing) + class AttrInputMetaItemContainer : public AttrInput { + ::std::vector< ::std::unique_ptr<MetaItemInner> > items; - // Forward decl - defined in rust-expr.h - struct MetaItemInner; + public: + AttrInputMetaItemContainer(::std::vector< ::std::unique_ptr<MetaItemInner> > items) : + items(::std::move(items)) {} - // Forward decl - defined in rust-expr.h - class MetaItemSeq; + // copy constructor with vector clone + AttrInputMetaItemContainer(const AttrInputMetaItemContainer& other) { + // crappy vector unique pointer clone - TODO is there a better way of doing this? + items.reserve(other.items.size()); - // Forward decl - defined in rust-expr.h - struct MetaWord; + for (const auto& e : other.items) { + items.push_back(e->clone_meta_item_inner()); + } + } - // Forward decl - defined in rust-expr.h - struct MetaNameValueStr; + // no destructor definition required - // Forward decl - defined in rust-expr.h - struct MetaListPaths; + // copy assignment operator with vector clone + AttrInputMetaItemContainer& operator=(const AttrInputMetaItemContainer& other) { + AttrInput::operator=(other); + // crappy vector unique pointer clone - TODO is there a better way of doing this? + items.reserve(other.items.size()); + + for (const auto& e : other.items) { + items.push_back(e->clone_meta_item_inner()); + } + + return *this; + } + + // default move constructors + AttrInputMetaItemContainer(AttrInputMetaItemContainer&& other) = default; + AttrInputMetaItemContainer& operator=(AttrInputMetaItemContainer&& other) = default; + + ::std::string as_string() const OVERRIDE; + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + + virtual bool check_cfg_predicate(const Session& session) const OVERRIDE; + + protected: + // Use covariance to implement clone function as returning this type + virtual AttrInputMetaItemContainer* clone_attr_input_impl() const OVERRIDE { + return new AttrInputMetaItemContainer(*this); + } + }; + + // abstract base meta item class + class MetaItem : public MetaItemInner {}; // Forward decl - defined in rust-expr.h - struct MetaListIdents; + class MetaItemLitExpr; // Forward decl - defined in rust-expr.h + class MetaItemPathLit; + + // Forward decl - defined in rust-macro.h + class MetaItemPath; + + // Forward decl - defined in rust-macro.h + class MetaItemSeq; + + // Forward decl - defined in rust-macro.h + class MetaWord; + + // Forward decl - defined in rust-macro.h + class MetaListPaths; + + // Forward decl - defined in rust-macro.h struct MetaListNameValueStr; /* Base statement abstract class. Note that most "statements" are not allowed in top-level * module scope - only a subclass of statements called "items" are. */ - class Stmt : public Node { + class Stmt { public: // Unique pointer custom clone function ::std::unique_ptr<Stmt> clone_stmt() const { return ::std::unique_ptr<Stmt>(clone_stmt_impl()); } + virtual ~Stmt() {} + + virtual ::std::string as_string() const = 0; + + virtual void accept_vis(ASTVisitor& vis) = 0; + protected: // Clone function implementation as pure virtual method virtual Stmt* clone_stmt_impl() const = 0; @@ -507,6 +738,8 @@ namespace Rust { class Item : public Stmt { ::std::vector<Attribute> outer_attrs; + // TODO: should outer attrs be defined here or in each derived class? + public: // Unique pointer custom clone function ::std::unique_ptr<Item> clone_item() const { @@ -515,6 +748,10 @@ namespace Rust { ::std::string as_string() const; + // Adds crate names to the vector passed by reference, if it can (polymorphism). + virtual void add_crate_name(::std::vector< ::std::string>& names ATTRIBUTE_UNUSED) const { + } + protected: // Constructor Item(::std::vector<Attribute> outer_attribs = ::std::vector<Attribute>()) : @@ -530,8 +767,12 @@ namespace Rust { } }; + // forward decl of ExprWithoutBlock + class ExprWithoutBlock; + // Base expression AST node - abstract - class Expr : public Node { + class Expr { + // TODO: move outer attribute data to derived classes? ::std::vector<Attribute> outer_attrs; public: @@ -548,7 +789,26 @@ namespace Rust { * - get_type() - returns type of expression. set_type() may also be useful for some? * - evaluate() - evaluates expression if constant? can_evaluate()? */ - ::std::string as_string() const; + // HACK: downcasting without dynamic_cast (if possible) via polymorphism - overrided in + // subclasses of ExprWithoutBlock + virtual ExprWithoutBlock* as_expr_without_block() const { + // DEBUG + fprintf(stderr, "clone expr without block returns null and has not been overriden\n"); + + return NULL; + } + + // TODO: make pure virtual if move out outer attributes to derived classes + virtual ::std::string as_string() const; + + virtual ~Expr() {} + + // HACK: slow way of getting location from base expression through virtual methods. + virtual location_t get_locus_slow() const { + return UNKNOWN_LOCATION; + } + + virtual void accept_vis(ASTVisitor& vis) = 0; protected: // Constructor @@ -557,26 +817,11 @@ namespace Rust { // Clone function implementation as pure virtual method virtual Expr* clone_expr_impl() const = 0; - }; - // HACK: IdentifierExpr, delete when figure out identifier vs expr problem in Pratt parser - class IdentifierExpr : public Expr { - Identifier ident; - - public: - IdentifierExpr( - Identifier ident, ::std::vector<Attribute> outer_attrs = ::std::vector<Attribute>()) : - Expr(::std::move(outer_attrs)), - ident(::std::move(ident)) {} - - ::std::string as_string() const { - return "not implemented as a HACK"; - } - - protected: - // Clone method implementation - virtual IdentifierExpr* clone_expr_impl() const OVERRIDE { - return new IdentifierExpr(*this); + // TODO: think of less hacky way to implement this kind of thing + // Sets outer attributes. + void set_outer_attrs(::std::vector<Attribute> outer_attrs_to_set) { + outer_attrs = ::std::move(outer_attrs_to_set); } }; @@ -601,10 +846,52 @@ namespace Rust { ::std::unique_ptr<ExprWithoutBlock> clone_expr_without_block() const { return ::std::unique_ptr<ExprWithoutBlock>(clone_expr_without_block_impl()); } + + // downcasting hack from expr to use pratt parsing with parse_expr_without_block + virtual ExprWithoutBlock* as_expr_without_block() const OVERRIDE { + // DEBUG + fprintf(stderr, "about to call the impl for clone expr without block\n"); + + return clone_expr_without_block_impl(); + } + }; + + // HACK: IdentifierExpr, delete when figure out identifier vs expr problem in Pratt parser + // Alternatively, identifiers could just be represented as single-segment paths + class IdentifierExpr : public ExprWithoutBlock { + Identifier ident; + + location_t locus; + + public: + IdentifierExpr(Identifier ident, location_t locus = UNKNOWN_LOCATION, + ::std::vector<Attribute> outer_attrs = ::std::vector<Attribute>()) : + ExprWithoutBlock(::std::move(outer_attrs)), + ident(::std::move(ident)), locus(locus) {} + + ::std::string as_string() const OVERRIDE { + return ident; + } + + location_t get_locus() const { + return locus; + } + + location_t get_locus_slow() const OVERRIDE { + return get_locus(); + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + + protected: + // Clone method implementation + virtual IdentifierExpr* clone_expr_without_block_impl() const OVERRIDE { + return new IdentifierExpr(*this); + } }; // Pattern base AST node - class Pattern : public Node { + class Pattern { public: // Unique pointer custom clone function ::std::unique_ptr<Pattern> clone_pattern() const { @@ -613,6 +900,12 @@ namespace Rust { // possible virtual methods: is_refutable() + virtual ~Pattern() {} + + virtual ::std::string as_string() const = 0; + + virtual void accept_vis(ASTVisitor& vis) = 0; + protected: // Clone pattern implementation as pure virtual method virtual Pattern* clone_pattern_impl() const = 0; @@ -635,11 +928,13 @@ namespace Rust { virtual ::std::string as_string() const = 0; // HACK: convert to trait bound. Virtual method overriden by classes that enable this. - virtual TraitBound* to_trait_bound(bool in_parens) const { + virtual TraitBound* to_trait_bound(bool in_parens ATTRIBUTE_UNUSED) const { return NULL; } // as pointer, shouldn't require definition beforehand, only forward declaration. + virtual void accept_vis(ASTVisitor& vis) = 0; + protected: // Clone function implementation as pure virtual method virtual Type* clone_type_impl() const = 0; @@ -676,6 +971,8 @@ namespace Rust { virtual ::std::string as_string() const = 0; + virtual void accept_vis(ASTVisitor& vis) = 0; + protected: // Clone function implementation as pure virtual method virtual TypeParamBound* clone_type_param_bound_impl() const = 0; @@ -698,10 +995,14 @@ namespace Rust { ::std::string lifetime_name; // only applies for NAMED lifetime_type + location_t locus; + public: // Constructor - Lifetime(LifetimeType type, ::std::string name = ::std::string()) : - lifetime_type(type), lifetime_name(::std::move(name)) {} + Lifetime(LifetimeType type, ::std::string name = ::std::string(), + location_t locus = UNKNOWN_LOCATION) : + lifetime_type(type), + lifetime_name(::std::move(name)), locus(locus) {} // Creates an "error" lifetime. static Lifetime error() { @@ -715,6 +1016,8 @@ namespace Rust { ::std::string as_string() const; + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual Lifetime* clone_type_param_bound_impl() const OVERRIDE { @@ -734,6 +1037,8 @@ namespace Rust { virtual ::std::string as_string() const = 0; + virtual void accept_vis(ASTVisitor& vis) = 0; + protected: // Clone function implementation as pure virtual method virtual GenericParam* clone_generic_param_impl() const = 0; @@ -751,6 +1056,8 @@ namespace Rust { //::std::unique_ptr<Attribute> outer_attr; Attribute outer_attr; + location_t locus; + public: // Returns whether the lifetime param has any lifetime bounds. inline bool has_lifetime_bounds() const { @@ -773,16 +1080,19 @@ namespace Rust { } // Constructor - LifetimeParam(Lifetime lifetime, + LifetimeParam(Lifetime lifetime, location_t locus = UNKNOWN_LOCATION, ::std::vector<Lifetime> lifetime_bounds = ::std::vector<Lifetime>(), Attribute outer_attr = Attribute::create_empty()) : lifetime(::std::move(lifetime)), - lifetime_bounds(::std::move(lifetime_bounds)), outer_attr(::std::move(outer_attr)) {} + lifetime_bounds(::std::move(lifetime_bounds)), outer_attr(::std::move(outer_attr)), + locus(locus) {} + + // TODO: remove copy and assignment operator definitions - not required // Copy constructor with clone LifetimeParam(LifetimeParam const& other) : lifetime(other.lifetime), lifetime_bounds(other.lifetime_bounds), - outer_attr(other.outer_attr) {} + outer_attr(other.outer_attr), locus(other.locus) {} // Destructor - define here if required @@ -791,6 +1101,7 @@ namespace Rust { lifetime = other.lifetime; lifetime_bounds = other.lifetime_bounds; outer_attr = other.outer_attr; + locus = other.locus; return *this; } @@ -801,6 +1112,8 @@ namespace Rust { ::std::string as_string() const; + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual LifetimeParam* clone_generic_param_impl() const OVERRIDE { @@ -820,12 +1133,14 @@ namespace Rust { class TraitItem { // bool has_outer_attrs; // TODO: remove and rely on virtual functions and VisItem-derived attributes? - ::std::vector<Attribute> outer_attrs; + //::std::vector<Attribute> outer_attrs; + + // NOTE: all children should have outer attributes protected: // Constructor - TraitItem(::std::vector<Attribute> outer_attrs = ::std::vector<Attribute>()) : - outer_attrs(::std::move(outer_attrs)) {} + /*TraitItem(::std::vector<Attribute> outer_attrs = ::std::vector<Attribute>()) : + outer_attrs(::std::move(outer_attrs)) {}*/ // Clone function implementation as pure virtual method virtual TraitItem* clone_trait_item_impl() const = 0; @@ -834,20 +1149,63 @@ namespace Rust { virtual ~TraitItem() {} // Returns whether TraitItem has outer attributes. - inline bool has_outer_attrs() const { + /*inline bool has_outer_attrs() const { return !outer_attrs.empty(); - } + }*/ // Unique pointer custom clone function ::std::unique_ptr<TraitItem> clone_trait_item() const { return ::std::unique_ptr<TraitItem>(clone_trait_item_impl()); } + + virtual ::std::string as_string() const = 0; + + virtual void accept_vis(ASTVisitor& vis) = 0; + }; + + // Abstract base class for items used within an inherent impl block (the impl name {} one) + class InherentImplItem { + protected: + // Clone function implementation as pure virtual method + virtual InherentImplItem* clone_inherent_impl_item_impl() const = 0; + + public: + virtual ~InherentImplItem() {} + + // Unique pointer custom clone function + ::std::unique_ptr<InherentImplItem> clone_inherent_impl_item() const { + return ::std::unique_ptr<InherentImplItem>(clone_inherent_impl_item_impl()); + } + + virtual ::std::string as_string() const = 0; + + virtual void accept_vis(ASTVisitor& vis) = 0; + }; + + // Abstract base class for items used in a trait impl + class TraitImplItem { + protected: + virtual TraitImplItem* clone_trait_impl_item_impl() const = 0; + + public: + virtual ~TraitImplItem(){}; + + // Unique pointer custom clone function + ::std::unique_ptr<TraitImplItem> clone_trait_impl_item() const { + return ::std::unique_ptr<TraitImplItem>(clone_trait_impl_item_impl()); + } + + virtual ::std::string as_string() const = 0; + + virtual void accept_vis(ASTVisitor& vis) = 0; }; // A macro invocation item (or statement) AST node (i.e. semi-coloned macro invocation) class MacroInvocationSemi : public MacroItem , public TraitItem + , public InherentImplItem + , public TraitImplItem /*, public Statement*/ { // already inherits from statement indirectly via item as item is a subclass of statement SimplePath path; @@ -856,15 +1214,17 @@ namespace Rust { //::std::vector<TokenTree> token_trees; ::std::vector< ::std::unique_ptr<TokenTree> > token_trees; + location_t locus; + public: ::std::string as_string() const; MacroInvocationSemi(SimplePath macro_path, DelimType delim_type, ::std::vector< ::std::unique_ptr<TokenTree> > token_trees, - ::std::vector<Attribute> outer_attribs) : - MacroItem(outer_attribs), - TraitItem(outer_attribs), path(::std::move(macro_path)), delim_type(delim_type), - token_trees(::std::move(token_trees)) {} + ::std::vector<Attribute> outer_attribs, location_t locus) : + MacroItem(::std::move(outer_attribs)), + path(::std::move(macro_path)), delim_type(delim_type), + token_trees(::std::move(token_trees)), locus(locus) {} /* TODO: possible issue with Item and TraitItem hierarchies both having outer attributes * - storage inefficiency at least. * Best current idea is to make Item preferred and have TraitItem get virtual functions @@ -874,7 +1234,8 @@ namespace Rust { // Copy constructor with vector clone MacroInvocationSemi(MacroInvocationSemi const& other) : - MacroItem(other), TraitItem(other), path(other.path), delim_type(other.delim_type) { + MacroItem(other), TraitItem(other), InherentImplItem(other), TraitImplItem(other), + path(other.path), delim_type(other.delim_type), locus(other.locus) { // crappy vector unique pointer clone - TODO is there a better way of doing this? token_trees.reserve(other.token_trees.size()); @@ -887,8 +1248,11 @@ namespace Rust { MacroInvocationSemi& operator=(MacroInvocationSemi const& other) { MacroItem::operator=(other); TraitItem::operator=(other); + InherentImplItem::operator=(other); + TraitImplItem::operator=(other); path = other.path; delim_type = other.delim_type; + locus = other.locus; // crappy vector unique pointer clone - TODO is there a better way of doing this? token_trees.reserve(other.token_trees.size()); @@ -904,12 +1268,24 @@ namespace Rust { MacroInvocationSemi(MacroInvocationSemi&& other) = default; MacroInvocationSemi& operator=(MacroInvocationSemi&& other) = default; + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual MacroInvocationSemi* clone_item_impl() const OVERRIDE { return new MacroInvocationSemi(*this); } + // Use covariance to implement clone function as returning this object rather than base + virtual MacroInvocationSemi* clone_inherent_impl_item_impl() const OVERRIDE { + return new MacroInvocationSemi(*this); + } + + // Use covariance to implement clone function as returning this object rather than base + virtual MacroInvocationSemi* clone_trait_impl_item_impl() const OVERRIDE { + return new MacroInvocationSemi(*this); + } + // FIXME: remove if item impl virtual override works properly // Use covariance to implement clone function as returning this object rather than base /*virtual MacroInvocationSemi* clone_statement_impl() const OVERRIDE { @@ -979,6 +1355,21 @@ namespace Rust { // Get crate representation as string (e.g. for debugging). ::std::string as_string() const; }; + + // Base path expression AST node - abstract + class PathExpr : public ExprWithoutBlock { + protected: + PathExpr(::std::vector<Attribute> outer_attribs) : + ExprWithoutBlock(::std::move(outer_attribs)) {} + + public: + // TODO: think of a better and less hacky way to allow this + + // Replaces the outer attributes of this path expression with the given outer attributes. + void replace_outer_attrs(::std::vector<Attribute> outer_attrs) { + set_outer_attrs(::std::move(outer_attrs)); + } + }; } } diff --git a/gcc/rust/test3/ast/rust-cond-compilation.h b/gcc/rust/test3/ast/rust-cond-compilation.h index c2491f1..4fa6a0b 100644 --- a/gcc/rust/test3/ast/rust-cond-compilation.h +++ b/gcc/rust/test3/ast/rust-cond-compilation.h @@ -17,6 +17,9 @@ namespace Rust { clone_configuration_predicate_impl()); } + // not sure if I'll use this but here anyway + virtual void accept_vis(ASTVisitor& vis) = 0; + protected: // Clone function impl to be overriden in base classes virtual ConfigurationPredicate* clone_configuration_predicate_impl() const = 0; @@ -42,6 +45,8 @@ namespace Rust { // Name-only constructor ConfigurationOption(Identifier option_name) : option_name(option_name) {} + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual ConfigurationOption* clone_configuration_predicate_impl() const OVERRIDE { @@ -63,6 +68,8 @@ namespace Rust { ::std::vector< ::std::unique_ptr<ConfigurationPredicate> > predicate_list) : predicate_list(predicate_list) {} + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual ConfigurationAll* clone_configuration_predicate_impl() const OVERRIDE { @@ -79,6 +86,8 @@ namespace Rust { ::std::vector< ::std::unique_ptr<ConfigurationPredicate> > predicate_list) : predicate_list(predicate_list) {} + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual ConfigurationAny* clone_configuration_predicate_impl() const OVERRIDE { @@ -107,9 +116,11 @@ namespace Rust { return *this; } - // no move constructors as not supported in c++03 - /*ConfigurationNot(ConfigurationNot&& other) = default; - ConfigurationNot& operator=(ConfigurationNot&& other) = default;*/ + // move constructors + ConfigurationNot(ConfigurationNot&& other) = default; + ConfigurationNot& operator=(ConfigurationNot&& other) = default; + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; protected: // Use covariance to implement clone function as returning this object rather than base @@ -139,10 +150,13 @@ namespace Rust { return *this; } - // no move constructors as not supported in c++03 - /*CfgAttrAttribute(CfgAttrAttribute&& other) = default; - CfgAttrAttribute& operator=(CfgAttrAttribute&& other) = default;*/ + // move constructors + CfgAttribute(CfgAttribute&& other) = default; + CfgAttribute& operator=(CfgAttribute&& other) = default; }; + /* TODO: ok, best thing to do would be eliminating this class, making Attribute has a "is_cfg()" + * method, and having attribute path as "cfg" and AttrInput as ConfigurationPredicate (so make + * ConfigurationPredicate a subclass of AttrInput?). Would need special handling in parser, however. */ // TODO: inline struct CfgAttrs { @@ -175,9 +189,9 @@ namespace Rust { return *this; } - // no move constructors as not supported in c++03 - /*CfgAttrAttribute(CfgAttrAttribute&& other) = default; - CfgAttrAttribute& operator=(CfgAttrAttribute&& other) = default;*/ + // move constructors + CfgAttrAttribute(CfgAttrAttribute&& other) = default; + CfgAttrAttribute& operator=(CfgAttrAttribute&& other) = default; }; } } diff --git a/gcc/rust/test3/ast/rust-expr.h b/gcc/rust/test3/ast/rust-expr.h index 2694c0a..1842da9 100644 --- a/gcc/rust/test3/ast/rust-expr.h +++ b/gcc/rust/test3/ast/rust-expr.h @@ -67,6 +67,8 @@ namespace Rust { // moved to Literal Literal literal; + location_t locus; + public: ::std::string as_string() const { return literal.as_string(); @@ -76,21 +78,31 @@ namespace Rust { return literal.get_lit_type(); } - LiteralExpr(::std::string value_as_string, Literal::LitType type, + LiteralExpr(::std::string value_as_string, Literal::LitType type, location_t locus, ::std::vector<Attribute> outer_attrs = ::std::vector<Attribute>()) : ExprWithoutBlock(::std::move(outer_attrs)), - literal(::std::move(value_as_string), type) {} + literal(::std::move(value_as_string), type), locus(locus) {} - LiteralExpr( - Literal literal, ::std::vector<Attribute> outer_attrs = ::std::vector<Attribute>()) : + LiteralExpr(Literal literal, location_t locus, + ::std::vector<Attribute> outer_attrs = ::std::vector<Attribute>()) : ExprWithoutBlock(::std::move(outer_attrs)), - literal(::std::move(literal)) {} + literal(::std::move(literal)), locus(locus) {} // Unique pointer custom clone function ::std::unique_ptr<LiteralExpr> clone_literal_expr() const { return ::std::unique_ptr<LiteralExpr>(clone_literal_expr_impl()); } + location_t get_locus() const { + return locus; + } + + location_t get_locus_slow() const OVERRIDE { + return get_locus(); + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual LiteralExpr* clone_expr_impl() const OVERRIDE { @@ -116,6 +128,8 @@ namespace Rust { LiteralExpr literal_expr; // as not using polymorphic behaviour, doesn't require pointer // TODO: will require pointer if LiteralExpr is changed to have subclassing + // TODO: should this store location data? + public: AttrInputLiteral(LiteralExpr lit_expr) : literal_expr(::std::move(lit_expr)) {} /*~AttrInputLiteral() { @@ -126,6 +140,18 @@ namespace Rust { return " = " + literal_expr.as_string(); } + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + + // this can never be a cfg predicate - cfg and cfg_attr require a token-tree cfg + virtual bool check_cfg_predicate(const Session& session ATTRIBUTE_UNUSED) const OVERRIDE { + // TODO: ensure this is true + // DEBUG + fprintf( + stderr, "check_cfg_predicate call went to AttrInputLiteral - should not happen?\n"); + + return false; + } + protected: // Use covariance to implement clone function as returning an AttrInputLiteral object virtual AttrInputLiteral* clone_attr_input_impl() const OVERRIDE { @@ -133,174 +159,56 @@ namespace Rust { } }; - // A literal meta item - class MetaItemLit : public MetaItem { - // LiteralExpr* expr; - //::std::unique_ptr<LiteralExpr> expr; - LiteralExpr expr; // as LiteralExpr not subclassed (currently, at least), ptr not needed + // literal expr only meta item inner - TODO possibly replace with inheritance of LiteralExpr + // itself? + class MetaItemLitExpr : public MetaItemInner { + LiteralExpr lit_expr; public: - /*~MetaItemLit() { - delete expr; - }*/ - - MetaItemLit(LiteralExpr expr, SimplePath path) : - MetaItem(::std::move(path)), expr(::std::move(expr)) {} - - ::std::string as_string() const; + MetaItemLitExpr(LiteralExpr lit_expr) : lit_expr(::std::move(lit_expr)) {} - protected: - // Use covariance to implement clone function as returning derived object - virtual MetaItemLit* clone_meta_item_impl() const OVERRIDE { - return new MetaItemLit(*this); + ::std::string as_string() const OVERRIDE { + return lit_expr.as_string(); } - }; - // An inner meta item - struct MetaItemInner { - // Allows EITHER MetaItem or LiteralExpression (without suffix) - // bool lit_active; - /*MetaItem* item; - LiteralExpr* expr;*/ - ::std::unique_ptr<MetaItem> item; - //::std::unique_ptr<LiteralExpr> expr; - ::std::unique_ptr<LiteralExpr> expr; + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; - // as no more conditional delete on expr member variable, must initialise it as NULL - public: - /*~MetaItemInner() { - if (lit_active) { - delete expr; - } - delete item; - }*/ - - // Returns whether the MetaItemInner is in an error state. - inline bool is_error_state() const { - return (item == NULL && expr == NULL) || (item != NULL && expr != NULL); - } - - // Returns whether the item is active - inline bool is_item_active() const { - return item != NULL && expr == NULL; - } - - // Returns whether the literal expr is active - inline bool is_expr_active() const { - return !is_item_active(); - } - - // Constructor with MetaItem - MetaItemInner(MetaItem* item) : item(item) /*, expr(NULL)*/ {} - - // Constructor with LitExpr - MetaItemInner(LiteralExpr* expr) : /*item(NULL), */ expr(expr) {} - - // Copy constructor with clone - MetaItemInner(MetaItemInner const& other) : - item(other.item->clone_meta_item()), expr(other.expr->clone_literal_expr()) {} - - // Destructor - define here if required - - // Overload assignment operator to use clone - MetaItemInner& operator=(MetaItemInner const& other) { - item = other.item->clone_meta_item(); - expr = other.expr->clone_literal_expr(); - - return *this; - } - - // move constructors - MetaItemInner(MetaItemInner&& other) = default; - MetaItemInner& operator=(MetaItemInner&& other) = default; - }; - - // A sequence meta item - class MetaItemSeq : public MetaItem { - // bool has_sequence; - ::std::vector<MetaItemInner> sequence; - - public: - // Returns whether the sequence meta item actually has a sequence - inline bool has_sequence() const { - return !sequence.empty(); - } - - MetaItemSeq(SimplePath path, ::std::vector<MetaItemInner> sequence) : - MetaItem(::std::move(path)), sequence(::std::move(sequence)) {} - - ::std::string as_string() const; + virtual bool check_cfg_predicate(const Session& session) const OVERRIDE; protected: - // Use covariance to implement clone function as returning derived object - virtual MetaItemSeq* clone_meta_item_impl() const OVERRIDE { - return new MetaItemSeq(*this); + // Use covariance to implement clone function as returning this type + virtual MetaItemLitExpr* clone_meta_item_inner_impl() const OVERRIDE { + return new MetaItemLitExpr(*this); } }; - // Something to do with subsets of MetaItem syntax or something - struct MetaWord { - private: - Identifier word; - - public: - MetaWord(Identifier word) : word(::std::move(word)) {} - }; - - // A name-value string - struct MetaNameValueStr { - private: - Identifier name; - ::std::string value; + // more generic meta item "path = lit" form + class MetaItemPathLit : public MetaItem { + SimplePath path; + LiteralExpr lit; public: - MetaNameValueStr(Identifier name, ::std::string value) : - name(::std::move(name)), value(::std::move(value)) {} - }; - - // A list of paths - struct MetaListPaths { - private: - Identifier type_thing; - ::std::vector<SimplePath> paths; + MetaItemPathLit(SimplePath path, LiteralExpr lit_expr) : + path(::std::move(path)), lit(::std::move(lit_expr)) {} - public: - MetaListPaths(Identifier type_thing, ::std::vector<SimplePath> paths) : - type_thing(::std::move(type_thing)), paths(::std::move(paths)) {} - }; - - // A list of identifiers - struct MetaListIdents { - private: - Identifier directive_thing; - ::std::vector<Identifier> idents_to_use; - - public: - MetaListIdents(Identifier directive_thing, ::std::vector<Identifier> idents_to_use) : - directive_thing(::std::move(directive_thing)), - idents_to_use(::std::move(idents_to_use)) {} - }; + ::std::string as_string() const OVERRIDE { + return path.as_string() + " = " + lit.as_string(); + } - // A list of MetaNameValueStr - struct MetaListNameValueStr { - private: - Identifier macro_name_thing; - ::std::vector<MetaNameValueStr> list; + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; - public: - MetaListNameValueStr(Identifier macro_name_thing, ::std::vector<MetaNameValueStr> list) : - macro_name_thing(::std::move(macro_name_thing)), list(::std::move(list)) {} - }; + virtual bool check_cfg_predicate(const Session& session) const OVERRIDE; + // TODO: return true if "ident" is defined and value of it is "lit", return false otherwise - // Base path expression AST node - abstract - class PathExpr : public ExprWithoutBlock { protected: - PathExpr(::std::vector<Attribute> outer_attribs) : - ExprWithoutBlock(::std::move(outer_attribs)) {} + // Use covariance to implement clone function as returning this type + virtual MetaItemPathLit* clone_meta_item_inner_impl() const OVERRIDE { + return new MetaItemPathLit(*this); + } }; // AST node for a non-qualified path expression - FIXME: should this be inheritance instead? - class PathExprNonQual : public PathExpr { + /*class PathExprNonQual : public PathExpr { PathInExpression path; public: @@ -321,10 +229,11 @@ namespace Rust { virtual PathExprNonQual* clone_expr_without_block_impl() const OVERRIDE { return new PathExprNonQual(*this); } - }; + };*/ + // converted to inheritance // AST node for a qualified path expression - FIXME: should this be inheritance instead? - class PathExprQual : public PathExpr { + /*class PathExprQual : public PathExpr { QualifiedPathInExpression path; public: @@ -345,29 +254,48 @@ namespace Rust { virtual PathExprQual* clone_expr_without_block_impl() const OVERRIDE { return new PathExprQual(*this); } - }; + };*/ + // replaced with inheritance // Represents an expression using unary or binary operators as AST node. Can be overloaded. class OperatorExpr : public ExprWithoutBlock { // TODO: create binary and unary operator subclasses? + location_t locus; + protected: // Variable must be protected to allow derived classes to use it as a first class citizen // Expr* main_or_left_expr; ::std::unique_ptr<Expr> main_or_left_expr; // Constructor (only for initialisation of expr purposes) - OperatorExpr(Expr* main_or_left_expr, ::std::vector<Attribute> outer_attribs) : - ExprWithoutBlock(::std::move(outer_attribs)), main_or_left_expr(main_or_left_expr) {} + OperatorExpr(::std::unique_ptr<Expr> main_or_left_expr, + ::std::vector<Attribute> outer_attribs, location_t locus) : + ExprWithoutBlock(::std::move(outer_attribs)), + locus(locus), main_or_left_expr(::std::move(main_or_left_expr)) {} // Copy constructor (only for initialisation of expr purposes) OperatorExpr(OperatorExpr const& other) : - ExprWithoutBlock(other), main_or_left_expr(other.main_or_left_expr->clone_expr()) {} + ExprWithoutBlock(other), + locus(other.locus) /*, main_or_left_expr(other.main_or_left_expr->clone_expr())*/ { + // DEBUG: moved main_or_left_expr into body - move back later + + if (other.main_or_left_expr == NULL) { + fprintf(stderr, "other operator expr's main_or_left_expr is null!\n"); + } + + fprintf(stderr, + "called operator expr copy constructor - about to clone main_or_left_expr\n"); + main_or_left_expr = other.main_or_left_expr->clone_expr(); + fprintf(stderr, "successfully cloned main_or_left_expr\n"); + // this occurred successfully, so something else must be the issue + } // Overload assignment operator to deep copy expr OperatorExpr& operator=(OperatorExpr const& other) { ExprWithoutBlock::operator=(other); main_or_left_expr = other.main_or_left_expr->clone_expr(); + locus = other.locus; // outer_attrs = other.outer_attrs; return *this; @@ -381,6 +309,14 @@ namespace Rust { /*virtual ~OperatorExpr() { delete main_or_left_expr; }*/ + + location_t get_locus() const { + return locus; + } + + location_t get_locus_slow() const OVERRIDE { + return get_locus(); + } }; // Unary prefix & or &mut (or && and &&mut) borrow operator. Cannot be overloaded. @@ -391,10 +327,9 @@ namespace Rust { public: ::std::string as_string() const; - // Constructor calls OperatorExpr's protected constructor - BorrowExpr(Expr* borrow_lvalue, bool is_mut_borrow, bool is_double_borrow, - ::std::vector<Attribute> outer_attribs) : - OperatorExpr(borrow_lvalue, ::std::move(outer_attribs)), + BorrowExpr(::std::unique_ptr<Expr> borrow_lvalue, bool is_mut_borrow, + bool is_double_borrow, ::std::vector<Attribute> outer_attribs, location_t locus) : + OperatorExpr(::std::move(borrow_lvalue), ::std::move(outer_attribs), locus), is_mut(is_mut_borrow), double_borrow(is_double_borrow) {} // Copy constructor - define here if required @@ -404,6 +339,9 @@ namespace Rust { // Overload assignment operator here if required // Move semantics here if required + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual BorrowExpr* clone_expr_impl() const OVERRIDE { @@ -412,6 +350,9 @@ namespace Rust { // Use covariance to implement clone function as returning this object rather than base virtual BorrowExpr* clone_expr_without_block_impl() const OVERRIDE { + // DEBUG + fprintf(stderr, "called clone_expr_without_block_impl() on borrowexpr\n"); + return new BorrowExpr(*this); } }; @@ -422,8 +363,9 @@ namespace Rust { ::std::string as_string() const; // Constructor calls OperatorExpr's protected constructor - DereferenceExpr(Expr* deref_lvalue, ::std::vector<Attribute> outer_attribs) : - OperatorExpr(deref_lvalue, ::std::move(outer_attribs)) {} + DereferenceExpr(::std::unique_ptr<Expr> deref_lvalue, + ::std::vector<Attribute> outer_attribs, location_t locus) : + OperatorExpr(::std::move(deref_lvalue), ::std::move(outer_attribs), locus) {} // Copy constructor - define here if required @@ -433,6 +375,8 @@ namespace Rust { // Move semantics here if required + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual DereferenceExpr* clone_expr_impl() const OVERRIDE { @@ -441,19 +385,22 @@ namespace Rust { // Use covariance to implement clone function as returning this object rather than base virtual DereferenceExpr* clone_expr_without_block_impl() const OVERRIDE { + // DEBUG + fprintf(stderr, "called clone_expr_without_block_impl() on dereferenceexpr\n"); + return new DereferenceExpr(*this); } }; // Unary postfix ? error propogation operator. Cannot be overloaded. - class ErrorPropogationExpr : public OperatorExpr { + class ErrorPropagationExpr : public OperatorExpr { public: ::std::string as_string() const; // Constructor calls OperatorExpr's protected constructor - ErrorPropogationExpr( - Expr* potential_error_value, ::std::vector<Attribute> outer_attribs) : - OperatorExpr(potential_error_value, ::std::move(outer_attribs)) {} + ErrorPropagationExpr(::std::unique_ptr<Expr> potential_error_value, + ::std::vector<Attribute> outer_attribs, location_t locus) : + OperatorExpr(::std::move(potential_error_value), ::std::move(outer_attribs), locus) {} // Copy constructor - define here if required @@ -463,15 +410,20 @@ namespace Rust { // Move semantics here if required + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base - virtual ErrorPropogationExpr* clone_expr_impl() const OVERRIDE { - return new ErrorPropogationExpr(*this); + virtual ErrorPropagationExpr* clone_expr_impl() const OVERRIDE { + return new ErrorPropagationExpr(*this); } // Use covariance to implement clone function as returning this object rather than base - virtual ErrorPropogationExpr* clone_expr_without_block_impl() const OVERRIDE { - return new ErrorPropogationExpr(*this); + virtual ErrorPropagationExpr* clone_expr_without_block_impl() const OVERRIDE { + // DEBUG + fprintf(stderr, "called clone_expr_without_block_impl() on errorpropagationexpr\n"); + + return new ErrorPropagationExpr(*this); } }; @@ -494,9 +446,9 @@ namespace Rust { } // Constructor calls OperatorExpr's protected constructor - NegationExpr(Expr* negated_value, NegationType negation_kind, - ::std::vector<Attribute> outer_attribs) : - OperatorExpr(negated_value, ::std::move(outer_attribs)), + NegationExpr(::std::unique_ptr<Expr> negated_value, NegationType negation_kind, + ::std::vector<Attribute> outer_attribs, location_t locus) : + OperatorExpr(::std::move(negated_value), ::std::move(outer_attribs), locus), negation_type(negation_kind) {} // Copy constructor - define here if required @@ -507,6 +459,8 @@ namespace Rust { // Move semantics here if required + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual NegationExpr* clone_expr_impl() const OVERRIDE { @@ -515,6 +469,9 @@ namespace Rust { // Use covariance to implement clone function as returning this object rather than base virtual NegationExpr* clone_expr_without_block_impl() const OVERRIDE { + // DEBUG + fprintf(stderr, "called clone_expr_without_block_impl() on negationexpr\n"); + return new NegationExpr(*this); } }; @@ -554,9 +511,10 @@ namespace Rust { } // Constructor calls OperatorExpr's protected constructor - ArithmeticOrLogicalExpr(Expr* left_value, Expr* right_value, ExprType expr_kind) : - OperatorExpr(left_value, ::std::vector<Attribute>()), expr_type(expr_kind), - right_expr(right_value) {} + ArithmeticOrLogicalExpr(::std::unique_ptr<Expr> left_value, + ::std::unique_ptr<Expr> right_value, ExprType expr_kind, location_t locus) : + OperatorExpr(::std::move(left_value), ::std::vector<Attribute>(), locus), + expr_type(expr_kind), right_expr(::std::move(right_value)) {} // outer attributes not allowed // Copy constructor - probably required due to unique pointer @@ -580,6 +538,8 @@ namespace Rust { ArithmeticOrLogicalExpr(ArithmeticOrLogicalExpr&& other) = default; ArithmeticOrLogicalExpr& operator=(ArithmeticOrLogicalExpr&& other) = default; + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual ArithmeticOrLogicalExpr* clone_expr_impl() const OVERRIDE { @@ -588,6 +548,10 @@ namespace Rust { // Use covariance to implement clone function as returning this object rather than base virtual ArithmeticOrLogicalExpr* clone_expr_without_block_impl() const OVERRIDE { + // DEBUG + fprintf( + stderr, "called clone_expr_without_block_impl() on arithmeticorlogicalexpr\n"); + return new ArithmeticOrLogicalExpr(*this); } }; @@ -623,9 +587,10 @@ namespace Rust { } // Constructor requires pointers for polymorphism - ComparisonExpr(Expr* left_value, Expr* right_value, ExprType comparison_kind) : - OperatorExpr(left_value, ::std::vector<Attribute>()), expr_type(comparison_kind), - right_expr(right_value) {} + ComparisonExpr(::std::unique_ptr<Expr> left_value, ::std::unique_ptr<Expr> right_value, + ExprType comparison_kind, location_t locus) : + OperatorExpr(::std::move(left_value), ::std::vector<Attribute>(), locus), + expr_type(comparison_kind), right_expr(::std::move(right_value)) {} // outer attributes not allowed // Copy constructor also calls OperatorExpr's protected constructor @@ -650,6 +615,8 @@ namespace Rust { ComparisonExpr(ComparisonExpr&& other) = default; ComparisonExpr& operator=(ComparisonExpr&& other) = default; + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + // TODO: implement via a function call to std::cmp::PartialEq::eq(&op1, &op2) maybe? protected: // Use covariance to implement clone function as returning this object rather than base @@ -659,6 +626,9 @@ namespace Rust { // Use covariance to implement clone function as returning this object rather than base virtual ComparisonExpr* clone_expr_without_block_impl() const OVERRIDE { + // DEBUG + fprintf(stderr, "called clone_expr_without_block_impl() on comparisonexpr\n"); + return new ComparisonExpr(*this); } }; @@ -680,9 +650,10 @@ namespace Rust { }*/ // Constructor calls OperatorExpr's protected constructor - LazyBooleanExpr(Expr* left_bool_expr, Expr* right_bool_expr, ExprType expr_kind) : - OperatorExpr(left_bool_expr, ::std::vector<Attribute>()), expr_type(expr_kind), - right_expr(right_bool_expr) {} + LazyBooleanExpr(::std::unique_ptr<Expr> left_bool_expr, + ::std::unique_ptr<Expr> right_bool_expr, ExprType expr_kind, location_t locus) : + OperatorExpr(::std::move(left_bool_expr), ::std::vector<Attribute>(), locus), + expr_type(expr_kind), right_expr(::std::move(right_bool_expr)) {} // outer attributes not allowed // Copy constructor also calls OperatorExpr's protected constructor @@ -712,6 +683,8 @@ namespace Rust { return expr_type; } + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual LazyBooleanExpr* clone_expr_impl() const OVERRIDE { @@ -720,6 +693,9 @@ namespace Rust { // Use covariance to implement clone function as returning this object rather than base virtual LazyBooleanExpr* clone_expr_without_block_impl() const OVERRIDE { + // DEBUG + fprintf(stderr, "called clone_expr_without_block_impl() on lazybooleanexpr\n"); + return new LazyBooleanExpr(*this); } }; @@ -734,9 +710,10 @@ namespace Rust { ::std::string as_string() const; // Constructor requires calling protected constructor of OperatorExpr - TypeCastExpr(Expr* expr_to_cast, TypeNoBounds* type_to_cast_to) : - OperatorExpr(expr_to_cast, ::std::vector<Attribute>()), - type_to_convert_to(type_to_cast_to) {} + TypeCastExpr(::std::unique_ptr<Expr> expr_to_cast, + ::std::unique_ptr<TypeNoBounds> type_to_cast_to, location_t locus) : + OperatorExpr(::std::move(expr_to_cast), ::std::vector<Attribute>(), locus), + type_to_convert_to(::std::move(type_to_cast_to)) {} // outer attributes not allowed // Copy constructor also requires calling protected constructor @@ -759,6 +736,8 @@ namespace Rust { TypeCastExpr(TypeCastExpr&& other) = default; TypeCastExpr& operator=(TypeCastExpr&& other) = default; + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual TypeCastExpr* clone_expr_impl() const OVERRIDE { @@ -767,6 +746,9 @@ namespace Rust { // Use covariance to implement clone function as returning this object rather than base virtual TypeCastExpr* clone_expr_without_block_impl() const OVERRIDE { + // DEBUG + fprintf(stderr, "called clone_expr_without_block_impl() on typecastexpr\n"); + return new TypeCastExpr(*this); } }; @@ -784,14 +766,30 @@ namespace Rust { ::std::string as_string() const; // Call OperatorExpr constructor to initialise left_expr - AssignmentExpr(Expr* value_to_assign_to, Expr* value_to_assign) : - OperatorExpr(value_to_assign_to, ::std::vector<Attribute>()), - right_expr(value_to_assign) {} + AssignmentExpr(::std::unique_ptr<Expr> value_to_assign_to, + ::std::unique_ptr<Expr> value_to_assign, location_t locus) : + OperatorExpr(::std::move(value_to_assign_to), ::std::vector<Attribute>(), locus), + right_expr(::std::move(value_to_assign)) {} // outer attributes not allowed // Call OperatorExpr constructor in copy constructor, as well as clone AssignmentExpr(AssignmentExpr const& other) : - OperatorExpr(other), right_expr(other.right_expr->clone_expr()) {} + OperatorExpr(other) /*, right_expr(other.right_expr->clone_expr())*/ { + // DEBUG: moved cloning right expr into body + fprintf(stderr, + "assignment expr copy constructor successfully cloned base operator expr\n"); + if (other.right_expr == NULL) { + fprintf(stderr, "other expr's right expr (in assignment) is null!!!"); + } + fprintf(stderr, "test other's right expr as string: %s\n", + other.right_expr->as_string().c_str()); + // apparently, despite not being null, cloning still fails + right_expr = other.right_expr->clone_expr(); + fprintf(stderr, "assignment expr copy constructor successfully cloned right expr\n"); + + // DEBUG + fprintf(stderr, "assignment expr copy constructor called successfully\n"); + } // Destructor - define here if required @@ -809,6 +807,8 @@ namespace Rust { AssignmentExpr(AssignmentExpr&& other) = default; AssignmentExpr& operator=(AssignmentExpr&& other) = default; + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual AssignmentExpr* clone_expr_impl() const OVERRIDE { @@ -817,6 +817,9 @@ namespace Rust { // Use covariance to implement clone function as returning this object rather than base virtual AssignmentExpr* clone_expr_without_block_impl() const OVERRIDE { + // DEBUG + fprintf(stderr, "called clone_expr_without_block_impl() on assignmentexpr\n"); + return new AssignmentExpr(*this); } }; @@ -856,10 +859,10 @@ namespace Rust { } // Use pointers in constructor to enable polymorphism - CompoundAssignmentExpr( - Expr* value_to_assign_to, Expr* value_to_assign, ExprType expr_kind) : - OperatorExpr(value_to_assign_to, ::std::vector<Attribute>()), - expr_type(expr_kind), right_expr(value_to_assign) {} + CompoundAssignmentExpr(::std::unique_ptr<Expr> value_to_assign_to, + ::std::unique_ptr<Expr> value_to_assign, ExprType expr_kind, location_t locus) : + OperatorExpr(::std::move(value_to_assign_to), ::std::vector<Attribute>(), locus), + expr_type(expr_kind), right_expr(::std::move(value_to_assign)) {} // outer attributes not allowed // Have clone in copy constructor @@ -884,6 +887,8 @@ namespace Rust { CompoundAssignmentExpr(CompoundAssignmentExpr&& other) = default; CompoundAssignmentExpr& operator=(CompoundAssignmentExpr&& other) = default; + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual CompoundAssignmentExpr* clone_expr_impl() const OVERRIDE { @@ -892,6 +897,9 @@ namespace Rust { // Use covariance to implement clone function as returning this object rather than base virtual CompoundAssignmentExpr* clone_expr_without_block_impl() const OVERRIDE { + // DEBUG + fprintf(stderr, "called clone_expr_without_block_impl() on compoundassignmentexpr\n"); + return new CompoundAssignmentExpr(*this); } }; @@ -902,6 +910,8 @@ namespace Rust { // Expr* expr_in_parens; ::std::unique_ptr<Expr> expr_in_parens; + location_t locus; + public: /*~GroupedExpr() { delete expr_in_parens; @@ -913,16 +923,17 @@ namespace Rust { return inner_attrs; } - // Use pointer in constructor for polymorphism reasons - GroupedExpr(Expr* parenthesised_expr, ::std::vector<Attribute> inner_attribs, - ::std::vector<Attribute> outer_attribs) : + GroupedExpr(::std::unique_ptr<Expr> parenthesised_expr, + ::std::vector<Attribute> inner_attribs, ::std::vector<Attribute> outer_attribs, + location_t locus) : ExprWithoutBlock(::std::move(outer_attribs)), - inner_attrs(::std::move(inner_attribs)), expr_in_parens(parenthesised_expr) {} + inner_attrs(::std::move(inner_attribs)), + expr_in_parens(::std::move(parenthesised_expr)), locus(locus) {} // Copy constructor includes clone for expr_in_parens GroupedExpr(GroupedExpr const& other) : ExprWithoutBlock(other), inner_attrs(other.inner_attrs), - expr_in_parens(other.expr_in_parens->clone_expr()) {} + expr_in_parens(other.expr_in_parens->clone_expr()), locus(other.locus) {} // Destructor - define here if required @@ -931,6 +942,7 @@ namespace Rust { ExprWithoutBlock::operator=(other); inner_attrs = other.inner_attrs; expr_in_parens = other.expr_in_parens->clone_expr(); + locus = other.locus; // outer_attrs = other.outer_attrs; return *this; @@ -940,6 +952,16 @@ namespace Rust { GroupedExpr(GroupedExpr&& other) = default; GroupedExpr& operator=(GroupedExpr&& other) = default; + location_t get_locus() const { + return locus; + } + + location_t get_locus_slow() const OVERRIDE { + return get_locus(); + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual GroupedExpr* clone_expr_impl() const OVERRIDE { @@ -952,7 +974,7 @@ namespace Rust { } }; - // Base array initialisation internal element representation thing + // Base array initialisation internal element representation thing (abstract) // aka ArrayElements class ArrayElems { public: @@ -963,6 +985,10 @@ namespace Rust { return ::std::unique_ptr<ArrayElems>(clone_array_elems_impl()); } + virtual ::std::string as_string() const = 0; + + virtual void accept_vis(ASTVisitor& vis) = 0; + protected: // pure virtual clone implementation virtual ArrayElems* clone_array_elems_impl() const = 0; @@ -973,6 +999,8 @@ namespace Rust { //::std::vector<Expr> values; ::std::vector< ::std::unique_ptr<Expr> > values; + // TODO: should this store location data? + public: /*inline ::std::vector< ::std::unique_ptr<Expr> > get_values() const { return values; @@ -1007,6 +1035,10 @@ namespace Rust { ArrayElemsValues(ArrayElemsValues&& other) = default; ArrayElemsValues& operator=(ArrayElemsValues&& other) = default; + ::std::string as_string() const; + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: virtual ArrayElemsValues* clone_array_elems_impl() const OVERRIDE { return new ArrayElemsValues(*this); @@ -1020,6 +1052,8 @@ namespace Rust { // Expr* num_copies; ::std::unique_ptr<Expr> num_copies; + // TODO: should this store location data? + public: /*~ArrayElemsCopied() { delete num_copies; @@ -1027,8 +1061,10 @@ namespace Rust { }*/ // Constructor requires pointers for polymorphism - ArrayElemsCopied(Expr* copied_elem, Expr* copy_amount) : - elem_to_copy(copied_elem), num_copies(copy_amount) {} + ArrayElemsCopied( + ::std::unique_ptr<Expr> copied_elem, ::std::unique_ptr<Expr> copy_amount) : + elem_to_copy(::std::move(copied_elem)), + num_copies(::std::move(copy_amount)) {} // Copy constructor required due to unique_ptr - uses custom clone ArrayElemsCopied(ArrayElemsCopied const& other) : @@ -1049,6 +1085,10 @@ namespace Rust { ArrayElemsCopied(ArrayElemsCopied&& other) = default; ArrayElemsCopied& operator=(ArrayElemsCopied&& other) = default; + ::std::string as_string() const; + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: virtual ArrayElemsCopied* clone_array_elems_impl() const OVERRIDE { return new ArrayElemsCopied(*this); @@ -1061,6 +1101,8 @@ namespace Rust { // ArrayElems internal_elements; ::std::unique_ptr<ArrayElems> internal_elements; + location_t locus; + public: ::std::string as_string() const; @@ -1068,16 +1110,26 @@ namespace Rust { return inner_attrs; } + // Returns whether array expr has array elems or if it is just empty. + inline bool has_array_elems() const { + return internal_elements != NULL; + } + // Constructor requires ArrayElems pointer - ArrayExpr(ArrayElems* array_elems, ::std::vector<Attribute> inner_attribs, - ::std::vector<Attribute> outer_attribs) : + ArrayExpr(::std::unique_ptr<ArrayElems> array_elems, + ::std::vector<Attribute> inner_attribs, ::std::vector<Attribute> outer_attribs, + location_t locus) : ExprWithoutBlock(::std::move(outer_attribs)), - inner_attrs(::std::move(inner_attribs)), internal_elements(array_elems) {} + inner_attrs(::std::move(inner_attribs)), internal_elements(::std::move(array_elems)), + locus(locus) {} // Copy constructor requires cloning ArrayElems for polymorphism to hold ArrayExpr(ArrayExpr const& other) : - ExprWithoutBlock(other), inner_attrs(other.inner_attrs), - internal_elements(other.internal_elements->clone_array_elems()) {} + ExprWithoutBlock(other), inner_attrs(other.inner_attrs), locus(other.locus) { + if (other.has_array_elems()) { + internal_elements = other.internal_elements->clone_array_elems(); + } + } // Destructor - define here if required @@ -1085,7 +1137,10 @@ namespace Rust { ArrayExpr& operator=(ArrayExpr const& other) { ExprWithoutBlock::operator=(other); inner_attrs = other.inner_attrs; - internal_elements = other.internal_elements->clone_array_elems(); + if (other.has_array_elems()) { + internal_elements = other.internal_elements->clone_array_elems(); + } + locus = other.locus; // outer_attrs = other.outer_attrs; return *this; @@ -1095,6 +1150,16 @@ namespace Rust { ArrayExpr(ArrayExpr&& other) = default; ArrayExpr& operator=(ArrayExpr&& other) = default; + location_t get_locus() const { + return locus; + } + + location_t get_locus_slow() const OVERRIDE { + return get_locus(); + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual ArrayExpr* clone_expr_impl() const OVERRIDE { @@ -1117,6 +1182,8 @@ namespace Rust { ::std::unique_ptr<Expr> array_expr; ::std::unique_ptr<Expr> index_expr; + location_t locus; + public: /*~ArrayIndexExpr() { delete index_expr; @@ -1125,15 +1192,17 @@ namespace Rust { ::std::string as_string() const; - ArrayIndexExpr( - Expr* array_expr, Expr* array_index_expr, ::std::vector<Attribute> outer_attribs) : + ArrayIndexExpr(::std::unique_ptr<Expr> array_expr, + ::std::unique_ptr<Expr> array_index_expr, ::std::vector<Attribute> outer_attribs, + location_t locus) : ExprWithoutBlock(::std::move(outer_attribs)), - array_expr(array_expr), index_expr(array_index_expr) {} + array_expr(::std::move(array_expr)), index_expr(::std::move(array_index_expr)), + locus(locus) {} // Copy constructor requires special cloning due to unique_ptr ArrayIndexExpr(ArrayIndexExpr const& other) : ExprWithoutBlock(other), array_expr(other.array_expr->clone_expr()), - index_expr(other.index_expr->clone_expr()) {} + index_expr(other.index_expr->clone_expr()), locus(other.locus) {} // Destructor - define here if required @@ -1143,6 +1212,7 @@ namespace Rust { array_expr = other.array_expr->clone_expr(); index_expr = other.index_expr->clone_expr(); // outer_attrs = other.outer_attrs; + locus = other.locus; return *this; } @@ -1151,6 +1221,16 @@ namespace Rust { ArrayIndexExpr(ArrayIndexExpr&& other) = default; ArrayIndexExpr& operator=(ArrayIndexExpr&& other) = default; + location_t get_locus() const { + return locus; + } + + location_t get_locus_slow() const OVERRIDE { + return get_locus(); + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual ArrayIndexExpr* clone_expr_impl() const OVERRIDE { @@ -1171,6 +1251,8 @@ namespace Rust { ::std::vector< ::std::unique_ptr<Expr> > tuple_elems; // replaces (inlined version of) TupleElements + location_t locus; + public: ::std::string as_string() const; @@ -1179,13 +1261,15 @@ namespace Rust { } TupleExpr(::std::vector< ::std::unique_ptr<Expr> > tuple_elements, - ::std::vector<Attribute> inner_attribs, ::std::vector<Attribute> outer_attribs) : + ::std::vector<Attribute> inner_attribs, ::std::vector<Attribute> outer_attribs, + location_t locus) : ExprWithoutBlock(::std::move(outer_attribs)), - inner_attrs(::std::move(inner_attribs)), tuple_elems(::std::move(tuple_elements)) {} + inner_attrs(::std::move(inner_attribs)), tuple_elems(::std::move(tuple_elements)), + locus(locus) {} // copy constructor with vector clone TupleExpr(TupleExpr const& other) : - ExprWithoutBlock(other), inner_attrs(other.inner_attrs) { + ExprWithoutBlock(other), inner_attrs(other.inner_attrs), locus(other.locus) { // crappy vector unique pointer clone - TODO is there a better way of doing this? tuple_elems.reserve(other.tuple_elems.size()); @@ -1198,6 +1282,7 @@ namespace Rust { TupleExpr& operator=(TupleExpr const& other) { ExprWithoutBlock::operator=(other); inner_attrs = other.inner_attrs; + locus = other.locus; // crappy vector unique pointer clone - TODO is there a better way of doing this? tuple_elems.reserve(other.tuple_elems.size()); @@ -1216,6 +1301,16 @@ namespace Rust { // Note: syntactically, can disambiguate single-element tuple from parens with comma, i.e. // (0,) rather than (0) + location_t get_locus() const { + return locus; + } + + location_t get_locus_slow() const OVERRIDE { + return get_locus(); + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual TupleExpr* clone_expr_impl() const OVERRIDE { @@ -1236,6 +1331,8 @@ namespace Rust { // TupleIndex is a decimal int literal with no underscores or suffix TupleIndex tuple_index; + location_t locus; + // i.e. pair.0 public: @@ -1249,15 +1346,15 @@ namespace Rust { return tuple_index; } - TupleIndexExpr( - Expr* tuple_expr, TupleIndex index, ::std::vector<Attribute> outer_attribs) : + TupleIndexExpr(::std::unique_ptr<Expr> tuple_expr, TupleIndex index, + ::std::vector<Attribute> outer_attribs, location_t locus) : ExprWithoutBlock(::std::move(outer_attribs)), - tuple_expr(tuple_expr), tuple_index(index) {} + tuple_expr(::std::move(tuple_expr)), tuple_index(index), locus(locus) {} // Copy constructor requires a clone for tuple_expr TupleIndexExpr(TupleIndexExpr const& other) : ExprWithoutBlock(other), tuple_expr(other.tuple_expr->clone_expr()), - tuple_index(other.tuple_index) {} + tuple_index(other.tuple_index), locus(other.locus) {} // Destructor - define here if required @@ -1266,6 +1363,7 @@ namespace Rust { ExprWithoutBlock::operator=(other); tuple_expr = other.tuple_expr->clone_expr(); tuple_index = other.tuple_index; + locus = other.locus; // outer_attrs = other.outer_attrs; return *this; @@ -1275,6 +1373,16 @@ namespace Rust { TupleIndexExpr(TupleIndexExpr&& other) = default; TupleIndexExpr& operator=(TupleIndexExpr&& other) = default; + location_t get_locus() const { + return locus; + } + + location_t get_locus_slow() const OVERRIDE { + return get_locus(); + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual TupleIndexExpr* clone_expr_impl() const OVERRIDE { @@ -1297,15 +1405,19 @@ namespace Rust { ExprWithoutBlock(::std::move(outer_attribs)), struct_name(::std::move(struct_path)) {} public: - inline PathInExpression get_struct_name() const { + inline const PathInExpression& get_struct_name() const { return struct_name; } + + virtual ::std::string as_string() const; }; // Actual AST node of the struct creator (with no fields). Not abstract! class StructExprStruct : public StructExpr { ::std::vector<Attribute> inner_attrs; + location_t locus; + public: ::std::string as_string() const; @@ -1315,9 +1427,19 @@ namespace Rust { // Constructor has to call protected constructor of base class StructExprStruct(PathInExpression struct_path, ::std::vector<Attribute> inner_attribs, - ::std::vector<Attribute> outer_attribs) : + ::std::vector<Attribute> outer_attribs, location_t locus) : StructExpr(::std::move(struct_path), ::std::move(outer_attribs)), - inner_attrs(::std::move(inner_attribs)) {} + inner_attrs(::std::move(inner_attribs)), locus(locus) {} + + location_t get_locus() const { + return locus; + } + + location_t get_locus_slow() const OVERRIDE { + return get_locus(); + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; protected: // Use covariance to implement clone function as returning this object rather than base @@ -1337,13 +1459,25 @@ namespace Rust { // Expr* base_struct; ::std::unique_ptr<Expr> base_struct; + // TODO: should this store location data? + public: - StructBase(Expr* base_struct_ptr) : base_struct(base_struct_ptr) {} + StructBase(::std::unique_ptr<Expr> base_struct_ptr) : + base_struct(::std::move(base_struct_ptr)) {} // Copy constructor requires clone - StructBase(StructBase const& other) : base_struct(other.base_struct->clone_expr()) {} + StructBase(StructBase const& other) { + // HACK: gets around base_struct pointer being null (e.g. if no struct base exists) + if (other.base_struct != NULL) { + other.base_struct->clone_expr(); + } - // Destructor - define here if required + // DEBUG: + fprintf(stderr, "struct base copy constructor called successfully\n"); + } + + // Destructor + ~StructBase() = default; // Overload assignment operator to clone base_struct StructBase& operator=(StructBase const& other) { @@ -1369,6 +1503,8 @@ namespace Rust { inline bool is_invalid() const { return base_struct == NULL; } + + ::std::string as_string() const; }; // Base AST node for a single struct expression field (in struct instance creation) - abstract @@ -1381,6 +1517,10 @@ namespace Rust { return ::std::unique_ptr<StructExprField>(clone_struct_expr_field_impl()); } + virtual ::std::string as_string() const = 0; + + virtual void accept_vis(ASTVisitor& vis) = 0; + protected: // pure virtual clone implementation virtual StructExprField* clone_struct_expr_field_impl() const = 0; @@ -1390,10 +1530,18 @@ namespace Rust { class StructExprFieldIdentifier : public StructExprField { Identifier field_name; + // TODO: should this store location data? + public: StructExprFieldIdentifier(Identifier field_identifier) : field_name(::std::move(field_identifier)) {} + ::std::string as_string() const { + return field_name; + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this rather than base virtual StructExprFieldIdentifier* clone_struct_expr_field_impl() const OVERRIDE { @@ -1407,7 +1555,8 @@ namespace Rust { ::std::unique_ptr<Expr> value; protected: - StructExprFieldWithVal(Expr* field_value) : value(field_value) {} + StructExprFieldWithVal(::std::unique_ptr<Expr> field_value) : + value(::std::move(field_value)) {} // Copy constructor requires clone StructExprFieldWithVal(StructExprFieldWithVal const& other) : @@ -1430,18 +1579,28 @@ namespace Rust { /*~StructExprFieldWithVal() { delete value; }*/ + + ::std::string as_string() const; }; // Identifier and value variant of StructExprField AST node class StructExprFieldIdentifierValue : public StructExprFieldWithVal { Identifier field_name; + // TODO: should this store location data? + public: - StructExprFieldIdentifierValue(Identifier field_identifier, Expr* field_value) : - StructExprFieldWithVal(field_value), field_name(::std::move(field_identifier)) {} + StructExprFieldIdentifierValue( + Identifier field_identifier, ::std::unique_ptr<Expr> field_value) : + StructExprFieldWithVal(::std::move(field_value)), + field_name(::std::move(field_identifier)) {} // copy constructor, destructor, and overloaded assignment operator should carry through + ::std::string as_string() const; + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this rather than base virtual StructExprFieldIdentifierValue* clone_struct_expr_field_impl() const OVERRIDE { @@ -1453,12 +1612,18 @@ namespace Rust { class StructExprFieldIndexValue : public StructExprFieldWithVal { TupleIndex index; + // TODO: should this store location data? + public: - StructExprFieldIndexValue(TupleIndex tuple_index, Expr* field_value) : - StructExprFieldWithVal(field_value), index(tuple_index) {} + StructExprFieldIndexValue(TupleIndex tuple_index, ::std::unique_ptr<Expr> field_value) : + StructExprFieldWithVal(::std::move(field_value)), index(tuple_index) {} // copy constructor, destructor, and overloaded assignment operator should carry through + ::std::string as_string() const; + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this rather than base virtual StructExprFieldIndexValue* clone_struct_expr_field_impl() const OVERRIDE { @@ -1491,23 +1656,38 @@ namespace Rust { // Constructor for StructExprStructFields when no struct base is used StructExprStructFields(PathInExpression struct_path, - ::std::vector< ::std::unique_ptr<StructExprField> > expr_fields, + ::std::vector< ::std::unique_ptr<StructExprField> > expr_fields, location_t locus, StructBase base_struct = StructBase::error(), ::std::vector<Attribute> inner_attribs = ::std::vector<Attribute>(), ::std::vector<Attribute> outer_attribs = ::std::vector<Attribute>()) : - StructExprStruct( - ::std::move(struct_path), ::std::move(inner_attribs), ::std::move(outer_attribs)), + StructExprStruct(::std::move(struct_path), ::std::move(inner_attribs), + ::std::move(outer_attribs), locus), fields(::std::move(expr_fields)), struct_base(::std::move(base_struct)) {} // copy constructor with vector clone StructExprStructFields(StructExprStructFields const& other) : StructExprStruct(other), struct_base(other.struct_base) { + // DEBUG + fprintf(stderr, "got past the initialisation list part of copy constructor\n"); + // crappy vector unique pointer clone - TODO is there a better way of doing this? fields.reserve(other.fields.size()); + // DEBUG + fprintf(stderr, "reserved space in fields\n"); + for (const auto& e : other.fields) { + // DEBUG + fprintf(stderr, "about to clone a field\n"); + fields.push_back(e->clone_struct_expr_field()); + + // DEBUG + fprintf(stderr, "cloned a field successfully\n"); } + + // DEBUG + fprintf(stderr, "finished cloning fields\n"); } // overloaded assignment operator with vector clone @@ -1529,6 +1709,8 @@ namespace Rust { StructExprStructFields(StructExprStructFields&& other) = default; StructExprStructFields& operator=(StructExprStructFields&& other) = default; + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual StructExprStructFields* clone_expr_impl() const OVERRIDE { @@ -1537,6 +1719,26 @@ namespace Rust { // Use covariance to implement clone function as returning this object rather than base virtual StructExprStructFields* clone_expr_without_block_impl() const OVERRIDE { + // DEBUG + fprintf(stderr, "called structexprstructfields clone expr without block impl - about " + "to return new structexprstructfields\n"); + + // DEBUG - test creation of a base from this + fprintf(stderr, "about to try to create and allocate structexprstruct \n"); + StructExprStruct* test_DELETE = new StructExprStruct(*this); + delete test_DELETE; + fprintf(stderr, "managed to create and allocate structexprstruct \n"); + // very weird: can create and allocate structexpstruct but not structexprstructfields + + // DEBUG - test creation of a non-returned class from this + fprintf(stderr, + "about to try to create and allocate structexprstructfields (but not return)\n"); + StructExprStructFields* test_DELETE2 = new StructExprStructFields(*this); + delete test_DELETE2; + fprintf(stderr, + "managed to create and allocate structexprstructfields (if not returned) \n"); + // ok this fails. fair enough. + return new StructExprStructFields(*this); } }; @@ -1553,11 +1755,14 @@ namespace Rust { }*/ StructExprStructBase(PathInExpression struct_path, StructBase base_struct, - ::std::vector<Attribute> inner_attribs, ::std::vector<Attribute> outer_attribs) : - StructExprStruct( - ::std::move(struct_path), ::std::move(inner_attribs), ::std::move(outer_attribs)), + ::std::vector<Attribute> inner_attribs, ::std::vector<Attribute> outer_attribs, + location_t locus) : + StructExprStruct(::std::move(struct_path), ::std::move(inner_attribs), + ::std::move(outer_attribs), locus), struct_base(::std::move(base_struct)) {} + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual StructExprStructBase* clone_expr_impl() const OVERRIDE { @@ -1576,10 +1781,12 @@ namespace Rust { //::std::vector<Expr> exprs; ::std::vector< ::std::unique_ptr<Expr> > exprs; + location_t locus; + public: ::std::string as_string() const; - inline ::std::vector<Attribute> get_inner_attrs() const { + inline const ::std::vector<Attribute>& get_inner_attrs() const { return inner_attrs; } @@ -1589,13 +1796,15 @@ namespace Rust { StructExprTuple(PathInExpression struct_path, ::std::vector< ::std::unique_ptr<Expr> > tuple_exprs, - ::std::vector<Attribute> inner_attribs, ::std::vector<Attribute> outer_attribs) : + ::std::vector<Attribute> inner_attribs, ::std::vector<Attribute> outer_attribs, + location_t locus) : StructExpr(::std::move(struct_path), ::std::move(outer_attribs)), - inner_attrs(::std::move(inner_attribs)), exprs(::std::move(tuple_exprs)) {} + inner_attrs(::std::move(inner_attribs)), exprs(::std::move(tuple_exprs)), locus(locus) { + } // copy constructor with vector clone StructExprTuple(StructExprTuple const& other) : - StructExpr(other), inner_attrs(other.inner_attrs) { + StructExpr(other), inner_attrs(other.inner_attrs), locus(other.locus) { // crappy vector unique pointer clone - TODO is there a better way of doing this? exprs.reserve(other.exprs.size()); @@ -1608,6 +1817,7 @@ namespace Rust { StructExprTuple& operator=(StructExprTuple const& other) { StructExpr::operator=(other); inner_attrs = other.inner_attrs; + locus = other.locus; // crappy vector unique pointer clone - TODO is there a better way of doing this? exprs.reserve(other.exprs.size()); @@ -1623,6 +1833,16 @@ namespace Rust { StructExprTuple(StructExprTuple&& other) = default; StructExprTuple& operator=(StructExprTuple&& other) = default; + location_t get_locus() const { + return locus; + } + + location_t get_locus_slow() const OVERRIDE { + return get_locus(); + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual StructExprTuple* clone_expr_impl() const OVERRIDE { @@ -1637,14 +1857,28 @@ namespace Rust { // AST node of a "unit" struct creator (no fields and no braces) class StructExprUnit : public StructExpr { + location_t locus; + public: ::std::string as_string() const { return get_struct_name().as_string(); // return struct_name.as_string(); } - StructExprUnit(PathInExpression struct_path, ::std::vector<Attribute> outer_attribs) : - StructExpr(::std::move(struct_path), ::std::move(outer_attribs)) {} + StructExprUnit(PathInExpression struct_path, ::std::vector<Attribute> outer_attribs, + location_t locus) : + StructExpr(::std::move(struct_path), ::std::move(outer_attribs)), + locus(locus) {} + + location_t get_locus() const { + return locus; + } + + location_t get_locus_slow() const OVERRIDE { + return get_locus(); + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; protected: // Use covariance to implement clone function as returning this object rather than base @@ -1687,6 +1921,8 @@ namespace Rust { return ::std::unique_ptr<EnumExprField>(clone_enum_expr_field_impl()); } + virtual void accept_vis(ASTVisitor& vis) = 0; + protected: // Clone function implementation as pure virtual method virtual EnumExprField* clone_enum_expr_field_impl() const = 0; @@ -1696,10 +1932,14 @@ namespace Rust { class EnumExprFieldIdentifier : public EnumExprField { Identifier field_name; + // TODO: should this store location data? + public: EnumExprFieldIdentifier(Identifier field_identifier) : field_name(::std::move(field_identifier)) {} + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual EnumExprFieldIdentifier* clone_enum_expr_field_impl() const OVERRIDE { @@ -1712,8 +1952,11 @@ namespace Rust { // Expr* value; ::std::unique_ptr<Expr> value; + // TODO: should this store location data? + protected: - EnumExprFieldWithVal(Expr* field_value) : value(field_value) {} + EnumExprFieldWithVal(::std::unique_ptr<Expr> field_value) : + value(::std::move(field_value)) {} // Copy constructor must clone unique_ptr value EnumExprFieldWithVal(EnumExprFieldWithVal const& other) : @@ -1737,12 +1980,16 @@ namespace Rust { class EnumExprFieldIdentifierValue : public EnumExprFieldWithVal { Identifier field_name; + // TODO: should this store location data? + public: - EnumExprFieldIdentifierValue(Identifier field_name, Expr* field_value) : - EnumExprFieldWithVal(field_value), field_name(::std::move(field_name)) {} + EnumExprFieldIdentifierValue(Identifier field_name, ::std::unique_ptr<Expr> field_value) : + EnumExprFieldWithVal(::std::move(field_value)), field_name(::std::move(field_name)) {} // copy constructor, destructor, and assignment operator should not need defining + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual EnumExprFieldIdentifierValue* clone_enum_expr_field_impl() const OVERRIDE { @@ -1755,12 +2002,16 @@ namespace Rust { TupleIndex index; // TODO: implement "with val" as a template with EnumExprField as type param? + // TODO: should this store location data? + public: - EnumExprFieldIndexValue(TupleIndex field_index, Expr* field_value) : - EnumExprFieldWithVal(field_value), index(field_index) {} + EnumExprFieldIndexValue(TupleIndex field_index, ::std::unique_ptr<Expr> field_value) : + EnumExprFieldWithVal(::std::move(field_value)), index(field_index) {} // copy constructor, destructor, and assignment operator should not need defining + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual EnumExprFieldIndexValue* clone_enum_expr_field_impl() const OVERRIDE { @@ -1773,6 +2024,8 @@ namespace Rust { //::std::vector<EnumExprField> fields; ::std::vector< ::std::unique_ptr<EnumExprField> > fields; + location_t locus; + public: ::std::string as_string() const; @@ -1782,12 +2035,12 @@ namespace Rust { EnumExprStruct(PathInExpression enum_variant_path, ::std::vector< ::std::unique_ptr<EnumExprField> > variant_fields, - ::std::vector<Attribute> outer_attribs) : + ::std::vector<Attribute> outer_attribs, location_t locus) : EnumVariantExpr(::std::move(enum_variant_path), ::std::move(outer_attribs)), - fields(::std::move(variant_fields)) {} + fields(::std::move(variant_fields)), locus(locus) {} // copy constructor with vector clone - EnumExprStruct(EnumExprStruct const& other) : EnumVariantExpr(other) { + EnumExprStruct(EnumExprStruct const& other) : EnumVariantExpr(other), locus(other.locus) { // crappy vector unique pointer clone - TODO is there a better way of doing this? fields.reserve(other.fields.size()); @@ -1799,6 +2052,7 @@ namespace Rust { // overloaded assignment operator with vector clone EnumExprStruct& operator=(EnumExprStruct const& other) { EnumVariantExpr::operator=(other); + locus = other.locus; // crappy vector unique pointer clone - TODO is there a better way of doing this? fields.reserve(other.fields.size()); @@ -1814,6 +2068,16 @@ namespace Rust { EnumExprStruct(EnumExprStruct&& other) = default; EnumExprStruct& operator=(EnumExprStruct&& other) = default; + location_t get_locus() const { + return locus; + } + + location_t get_locus_slow() const OVERRIDE { + return get_locus(); + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual EnumExprStruct* clone_expr_impl() const OVERRIDE { @@ -1831,6 +2095,8 @@ namespace Rust { //::std::vector<Expr> values; ::std::vector< ::std::unique_ptr<Expr> > values; + location_t locus; + public: ::std::string as_string() const; @@ -1840,12 +2106,12 @@ namespace Rust { EnumExprTuple(PathInExpression enum_variant_path, ::std::vector< ::std::unique_ptr<Expr> > variant_values, - ::std::vector<Attribute> outer_attribs) : + ::std::vector<Attribute> outer_attribs, location_t locus) : EnumVariantExpr(::std::move(enum_variant_path), ::std::move(outer_attribs)), - values(::std::move(variant_values)) {} + values(::std::move(variant_values)), locus(locus) {} // copy constructor with vector clone - EnumExprTuple(EnumExprTuple const& other) : EnumVariantExpr(other) { + EnumExprTuple(EnumExprTuple const& other) : EnumVariantExpr(other), locus(other.locus) { // crappy vector unique pointer clone - TODO is there a better way of doing this? values.reserve(other.values.size()); @@ -1857,6 +2123,7 @@ namespace Rust { // overloaded assignment operator with vector clone EnumExprTuple& operator=(EnumExprTuple const& other) { EnumVariantExpr::operator=(other); + locus = other.locus; // crappy vector unique pointer clone - TODO is there a better way of doing this? values.reserve(other.values.size()); @@ -1872,6 +2139,16 @@ namespace Rust { EnumExprTuple(EnumExprTuple&& other) = default; EnumExprTuple& operator=(EnumExprTuple&& other) = default; + location_t get_locus() const { + return locus; + } + + location_t get_locus_slow() const OVERRIDE { + return get_locus(); + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual EnumExprTuple* clone_expr_impl() const OVERRIDE { @@ -1886,18 +2163,31 @@ namespace Rust { // No-field enum variant instance creation AST node class EnumExprFieldless : public EnumVariantExpr { + location_t locus; + public: ::std::string as_string() const { // return enum_variant_path.as_string(); return get_enum_variant_path().as_string(); } - EnumExprFieldless( - PathInExpression enum_variant_path, ::std::vector<Attribute> outer_attribs) : - EnumVariantExpr(::std::move(enum_variant_path), ::std::move(outer_attribs)) {} + EnumExprFieldless(PathInExpression enum_variant_path, + ::std::vector<Attribute> outer_attribs, location_t locus) : + EnumVariantExpr(::std::move(enum_variant_path), ::std::move(outer_attribs)), + locus(locus) {} // copy constructor, destructor, and assignment operator should not need defining + location_t get_locus() const { + return locus; + } + + location_t get_locus_slow() const OVERRIDE { + return get_locus(); + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual EnumExprFieldless* clone_expr_impl() const OVERRIDE { @@ -1917,6 +2207,8 @@ namespace Rust { //::std::vector<Expr> params; // inlined form of CallParams ::std::vector< ::std::unique_ptr<Expr> > params; + location_t locus; + public: /*~CallExpr() { delete function; @@ -1928,14 +2220,16 @@ namespace Rust { return params; }*/ - CallExpr(Expr* function_expr, ::std::vector< ::std::unique_ptr<Expr> > function_params, - ::std::vector<Attribute> outer_attribs) : + CallExpr(::std::unique_ptr<Expr> function_expr, + ::std::vector< ::std::unique_ptr<Expr> > function_params, + ::std::vector<Attribute> outer_attribs, location_t locus) : ExprWithoutBlock(::std::move(outer_attribs)), - function(function_expr), params(::std::move(function_params)) {} + function(::std::move(function_expr)), params(::std::move(function_params)), + locus(locus) {} // copy constructor requires clone CallExpr(CallExpr const& other) : - ExprWithoutBlock(other), function(other.function->clone_expr()) + ExprWithoutBlock(other), function(other.function->clone_expr()), locus(other.locus) /*, params(other.params),*/ { // crappy vector unique pointer clone - TODO is there a better way of doing this? params.reserve(other.params.size()); @@ -1951,6 +2245,7 @@ namespace Rust { CallExpr& operator=(CallExpr const& other) { ExprWithoutBlock::operator=(other); function = other.function->clone_expr(); + locus = other.locus; // params = other.params; // outer_attrs = other.outer_attrs; @@ -1973,6 +2268,16 @@ namespace Rust { return !params.empty(); } + location_t get_locus() const { + return locus; + } + + location_t get_locus_slow() const OVERRIDE { + return get_locus(); + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual CallExpr* clone_expr_impl() const OVERRIDE { @@ -1993,6 +2298,8 @@ namespace Rust { //::std::vector<Expr> params; // inlined form of CallParams ::std::vector< ::std::unique_ptr<Expr> > params; + location_t locus; + public: /*~MethodCallExpr() { delete receiver; @@ -2004,17 +2311,17 @@ namespace Rust { return params; }*/ - MethodCallExpr(Expr* call_receiver, PathExprSegment method_path, + MethodCallExpr(::std::unique_ptr<Expr> call_receiver, PathExprSegment method_path, ::std::vector< ::std::unique_ptr<Expr> > method_params, - ::std::vector<Attribute> outer_attribs) : + ::std::vector<Attribute> outer_attribs, location_t locus) : ExprWithoutBlock(::std::move(outer_attribs)), - receiver(call_receiver), method_name(::std::move(method_path)), - params(::std::move(method_params)) {} + receiver(::std::move(call_receiver)), method_name(::std::move(method_path)), + params(::std::move(method_params)), locus(locus) {} // copy constructor required due to cloning MethodCallExpr(MethodCallExpr const& other) : ExprWithoutBlock(other), receiver(other.receiver->clone_expr()), - method_name(other.method_name) + method_name(other.method_name), locus(other.locus) /*, params(other.params),*/ { // crappy vector unique pointer clone - TODO is there a better way of doing this? params.reserve(other.params.size()); @@ -2031,6 +2338,7 @@ namespace Rust { ExprWithoutBlock::operator=(other); receiver = other.receiver->clone_expr(); method_name = other.method_name; + locus = other.locus; // params = other.params; // outer_attrs = other.outer_attrs; @@ -2048,6 +2356,16 @@ namespace Rust { MethodCallExpr(MethodCallExpr&& other) = default; MethodCallExpr& operator=(MethodCallExpr&& other) = default; + location_t get_locus() const { + return locus; + } + + location_t get_locus_slow() const OVERRIDE { + return get_locus(); + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual MethodCallExpr* clone_expr_impl() const OVERRIDE { @@ -2067,6 +2385,8 @@ namespace Rust { ::std::unique_ptr<Expr> receiver; Identifier field; + location_t locus; + public: /*~FieldAccessExpr() { delete receiver; @@ -2074,14 +2394,16 @@ namespace Rust { ::std::string as_string() const; - FieldAccessExpr(Expr* field_access_receiver, Identifier field_name, - ::std::vector<Attribute> outer_attribs) : + FieldAccessExpr(::std::unique_ptr<Expr> field_access_receiver, Identifier field_name, + ::std::vector<Attribute> outer_attribs, location_t locus) : ExprWithoutBlock(::std::move(outer_attribs)), - receiver(field_access_receiver), field(::std::move(field_name)) {} + receiver(::std::move(field_access_receiver)), field(::std::move(field_name)), + locus(locus) {} // Copy constructor required due to unique_ptr cloning FieldAccessExpr(FieldAccessExpr const& other) : - ExprWithoutBlock(other), receiver(other.receiver->clone_expr()), field(other.field) {} + ExprWithoutBlock(other), receiver(other.receiver->clone_expr()), field(other.field), + locus(other.locus) {} // Destructor - define here if required @@ -2090,6 +2412,7 @@ namespace Rust { ExprWithoutBlock::operator=(other); receiver = other.receiver->clone_expr(); field = other.field; + locus = other.locus; // outer_attrs = other.outer_attrs; return *this; @@ -2099,6 +2422,16 @@ namespace Rust { FieldAccessExpr(FieldAccessExpr&& other) = default; FieldAccessExpr& operator=(FieldAccessExpr&& other) = default; + location_t get_locus() const { + return locus; + } + + location_t get_locus_slow() const OVERRIDE { + return get_locus(); + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual FieldAccessExpr* clone_expr_impl() const OVERRIDE { @@ -2121,6 +2454,8 @@ namespace Rust { // Type type; ::std::unique_ptr<Type> type; + // TODO: should this store location data? + public: // Returns whether the type of the parameter has been given. inline bool has_type_given() const { @@ -2128,12 +2463,18 @@ namespace Rust { } // Constructor for closure parameter - ClosureParam(Pattern* param_pattern, Type* param_type = NULL) : - pattern(param_pattern), type(param_type) {} + ClosureParam( + ::std::unique_ptr<Pattern> param_pattern, ::std::unique_ptr<Type> param_type = NULL) : + pattern(::std::move(param_pattern)), + type(::std::move(param_type)) {} // Copy constructor required due to cloning as a result of unique_ptrs - ClosureParam(ClosureParam const& other) : - pattern(other.pattern->clone_pattern()), type(other.type->clone_type()) {} + ClosureParam(ClosureParam const& other) : pattern(other.pattern->clone_pattern()) { + // guard to protect from null pointer dereference + if (other.type != NULL) { + type = other.type->clone_type(); + } + } ~ClosureParam() = default; @@ -2158,6 +2499,8 @@ namespace Rust { static ClosureParam create_error() { return ClosureParam(NULL); } + + ::std::string as_string() const; }; // Base closure definition expression AST node - abstract @@ -2166,13 +2509,25 @@ namespace Rust { ::std::vector<ClosureParam> params; // may be empty // also note a double pipe "||" can be used for empty params - does not need a space + location_t locus; + protected: ClosureExpr(::std::vector<ClosureParam> closure_params, bool has_move, - ::std::vector<Attribute> outer_attribs) : + ::std::vector<Attribute> outer_attribs, location_t locus) : ExprWithoutBlock(::std::move(outer_attribs)), - has_move(has_move), params(::std::move(closure_params)) {} + has_move(has_move), params(::std::move(closure_params)), locus(locus) {} // Copy constructor, destructor, and assignment operator override should not be needed + public: + virtual ::std::string as_string() const; + + location_t get_locus() const { + return locus; + } + + location_t get_locus_slow() const OVERRIDE { + return get_locus(); + } }; // Represents a non-type-specified closure expression AST node @@ -2188,11 +2543,11 @@ namespace Rust { ::std::string as_string() const; // Constructor for a ClosureExprInner - ClosureExprInner(Expr* closure_inner_expr, ::std::vector<ClosureParam> closure_params, - bool is_move = false, + ClosureExprInner(::std::unique_ptr<Expr> closure_inner_expr, + ::std::vector<ClosureParam> closure_params, location_t locus, bool is_move = false, ::std::vector<Attribute> outer_attribs = ::std::vector<Attribute>()) : - ClosureExpr(::std::move(closure_params), is_move, ::std::move(outer_attribs)), - closure_inner(closure_inner_expr) {} + ClosureExpr(::std::move(closure_params), is_move, ::std::move(outer_attribs), locus), + closure_inner(::std::move(closure_inner_expr)) {} // Copy constructor must be defined to allow copying via cloning of unique_ptr ClosureExprInner(ClosureExprInner const& other) : @@ -2216,6 +2571,8 @@ namespace Rust { ClosureExprInner(ClosureExprInner&& other) = default; ClosureExprInner& operator=(ClosureExprInner&& other) = default; + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual ClosureExprInner* clone_expr_impl() const OVERRIDE { @@ -2243,6 +2600,8 @@ namespace Rust { // bool has_expr; ::std::unique_ptr<ExprWithoutBlock> expr; // inlined from Statements + location_t locus; + public: ::std::string as_string() const; @@ -2257,16 +2616,21 @@ namespace Rust { } BlockExpr(::std::vector< ::std::unique_ptr<Stmt> > block_statements, - ExprWithoutBlock* block_expr, ::std::vector<Attribute> inner_attribs, - ::std::vector<Attribute> outer_attribs) : + ::std::unique_ptr<ExprWithoutBlock> block_expr, ::std::vector<Attribute> inner_attribs, + ::std::vector<Attribute> outer_attribs, location_t locus) : ExprWithBlock(::std::move(outer_attribs)), inner_attrs(::std::move(inner_attribs)), statements(::std::move(block_statements)), - expr(block_expr) {} + expr(::std::move(block_expr)), locus(locus) {} // Copy constructor with clone BlockExpr(BlockExpr const& other) : ExprWithBlock(other), /*statements(other.statements),*/ - inner_attrs(other.inner_attrs), expr(other.expr->clone_expr_without_block()) { + inner_attrs(other.inner_attrs), locus(other.locus) { + // guard to protect from null pointer dereference + if (other.expr != NULL) { + expr = other.expr->clone_expr_without_block(); + } + // crappy vector unique pointer clone - TODO is there a better way of doing this? statements.reserve(other.statements.size()); @@ -2283,6 +2647,7 @@ namespace Rust { // statements = other.statements; expr = other.expr->clone_expr_without_block(); inner_attrs = other.inner_attrs; + locus = other.locus; // outer_attrs = other.outer_attrs; // crappy vector unique pointer clone - TODO is there a better way of doing this? @@ -2304,6 +2669,16 @@ namespace Rust { return ::std::unique_ptr<BlockExpr>(clone_block_expr_impl()); } + location_t get_locus() const { + return locus; + } + + location_t get_locus_slow() const OVERRIDE { + return get_locus(); + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual BlockExpr* clone_expr_impl() const OVERRIDE { @@ -2337,11 +2712,12 @@ namespace Rust { ::std::string as_string() const; // Constructor potentially with a move - ClosureExprInnerTyped(Type* closure_return_type, BlockExpr* closure_expr, - ::std::vector<ClosureParam> closure_params, bool is_move = false, + ClosureExprInnerTyped(::std::unique_ptr<Type> closure_return_type, + ::std::unique_ptr<BlockExpr> closure_expr, ::std::vector<ClosureParam> closure_params, + location_t locus, bool is_move = false, ::std::vector<Attribute> outer_attribs = ::std::vector<Attribute>()) : - ClosureExpr(::std::move(closure_params), is_move, ::std::move(outer_attribs)), - return_type(closure_return_type), expr(closure_expr) {} + ClosureExpr(::std::move(closure_params), is_move, ::std::move(outer_attribs), locus), + return_type(::std::move(closure_return_type)), expr(::std::move(closure_expr)) {} // Copy constructor requires cloning ClosureExprInnerTyped(ClosureExprInnerTyped const& other) : @@ -2366,6 +2742,8 @@ namespace Rust { ClosureExprInnerTyped(ClosureExprInnerTyped&& other) = default; ClosureExprInnerTyped& operator=(ClosureExprInnerTyped&& other) = default; + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual ClosureExprInnerTyped* clone_expr_impl() const OVERRIDE { @@ -2383,6 +2761,8 @@ namespace Rust { // bool has_label; Lifetime label; + location_t locus; + public: ::std::string as_string() const; @@ -2392,13 +2772,23 @@ namespace Rust { } // Constructor for a ContinueExpr with a label. - ContinueExpr(Lifetime label = Lifetime::error(), + ContinueExpr(location_t locus, Lifetime label = Lifetime::error(), ::std::vector<Attribute> outer_attribs = ::std::vector<Attribute>()) : ExprWithoutBlock(::std::move(outer_attribs)), - label(::std::move(label)) {} + label(::std::move(label)), locus(locus) {} // copy constructor, destructor, and assignment operator should not need defining + location_t get_locus() const { + return locus; + } + + location_t get_locus_slow() const OVERRIDE { + return get_locus(); + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual ContinueExpr* clone_expr_impl() const OVERRIDE { @@ -2421,6 +2811,8 @@ namespace Rust { // Expr* break_expr; // may be uninitialised ::std::unique_ptr<Expr> break_expr; + location_t locus; + public: /*~BreakExpr() { if (has_break_expr) { @@ -2441,15 +2833,20 @@ namespace Rust { } // Constructor for a break expression - BreakExpr(Lifetime break_label = Lifetime::error(), Expr* expr_in_break = NULL, + BreakExpr(location_t locus, Lifetime break_label = Lifetime::error(), + ::std::unique_ptr<Expr> expr_in_break = NULL, ::std::vector<Attribute> outer_attribs = ::std::vector<Attribute>()) : ExprWithoutBlock(::std::move(outer_attribs)), - label(::std::move(break_label)), break_expr(expr_in_break) {} + label(::std::move(break_label)), break_expr(::std::move(expr_in_break)), locus(locus) {} // Copy constructor defined to use clone for unique pointer BreakExpr(BreakExpr const& other) : - ExprWithoutBlock(other), label(other.label), - break_expr(other.break_expr->clone_expr()) {} + ExprWithoutBlock(other), label(other.label), locus(other.locus) { + // guard to protect from null pointer dereference + if (other.break_expr != NULL) { + break_expr = other.break_expr->clone_expr(); + } + } // Destructor - define here if required @@ -2458,6 +2855,7 @@ namespace Rust { ExprWithoutBlock::operator=(other); label = other.label; break_expr = other.break_expr->clone_expr(); + locus = other.locus; // outer_attrs = other.outer_attrs; return *this; @@ -2467,6 +2865,16 @@ namespace Rust { BreakExpr(BreakExpr&& other) = default; BreakExpr& operator=(BreakExpr&& other) = default; + location_t get_locus() const { + return locus; + } + + location_t get_locus_slow() const OVERRIDE { + return get_locus(); + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual BreakExpr* clone_expr_impl() const OVERRIDE { @@ -2481,9 +2889,21 @@ namespace Rust { // Base range expression AST node object - abstract class RangeExpr : public ExprWithoutBlock { + location_t locus; + protected: // outer attributes not allowed before range expressions - RangeExpr() : ExprWithoutBlock(::std::vector<Attribute>()) {} + RangeExpr(location_t locus) : + ExprWithoutBlock(::std::vector<Attribute>()), locus(locus) {} + + public: + location_t get_locus() const { + return locus; + } + + location_t get_locus_slow() const OVERRIDE { + return get_locus(); + } }; // Range from (inclusive) and to (exclusive) expression AST node object @@ -2502,9 +2922,10 @@ namespace Rust { ::std::string as_string() const; - RangeFromToExpr(Expr* range_from, Expr* range_to) : - RangeExpr(), from(range_from), to(range_to) {} - // outer attributes not allowed + RangeFromToExpr(::std::unique_ptr<Expr> range_from, ::std::unique_ptr<Expr> range_to, + location_t locus) : + RangeExpr(locus), + from(::std::move(range_from)), to(::std::move(range_to)) {} // Copy constructor with cloning RangeFromToExpr(RangeFromToExpr const& other) : @@ -2521,10 +2942,12 @@ namespace Rust { return *this; } - // move constructors as not supported in c++03 + // move constructors RangeFromToExpr(RangeFromToExpr&& other) = default; RangeFromToExpr& operator=(RangeFromToExpr&& other) = default; + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual RangeFromToExpr* clone_expr_impl() const OVERRIDE { @@ -2550,8 +2973,8 @@ namespace Rust { ::std::string as_string() const; - RangeFromExpr(Expr* range_from) : RangeExpr(), from(range_from) {} - // outer attributes not allowed + RangeFromExpr(::std::unique_ptr<Expr> range_from, location_t locus) : + RangeExpr(locus), from(::std::move(range_from)) {} // Copy constructor with clone RangeFromExpr(RangeFromExpr const& other) : @@ -2571,6 +2994,8 @@ namespace Rust { RangeFromExpr(RangeFromExpr&& other) = default; RangeFromExpr& operator=(RangeFromExpr&& other) = default; + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual RangeFromExpr* clone_expr_impl() const OVERRIDE { @@ -2597,7 +3022,8 @@ namespace Rust { ::std::string as_string() const; // outer attributes not allowed - RangeToExpr(Expr* range_to) : RangeExpr(), to(range_to) {} + RangeToExpr(::std::unique_ptr<Expr> range_to, location_t locus) : + RangeExpr(locus), to(::std::move(range_to)) {} // Copy constructor with clone RangeToExpr(RangeToExpr const& other) : RangeExpr(other), to(other.to->clone_expr()) {} @@ -2616,6 +3042,8 @@ namespace Rust { RangeToExpr(RangeToExpr&& other) = default; RangeToExpr& operator=(RangeToExpr&& other) = default; + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual RangeToExpr* clone_expr_impl() const OVERRIDE { @@ -2634,9 +3062,11 @@ namespace Rust { public: ::std::string as_string() const; - RangeFullExpr() : RangeExpr() {} + RangeFullExpr(location_t locus) : RangeExpr(locus) {} // outer attributes not allowed + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual RangeFullExpr* clone_expr_impl() const OVERRIDE { @@ -2665,8 +3095,10 @@ namespace Rust { ::std::string as_string() const; - RangeFromToInclExpr(Expr* range_from, Expr* range_to) : - RangeExpr(), from(range_from), to(range_to) {} + RangeFromToInclExpr(::std::unique_ptr<Expr> range_from, ::std::unique_ptr<Expr> range_to, + location_t locus) : + RangeExpr(locus), + from(::std::move(range_from)), to(::std::move(range_to)) {} // outer attributes not allowed // Copy constructor with clone @@ -2688,6 +3120,8 @@ namespace Rust { RangeFromToInclExpr(RangeFromToInclExpr&& other) = default; RangeFromToInclExpr& operator=(RangeFromToInclExpr&& other) = default; + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual RangeFromToInclExpr* clone_expr_impl() const OVERRIDE { @@ -2713,7 +3147,8 @@ namespace Rust { ::std::string as_string() const; - RangeToInclExpr(Expr* range_to) : RangeExpr(), to(range_to) {} + RangeToInclExpr(::std::unique_ptr<Expr> range_to, location_t locus) : + RangeExpr(locus), to(::std::move(range_to)) {} // outer attributes not allowed // Copy constructor with clone @@ -2734,6 +3169,8 @@ namespace Rust { RangeToInclExpr(RangeToInclExpr&& other) = default; RangeToInclExpr& operator=(RangeToInclExpr&& other) = default; + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual RangeToInclExpr* clone_expr_impl() const OVERRIDE { @@ -2752,6 +3189,8 @@ namespace Rust { // Expr* return_expr; ::std::unique_ptr<Expr> return_expr; + location_t locus; + public: /*~ReturnExpr() { if (has_return_expr) { @@ -2767,14 +3206,18 @@ namespace Rust { } // Constructor for ReturnExpr. - ReturnExpr(Expr* returned_expr = NULL, + ReturnExpr(location_t locus, ::std::unique_ptr<Expr> returned_expr = NULL, ::std::vector<Attribute> outer_attribs = ::std::vector<Attribute>()) : ExprWithoutBlock(::std::move(outer_attribs)), - return_expr(returned_expr) {} + return_expr(::std::move(returned_expr)), locus(locus) {} // Copy constructor with clone - ReturnExpr(ReturnExpr const& other) : - ExprWithoutBlock(other), return_expr(other.return_expr->clone_expr()) {} + ReturnExpr(ReturnExpr const& other) : ExprWithoutBlock(other), locus(other.locus) { + // guard to protect from null pointer dereference + if (other.return_expr != NULL) { + return_expr = other.return_expr->clone_expr(); + } + } // Destructor - define here if required @@ -2782,6 +3225,7 @@ namespace Rust { ReturnExpr& operator=(ReturnExpr const& other) { ExprWithoutBlock::operator=(other); return_expr = other.return_expr->clone_expr(); + locus = other.locus; // outer_attrs = other.outer_attrs; return *this; @@ -2791,6 +3235,16 @@ namespace Rust { ReturnExpr(ReturnExpr&& other) = default; ReturnExpr& operator=(ReturnExpr&& other) = default; + location_t get_locus() const { + return locus; + } + + location_t get_locus_slow() const OVERRIDE { + return get_locus(); + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual ReturnExpr* clone_expr_impl() const OVERRIDE { @@ -2816,6 +3270,8 @@ namespace Rust { // BlockExpr* expr; ::std::unique_ptr<BlockExpr> expr; + location_t locus; + public: /*~UnsafeBlockExpr() { delete expr; @@ -2823,12 +3279,14 @@ namespace Rust { ::std::string as_string() const; - UnsafeBlockExpr(BlockExpr* block_expr, ::std::vector<Attribute> outer_attribs) : - ExprWithBlock(::std::move(outer_attribs)), expr(block_expr) {} + UnsafeBlockExpr(::std::unique_ptr<BlockExpr> block_expr, + ::std::vector<Attribute> outer_attribs, location_t locus) : + ExprWithBlock(::std::move(outer_attribs)), + expr(::std::move(block_expr)), locus(locus) {} // Copy constructor with clone UnsafeBlockExpr(UnsafeBlockExpr const& other) : - ExprWithBlock(other), expr(other.expr->clone_block_expr()) {} + ExprWithBlock(other), expr(other.expr->clone_block_expr()), locus(other.locus) {} // Destructor - define here if required @@ -2836,6 +3294,7 @@ namespace Rust { UnsafeBlockExpr& operator=(UnsafeBlockExpr const& other) { ExprWithBlock::operator=(other); expr = other.expr->clone_block_expr(); + locus = other.locus; // outer_attrs = other.outer_attrs; return *this; @@ -2845,6 +3304,16 @@ namespace Rust { UnsafeBlockExpr(UnsafeBlockExpr&& other) = default; UnsafeBlockExpr& operator=(UnsafeBlockExpr&& other) = default; + location_t get_locus() const { + return locus; + } + + location_t get_locus_slow() const OVERRIDE { + return get_locus(); + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual UnsafeBlockExpr* clone_expr_impl() const OVERRIDE { @@ -2859,13 +3328,16 @@ namespace Rust { // Loop label expression AST node used with break and continue expressions // TODO: inline? - class LoopLabel : public Node { + class LoopLabel /*: public Node*/ { Lifetime label; // or type LIFETIME_OR_LABEL + location_t locus; + public: ::std::string as_string() const; - LoopLabel(Lifetime loop_label) : label(::std::move(loop_label)) {} + LoopLabel(Lifetime loop_label, location_t locus = UNKNOWN_LOCATION) : + label(::std::move(loop_label)), locus(locus) {} // Returns whether the LoopLabel is in an error state. inline bool is_error() const { @@ -2876,27 +3348,38 @@ namespace Rust { static LoopLabel error() { return LoopLabel(Lifetime::error()); } + + location_t get_locus() const { + return locus; + } }; // Base loop expression AST node - aka LoopExpr class BaseLoopExpr : public ExprWithBlock { + protected: + // protected to allow subclasses better use of them // bool has_loop_label; LoopLabel loop_label; // BlockExpr* loop_block; ::std::unique_ptr<BlockExpr> loop_block; + private: + location_t locus; + protected: // Constructor for BaseLoopExpr - BaseLoopExpr(BlockExpr* loop_block, LoopLabel loop_label = LoopLabel::error(), + BaseLoopExpr(::std::unique_ptr<BlockExpr> loop_block, location_t locus, + LoopLabel loop_label = LoopLabel::error(), ::std::vector<Attribute> outer_attribs = ::std::vector<Attribute>()) : ExprWithBlock(::std::move(outer_attribs)), - loop_label(::std::move(loop_label)), loop_block(loop_block) {} + loop_label(::std::move(loop_label)), loop_block(::std::move(loop_block)), locus(locus) { + } // Copy constructor for BaseLoopExpr with clone BaseLoopExpr(BaseLoopExpr const& other) : ExprWithBlock(other), loop_label(other.loop_label), - loop_block(other.loop_block->clone_block_expr()) {} + loop_block(other.loop_block->clone_block_expr()), locus(other.locus) {} // Destructor - define here if required @@ -2905,6 +3388,7 @@ namespace Rust { ExprWithBlock::operator=(other); loop_block = other.loop_block->clone_block_expr(); loop_label = other.loop_label; + locus = other.locus; // outer_attrs = other.outer_attrs; return *this; @@ -2922,6 +3406,14 @@ namespace Rust { inline bool has_loop_label() const { return !loop_label.is_error(); } + + location_t get_locus() const { + return locus; + } + + location_t get_locus_slow() const OVERRIDE { + return get_locus(); + } }; // 'Loop' expression (i.e. the infinite loop) AST node @@ -2930,12 +3422,16 @@ namespace Rust { ::std::string as_string() const; // Constructor for LoopExpr - LoopExpr(BlockExpr* loop_block, LoopLabel loop_label = LoopLabel::error(), + LoopExpr(::std::unique_ptr<BlockExpr> loop_block, location_t locus, + LoopLabel loop_label = LoopLabel::error(), ::std::vector<Attribute> outer_attribs = ::std::vector<Attribute>()) : - BaseLoopExpr(loop_block, ::std::move(loop_label), ::std::move(outer_attribs)) {} + BaseLoopExpr(::std::move(loop_block), locus, ::std::move(loop_label), + ::std::move(outer_attribs)) {} // copy constructor, destructor, and assignment operator should not need modification + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual LoopExpr* clone_expr_impl() const OVERRIDE { @@ -2961,11 +3457,13 @@ namespace Rust { ::std::string as_string() const; // Constructor for while loop with loop label - WhileLoopExpr(Expr* loop_condition, BlockExpr* loop_block, + WhileLoopExpr(::std::unique_ptr<Expr> loop_condition, + ::std::unique_ptr<BlockExpr> loop_block, location_t locus, LoopLabel loop_label = LoopLabel::error(), ::std::vector<Attribute> outer_attribs = ::std::vector<Attribute>()) : - BaseLoopExpr(loop_block, ::std::move(loop_label), ::std::move(outer_attribs)), - condition(loop_condition) {} + BaseLoopExpr( + ::std::move(loop_block), locus, ::std::move(loop_label), ::std::move(outer_attribs)), + condition(::std::move(loop_condition)) {} // Copy constructor with clone WhileLoopExpr(WhileLoopExpr const& other) : @@ -2988,6 +3486,8 @@ namespace Rust { WhileLoopExpr(WhileLoopExpr&& other) = default; WhileLoopExpr& operator=(WhileLoopExpr&& other) = default; + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual WhileLoopExpr* clone_expr_impl() const OVERRIDE { @@ -3019,10 +3519,13 @@ namespace Rust { // Constructor with a loop label WhileLetLoopExpr(::std::vector< ::std::unique_ptr<Pattern> > match_arm_patterns, - Expr* condition, BlockExpr* loop_block, LoopLabel loop_label = LoopLabel::error(), + ::std::unique_ptr<Expr> condition, ::std::unique_ptr<BlockExpr> loop_block, + location_t locus, LoopLabel loop_label = LoopLabel::error(), ::std::vector<Attribute> outer_attribs = ::std::vector<Attribute>()) : - BaseLoopExpr(loop_block, ::std::move(loop_label), ::std::move(outer_attribs)), - match_arm_patterns(::std::move(match_arm_patterns)), condition(condition) {} + BaseLoopExpr( + ::std::move(loop_block), locus, ::std::move(loop_label), ::std::move(outer_attribs)), + match_arm_patterns(::std::move(match_arm_patterns)), condition(::std::move(condition)) { + } // Copy constructor with clone WhileLetLoopExpr(WhileLetLoopExpr const& other) : @@ -3061,6 +3564,8 @@ namespace Rust { WhileLetLoopExpr(WhileLetLoopExpr&& other) = default; WhileLetLoopExpr& operator=(WhileLetLoopExpr&& other) = default; + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual WhileLetLoopExpr* clone_expr_impl() const OVERRIDE { @@ -3088,11 +3593,13 @@ namespace Rust { ::std::string as_string() const; // Constructor with loop label - ForLoopExpr(Pattern* loop_pattern, Expr* iterator_expr, BlockExpr* loop_body, - LoopLabel loop_label = LoopLabel::error(), + ForLoopExpr(::std::unique_ptr<Pattern> loop_pattern, + ::std::unique_ptr<Expr> iterator_expr, ::std::unique_ptr<BlockExpr> loop_body, + location_t locus, LoopLabel loop_label = LoopLabel::error(), ::std::vector<Attribute> outer_attribs = ::std::vector<Attribute>()) : - BaseLoopExpr(loop_body, ::std::move(loop_label), ::std::move(outer_attribs)), - pattern(loop_pattern), iterator_expr(iterator_expr) {} + BaseLoopExpr( + ::std::move(loop_body), locus, ::std::move(loop_label), ::std::move(outer_attribs)), + pattern(::std::move(loop_pattern)), iterator_expr(::std::move(iterator_expr)) {} // Copy constructor with clone ForLoopExpr(ForLoopExpr const& other) : @@ -3117,6 +3624,8 @@ namespace Rust { ForLoopExpr(ForLoopExpr&& other) = default; ForLoopExpr& operator=(ForLoopExpr&& other) = default; + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual ForLoopExpr* clone_expr_impl() const OVERRIDE { @@ -3144,6 +3653,8 @@ namespace Rust { IfLetExpr if_let_expr; } consequent_block;*/ + location_t locus; + public: /*virtual ~IfExpr() { delete condition; @@ -3152,14 +3663,16 @@ namespace Rust { ::std::string as_string() const; - IfExpr(Expr* condition, BlockExpr* if_block) : - ExprWithBlock(::std::vector<Attribute>()), condition(condition), if_block(if_block) {} + IfExpr(::std::unique_ptr<Expr> condition, ::std::unique_ptr<BlockExpr> if_block, + location_t locus) : + ExprWithBlock(::std::vector<Attribute>()), + condition(::std::move(condition)), if_block(::std::move(if_block)), locus(locus) {} // outer attributes are never allowed on IfExprs // Copy constructor with clone IfExpr(IfExpr const& other) : ExprWithBlock(other), condition(other.condition->clone_expr()), - if_block(other.if_block->clone_block_expr()) {} + if_block(other.if_block->clone_block_expr()), locus(other.locus) {} // Destructor - define here if required @@ -3168,6 +3681,7 @@ namespace Rust { ExprWithBlock::operator=(other); condition = other.condition->clone_expr(); if_block = other.if_block->clone_block_expr(); + locus = other.locus; return *this; } @@ -3185,6 +3699,16 @@ namespace Rust { * else ifs - i.e. not like a switch statement. TODO - is this a better approach? or * does it not parse correctly and have downsides? */ + location_t get_locus() const { + return locus; + } + + location_t get_locus_slow() const OVERRIDE { + return get_locus(); + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual IfExpr* clone_expr_impl() const OVERRIDE { @@ -3214,8 +3738,10 @@ namespace Rust { ::std::string as_string() const; - IfExprConseqElse(Expr* condition, BlockExpr* if_block, BlockExpr* else_block) : - IfExpr(condition, if_block), else_block(else_block) {} + IfExprConseqElse(::std::unique_ptr<Expr> condition, ::std::unique_ptr<BlockExpr> if_block, + ::std::unique_ptr<BlockExpr> else_block, location_t locus) : + IfExpr(::std::move(condition), ::std::move(if_block), locus), + else_block(::std::move(else_block)) {} // again, outer attributes not allowed // Copy constructor with clone @@ -3238,6 +3764,8 @@ namespace Rust { IfExprConseqElse(IfExprConseqElse&& other) = default; IfExprConseqElse& operator=(IfExprConseqElse&& other) = default; + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual IfExprConseqElse* clone_expr_impl() const OVERRIDE { @@ -3267,8 +3795,10 @@ namespace Rust { ::std::string as_string() const; - IfExprConseqIf(Expr* condition, BlockExpr* if_block, IfExpr* conseq_if_expr) : - IfExpr(condition, if_block), if_expr(conseq_if_expr) {} + IfExprConseqIf(::std::unique_ptr<Expr> condition, ::std::unique_ptr<BlockExpr> if_block, + ::std::unique_ptr<IfExpr> conseq_if_expr, location_t locus) : + IfExpr(::std::move(condition), ::std::move(if_block), locus), + if_expr(::std::move(conseq_if_expr)) {} // outer attributes not allowed // Copy constructor with clone @@ -3291,6 +3821,8 @@ namespace Rust { IfExprConseqIf(IfExprConseqIf&& other) = default; IfExprConseqIf& operator=(IfExprConseqIf&& other) = default; + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual IfExprConseqIf* clone_expr_impl() const OVERRIDE { @@ -3322,20 +3854,24 @@ namespace Rust { IfLetExpr* if_let_expr; } consequent_block;*/ + location_t locus; + public: ::std::string as_string() const; - IfLetExpr(::std::vector< ::std::unique_ptr<Pattern> > match_arm_patterns, Expr* value, - BlockExpr* if_block) : + IfLetExpr(::std::vector< ::std::unique_ptr<Pattern> > match_arm_patterns, + ::std::unique_ptr<Expr> value, ::std::unique_ptr<BlockExpr> if_block, + location_t locus) : ExprWithBlock(::std::vector<Attribute>()), - match_arm_patterns(::std::move(match_arm_patterns)), value(value), if_block(if_block) {} + match_arm_patterns(::std::move(match_arm_patterns)), value(::std::move(value)), + if_block(::std::move(if_block)), locus(locus) {} // outer attributes not allowed on if let exprs either // copy constructor with clone IfLetExpr(IfLetExpr const& other) : ExprWithBlock(other), /*match_arm_patterns(other.match_arm_patterns),*/ value(other.value->clone_expr()), - if_block(other.if_block->clone_block_expr()) { + if_block(other.if_block->clone_block_expr()), locus(other.locus) { // crappy vector unique pointer clone - TODO is there a better way of doing this? match_arm_patterns.reserve(other.match_arm_patterns.size()); @@ -3352,6 +3888,7 @@ namespace Rust { // match_arm_patterns = other.match_arm_patterns; value = other.value->clone_expr(); if_block = other.if_block->clone_block_expr(); + locus = other.locus; // crappy vector unique pointer clone - TODO is there a better way of doing this? match_arm_patterns.reserve(other.match_arm_patterns.size()); @@ -3372,6 +3909,16 @@ namespace Rust { return ::std::unique_ptr<IfLetExpr>(clone_if_let_expr_impl()); } + location_t get_locus() const { + return locus; + } + + location_t get_locus_slow() const OVERRIDE { + return get_locus(); + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual IfLetExpr* clone_expr_impl() const OVERRIDE { @@ -3401,8 +3948,11 @@ namespace Rust { ::std::string as_string() const; - IfExprConseqIfLet(Expr* condition, BlockExpr* if_block, IfLetExpr* conseq_if_let_expr) : - IfExpr(condition, if_block), if_let_expr(conseq_if_let_expr) {} + IfExprConseqIfLet(::std::unique_ptr<Expr> condition, + ::std::unique_ptr<BlockExpr> if_block, ::std::unique_ptr<IfLetExpr> conseq_if_let_expr, + location_t locus) : + IfExpr(::std::move(condition), ::std::move(if_block), locus), + if_let_expr(::std::move(conseq_if_let_expr)) {} // outer attributes not allowed // Copy constructor with clone @@ -3425,6 +3975,8 @@ namespace Rust { IfExprConseqIfLet(IfExprConseqIfLet&& other) = default; IfExprConseqIfLet& operator=(IfExprConseqIfLet&& other) = default; + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual IfExprConseqIfLet* clone_expr_impl() const OVERRIDE { @@ -3455,9 +4007,11 @@ namespace Rust { ::std::string as_string() const; IfLetExprConseqElse(::std::vector< ::std::unique_ptr<Pattern> > match_arm_patterns, - Expr* value, BlockExpr* if_block, BlockExpr* else_block) : - IfLetExpr(::std::move(match_arm_patterns), value, if_block), - else_block(else_block) {} + ::std::unique_ptr<Expr> value, ::std::unique_ptr<BlockExpr> if_block, + ::std::unique_ptr<BlockExpr> else_block, location_t locus) : + IfLetExpr( + ::std::move(match_arm_patterns), ::std::move(value), ::std::move(if_block), locus), + else_block(::std::move(else_block)) {} // outer attributes not allowed // copy constructor with clone @@ -3482,6 +4036,8 @@ namespace Rust { IfLetExprConseqElse(IfLetExprConseqElse&& other) = default; IfLetExprConseqElse& operator=(IfLetExprConseqElse&& other) = default; + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual IfLetExprConseqElse* clone_expr_impl() const OVERRIDE { @@ -3512,9 +4068,11 @@ namespace Rust { ::std::string as_string() const; IfLetExprConseqIf(::std::vector< ::std::unique_ptr<Pattern> > match_arm_patterns, - Expr* value, BlockExpr* if_block, IfExpr* if_expr) : - IfLetExpr(::std::move(match_arm_patterns), value, if_block), - if_expr(if_expr) {} + ::std::unique_ptr<Expr> value, ::std::unique_ptr<BlockExpr> if_block, + ::std::unique_ptr<IfExpr> if_expr, location_t locus) : + IfLetExpr( + ::std::move(match_arm_patterns), ::std::move(value), ::std::move(if_block), locus), + if_expr(::std::move(if_expr)) {} // again, outer attributes not allowed // copy constructor with clone @@ -3538,6 +4096,8 @@ namespace Rust { IfLetExprConseqIf(IfLetExprConseqIf&& other) = default; IfLetExprConseqIf& operator=(IfLetExprConseqIf&& other) = default; + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual IfLetExprConseqIf* clone_expr_impl() const OVERRIDE { @@ -3568,9 +4128,11 @@ namespace Rust { ::std::string as_string() const; IfLetExprConseqIfLet(::std::vector< ::std::unique_ptr<Pattern> > match_arm_patterns, - Expr* value, BlockExpr* if_block, IfLetExpr* if_let_expr) : - IfLetExpr(::std::move(match_arm_patterns), value, if_block), - if_let_expr(if_let_expr) {} + ::std::unique_ptr<Expr> value, ::std::unique_ptr<BlockExpr> if_block, + ::std::unique_ptr<IfLetExpr> if_let_expr, location_t locus) : + IfLetExpr( + ::std::move(match_arm_patterns), ::std::move(value), ::std::move(if_block), locus), + if_let_expr(::std::move(if_let_expr)) {} // outer attributes not allowed // copy constructor with clone @@ -3594,6 +4156,8 @@ namespace Rust { IfLetExprConseqIfLet(IfLetExprConseqIfLet&& other) = default; IfLetExprConseqIfLet& operator=(IfLetExprConseqIfLet&& other) = default; + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual IfLetExprConseqIfLet* clone_expr_impl() const OVERRIDE { @@ -3622,6 +4186,8 @@ namespace Rust { // Expr* match_arm_guard; // inlined from MatchArmGuard ::std::unique_ptr<Expr> guard_expr; + // TODO: should this store location data? + public: /*~MatchArm() { if (has_match_arm_guard) { @@ -3636,21 +4202,36 @@ namespace Rust { // Constructor for match arm with a guard expression MatchArm(::std::vector< ::std::unique_ptr<Pattern> > match_arm_patterns, - Expr* guard_expr = NULL, + ::std::unique_ptr<Expr> guard_expr = NULL, ::std::vector<Attribute> outer_attrs = ::std::vector<Attribute>()) : outer_attrs(::std::move(outer_attrs)), - match_arm_patterns(::std::move(match_arm_patterns)), guard_expr(guard_expr) {} + match_arm_patterns(::std::move(match_arm_patterns)), + guard_expr(::std::move(guard_expr)) {} // Copy constructor with clone MatchArm(MatchArm const& other) : - /*match_arm_patterns(other.match_arm_patterns),*/ outer_attrs(other.outer_attrs), - guard_expr(other.guard_expr->clone_expr()) { + /*match_arm_patterns(other.match_arm_patterns),*/ outer_attrs(other.outer_attrs) { + // guard to protect from null pointer dereference + if (other.guard_expr != NULL) { + guard_expr = other.guard_expr->clone_expr(); + } + + // DEBUG + fprintf( + stderr, "started copy-constructing match arm (outer attrs, guard expr done)\n"); + // crappy vector unique pointer clone - TODO is there a better way of doing this? match_arm_patterns.reserve(other.match_arm_patterns.size()); for (const auto& e : other.match_arm_patterns) { match_arm_patterns.push_back(e->clone_pattern()); + + // DEBUG + fprintf(stderr, "successfully pushed back a match arm pattern\n"); } + + // DEBUG + fprintf(stderr, "successfully copy-constructed match arm\n"); } ~MatchArm() = default; @@ -3684,6 +4265,8 @@ namespace Rust { static MatchArm create_error() { return MatchArm(::std::vector< ::std::unique_ptr<Pattern> >()); } + + ::std::string as_string() const; }; // Base "match case" for a match expression - abstract @@ -3703,8 +4286,15 @@ namespace Rust { // Unique pointer custom clone function ::std::unique_ptr<MatchCase> clone_match_case() const { + // DEBUG + fprintf(stderr, "about to call clone match case impl\n"); + return ::std::unique_ptr<MatchCase>(clone_match_case_impl()); } + + virtual ::std::string as_string() const; + + virtual void accept_vis(ASTVisitor& vis) = 0; }; // Block expression match case @@ -3712,17 +4302,22 @@ namespace Rust { // BlockExpr* block_expr; ::std::unique_ptr<BlockExpr> block_expr; + // TODO: should this store location data? + public: /*~MatchCaseBlockExpr() { delete block_expr; }*/ - MatchCaseBlockExpr(MatchArm arm, BlockExpr* block_expr) : - MatchCase(::std::move(arm)), block_expr(block_expr) {} + MatchCaseBlockExpr(MatchArm arm, ::std::unique_ptr<BlockExpr> block_expr) : + MatchCase(::std::move(arm)), block_expr(::std::move(block_expr)) {} // Copy constructor requires clone MatchCaseBlockExpr(MatchCaseBlockExpr const& other) : - MatchCase(other), block_expr(other.block_expr->clone_block_expr()) {} + MatchCase(other), block_expr(other.block_expr->clone_block_expr()) { + // DEBUG + fprintf(stderr, "successfully copy constructed match case expr\n"); + } // Destructor - define here if required @@ -3739,9 +4334,16 @@ namespace Rust { MatchCaseBlockExpr(MatchCaseBlockExpr&& other) = default; MatchCaseBlockExpr& operator=(MatchCaseBlockExpr&& other) = default; + ::std::string as_string() const; + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual MatchCaseBlockExpr* clone_match_case_impl() const OVERRIDE { + // DEBUG + fprintf(stderr, "about to copy construct match case block expr\n"); + return new MatchCaseBlockExpr(*this); } }; @@ -3751,16 +4353,22 @@ namespace Rust { // Expr* expr; ::std::unique_ptr<Expr> expr; + // TODO: should this store location data? + public: /*~MatchCaseExpr() { delete expr; }*/ - MatchCaseExpr(MatchArm arm, Expr* expr) : MatchCase(::std::move(arm)), expr(expr) {} + MatchCaseExpr(MatchArm arm, ::std::unique_ptr<Expr> expr) : + MatchCase(::std::move(arm)), expr(::std::move(expr)) {} // Copy constructor requires clone MatchCaseExpr(MatchCaseExpr const& other) : - MatchCase(other), expr(other.expr->clone_expr()) {} + MatchCase(other), expr(other.expr->clone_expr()) { + // DEBUG + fprintf(stderr, "successfully copy constructed match case expr\n"); + } // Destructor - define here if required @@ -3777,9 +4385,20 @@ namespace Rust { MatchCaseExpr(MatchCaseExpr&& other) = default; MatchCaseExpr& operator=(MatchCaseExpr&& other) = default; + ::std::string as_string() const; + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual MatchCaseExpr* clone_match_case_impl() const OVERRIDE { + // DEBUG + fprintf(stderr, "about to copy construct match case expr\n"); + if (expr == NULL) { + fprintf( + stderr, "warning: match case expr to be copy constructed has null expr!\n"); + } + return new MatchCaseExpr(*this); } }; @@ -3794,6 +4413,8 @@ namespace Rust { // MatchArms match_arms; ::std::vector< ::std::unique_ptr<MatchCase> > match_arms; // inlined from MatchArms + location_t locus; + public: /*~MatchExpr() { delete branch_value; @@ -3806,23 +4427,33 @@ namespace Rust { return !match_arms.empty(); } - MatchExpr(Expr* branch_value, ::std::vector< ::std::unique_ptr<MatchCase> > match_arms, - ::std::vector<Attribute> inner_attrs, ::std::vector<Attribute> outer_attrs) : + MatchExpr(::std::unique_ptr<Expr> branch_value, + ::std::vector< ::std::unique_ptr<MatchCase> > match_arms, + ::std::vector<Attribute> inner_attrs, ::std::vector<Attribute> outer_attrs, + location_t locus) : ExprWithBlock(::std::move(outer_attrs)), - branch_value(branch_value), inner_attrs(::std::move(inner_attrs)), - match_arms(::std::move(match_arms)) {} + branch_value(::std::move(branch_value)), inner_attrs(::std::move(inner_attrs)), + match_arms(::std::move(match_arms)), locus(locus) {} // Copy constructor requires clone due to unique_ptr MatchExpr(MatchExpr const& other) : ExprWithBlock(other), branch_value(other.branch_value->clone_expr()), /*match_arms(other.match_arms),*/ - inner_attrs(other.inner_attrs) { + inner_attrs(other.inner_attrs), locus(other.locus) { + fprintf(stderr, "copy constructor for matchexpr called - only match arm vector " + "copying after this\n"); + // crappy vector unique pointer clone - TODO is there a better way of doing this? match_arms.reserve(other.match_arms.size()); + fprintf(stderr, "match expr: successfully reserved size\n"); + for (const auto& e : other.match_arms) { match_arms.push_back(e->clone_match_case()); + fprintf(stderr, "match expr: successfully pushed back a match case\n"); } + + fprintf(stderr, "match expr: successfully pushed back all match cases\n"); } // Destructor - define here if required @@ -3834,6 +4465,7 @@ namespace Rust { // match_arms = other.match_arms; inner_attrs = other.inner_attrs; // outer_attrs = other.outer_attrs; + locus = other.locus; // crappy vector unique pointer clone - TODO is there a better way of doing this? match_arms.reserve(other.match_arms.size()); @@ -3849,6 +4481,16 @@ namespace Rust { MatchExpr(MatchExpr&& other) = default; MatchExpr& operator=(MatchExpr&& other) = default; + location_t get_locus() const { + return locus; + } + + location_t get_locus_slow() const OVERRIDE { + return get_locus(); + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual MatchExpr* clone_expr_impl() const OVERRIDE { @@ -3865,14 +4507,19 @@ namespace Rust { class AwaitExpr : public ExprWithoutBlock { ::std::unique_ptr<Expr> awaited_expr; + location_t locus; + public: // TODO: ensure outer attributes are actually allowed - AwaitExpr(Expr* awaited_expr, ::std::vector<Attribute> outer_attrs) : - ExprWithoutBlock(::std::move(outer_attrs)), awaited_expr(awaited_expr) {} + AwaitExpr(::std::unique_ptr<Expr> awaited_expr, ::std::vector<Attribute> outer_attrs, + location_t locus) : + ExprWithoutBlock(::std::move(outer_attrs)), + awaited_expr(::std::move(awaited_expr)), locus(locus) {} // copy constructor with clone AwaitExpr(AwaitExpr const& other) : - ExprWithoutBlock(other), awaited_expr(other.awaited_expr->clone_expr()) {} + ExprWithoutBlock(other), awaited_expr(other.awaited_expr->clone_expr()), + locus(other.locus) {} // destructor - define here if required @@ -3880,6 +4527,7 @@ namespace Rust { AwaitExpr& operator=(AwaitExpr const& other) { ExprWithoutBlock::operator=(other); awaited_expr = other.awaited_expr->clone_expr(); + locus = other.locus; return *this; } @@ -3890,6 +4538,16 @@ namespace Rust { ::std::string as_string() const; + location_t get_locus() const { + return locus; + } + + location_t get_locus_slow() const OVERRIDE { + return get_locus(); + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual AwaitExpr* clone_expr_without_block_impl() const OVERRIDE { @@ -3903,16 +4561,18 @@ namespace Rust { bool has_move; ::std::unique_ptr<BlockExpr> block_expr; + location_t locus; + public: - AsyncBlockExpr( - BlockExpr* block_expr, bool has_move, ::std::vector<Attribute> outer_attrs) : + AsyncBlockExpr(::std::unique_ptr<BlockExpr> block_expr, bool has_move, + ::std::vector<Attribute> outer_attrs, location_t locus) : ExprWithBlock(::std::move(outer_attrs)), - has_move(has_move), block_expr(block_expr) {} + has_move(has_move), block_expr(::std::move(block_expr)), locus(locus) {} // copy constructor with clone AsyncBlockExpr(AsyncBlockExpr const& other) : ExprWithBlock(other), has_move(other.has_move), - block_expr(other.block_expr->clone_block_expr()) {} + block_expr(other.block_expr->clone_block_expr()), locus(other.locus) {} // destructor - define if required @@ -3921,6 +4581,7 @@ namespace Rust { ExprWithBlock::operator=(other); has_move = other.has_move; block_expr = other.block_expr->clone_block_expr(); + locus = other.locus; return *this; } @@ -3931,6 +4592,16 @@ namespace Rust { ::std::string as_string() const; + location_t get_locus() const { + return locus; + } + + location_t get_locus_slow() const OVERRIDE { + return get_locus(); + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual AsyncBlockExpr* clone_expr_with_block_impl() const OVERRIDE { diff --git a/gcc/rust/test3/ast/rust-item.h b/gcc/rust/test3/ast/rust-item.h index fd04b55..c5154f5 100644 --- a/gcc/rust/test3/ast/rust-item.h +++ b/gcc/rust/test3/ast/rust-item.h @@ -17,20 +17,8 @@ namespace Rust { // class Pattern; class MacroInvocationSemi; - // TODO: remove - // typedef int Type; - // typedef ::std::vector<int> Generics; - // typedef ::std::string WhereClause; - // typedef ::std::vector<int> TypeParamBounds; - // typedef ::std::string Lifetime; - // typedef ::std::string LifetimeBounds; - // typedef ::std::string LifetimeParams; - // typedef Type FunctionReturnType; - // typedef Identifier AbiName; - // typedef Type TypePath; - // TODO: inline? - struct AbiName { + /*struct AbiName { ::std::string abi_name; // Technically is meant to be STRING_LITERAL or RAW_STRING_LITERAL @@ -44,7 +32,7 @@ namespace Rust { // Empty AbiName constructor AbiName() {} - }; + };*/ // A type generic parameter (as opposed to a lifetime generic parameter) class TypeParam : public GenericParam { @@ -62,6 +50,8 @@ namespace Rust { // Type type; ::std::unique_ptr<Type> type; + location_t locus; + public: // Returns whether the type of the type param has been specified. inline bool has_type() const { @@ -78,18 +68,20 @@ namespace Rust { return !outer_attr.is_empty(); } - TypeParam(Identifier type_representation, + TypeParam(Identifier type_representation, location_t locus = UNKNOWN_LOCATION, ::std::vector< ::std::unique_ptr<TypeParamBound> > type_param_bounds = ::std::vector< ::std::unique_ptr<TypeParamBound> >(), - Type* type = NULL, Attribute outer_attr = Attribute::create_empty()) : + ::std::unique_ptr<Type> type = NULL, Attribute outer_attr = Attribute::create_empty()) : outer_attr(::std::move(outer_attr)), type_representation(::std::move(type_representation)), - type_param_bounds(::std::move(type_param_bounds)), type(type) {} + type_param_bounds(::std::move(type_param_bounds)), type(::std::move(type)), + locus(locus) {} // Copy constructor uses clone TypeParam(TypeParam const& other) : outer_attr(other.outer_attr), type_representation(other.type_representation), - /*type_param_bounds(other.type_param_bounds),*/ type(other.type->clone_type()) { + /*type_param_bounds(other.type_param_bounds),*/ type(other.type->clone_type()), + locus(other.locus) { // crappy vector unique pointer clone - TODO is there a better way of doing this? type_param_bounds.reserve(other.type_param_bounds.size()); @@ -106,6 +98,7 @@ namespace Rust { // type_param_bounds = other.type_param_bounds; type = other.type->clone_type(); outer_attr = other.outer_attr; + locus = other.locus; // crappy vector unique pointer clone - TODO is there a better way of doing this? type_param_bounds.reserve(other.type_param_bounds.size()); @@ -123,6 +116,12 @@ namespace Rust { ::std::string as_string() const; + location_t get_locus() const { + return locus; + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Clone function implementation as (not pure) virtual method virtual TypeParam* clone_generic_param_impl() const { @@ -140,6 +139,10 @@ namespace Rust { return ::std::unique_ptr<WhereClauseItem>(clone_where_clause_item_impl()); } + virtual ::std::string as_string() const = 0; + + virtual void accept_vis(ASTVisitor& vis) = 0; + protected: // Clone function implementation as pure virtual method virtual WhereClauseItem* clone_where_clause_item_impl() const = 0; @@ -152,10 +155,16 @@ namespace Rust { // LifetimeBounds lifetime_bounds; ::std::vector<Lifetime> lifetime_bounds; // inlined lifetime bounds + // should this store location info? + public: LifetimeWhereClauseItem(Lifetime lifetime, ::std::vector<Lifetime> lifetime_bounds) : lifetime(::std::move(lifetime)), lifetime_bounds(::std::move(lifetime_bounds)) {} + ::std::string as_string() const; + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Clone function implementation as (not pure) virtual method virtual LifetimeWhereClauseItem* clone_where_clause_item_impl() const { @@ -176,6 +185,8 @@ namespace Rust { // TypeParamBounds type_param_bounds; ::std::vector< ::std::unique_ptr<TypeParamBound> > type_param_bounds; // inlined form + // should this store location info? + public: // Returns whether the item has ForLifetimes inline bool has_for_lifetimes() const { @@ -187,10 +198,12 @@ namespace Rust { return !type_param_bounds.empty(); } - TypeBoundWhereClauseItem(::std::vector<LifetimeParam> for_lifetimes, Type* bound_type, + TypeBoundWhereClauseItem(::std::vector<LifetimeParam> for_lifetimes, + ::std::unique_ptr<Type> bound_type, ::std::vector< ::std::unique_ptr<TypeParamBound> > type_param_bounds) : for_lifetimes(::std::move(for_lifetimes)), - bound_type(bound_type), type_param_bounds(::std::move(type_param_bounds)) {} + bound_type(::std::move(bound_type)), type_param_bounds(::std::move(type_param_bounds)) { + } // Copy constructor requires clone TypeBoundWhereClauseItem(TypeBoundWhereClauseItem const& other) : @@ -227,6 +240,10 @@ namespace Rust { TypeBoundWhereClauseItem(TypeBoundWhereClauseItem&& other) = default; TypeBoundWhereClauseItem& operator=(TypeBoundWhereClauseItem&& other) = default; + ::std::string as_string() const; + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Clone function implementation as (not pure) virtual method virtual TypeBoundWhereClauseItem* clone_where_clause_item_impl() const { @@ -240,6 +257,8 @@ namespace Rust { //::std::vector<WhereClauseItem> where_clause_items; ::std::vector< ::std::unique_ptr<WhereClauseItem> > where_clause_items; + // should this store location info? + public: WhereClause(::std::vector< ::std::unique_ptr<WhereClauseItem> > where_clause_items) : where_clause_items(::std::move(where_clause_items)) {} @@ -295,9 +314,12 @@ namespace Rust { // Type type; ::std::unique_ptr<Type> type; + location_t locus; + // Unrestricted constructor used for error state SelfParam(Lifetime lifetime, bool has_ref, bool is_mut, Type* type) : has_ref(has_ref), is_mut(is_mut), lifetime(::std::move(lifetime)), type(type) {} + // this is ok as no outside classes can ever call this public: // Returns whether the self-param has a type field. @@ -325,17 +347,19 @@ namespace Rust { } // Type-based self parameter (not ref, no lifetime) - SelfParam(Type* type, bool is_mut) : - has_ref(false), is_mut(is_mut), lifetime(Lifetime::error()), type(type) {} + SelfParam(::std::unique_ptr<Type> type, bool is_mut, location_t locus) : + has_ref(false), is_mut(is_mut), lifetime(Lifetime::error()), type(::std::move(type)), + locus(locus) {} // Lifetime-based self parameter (is ref, no type) - SelfParam(Lifetime lifetime, bool is_mut) : - /*type(NULL), */ has_ref(true), is_mut(is_mut), lifetime(::std::move(lifetime)) {} + SelfParam(Lifetime lifetime, bool is_mut, location_t locus) : + /*type(NULL), */ has_ref(true), is_mut(is_mut), lifetime(::std::move(lifetime)), + locus(locus) {} // Copy constructor requires clone SelfParam(SelfParam const& other) : has_ref(other.has_ref), is_mut(other.is_mut), lifetime(other.lifetime), - type(other.type->clone_type()) {} + type(other.type->clone_type()), locus(other.locus) {} // Destructor - define here if required @@ -345,6 +369,7 @@ namespace Rust { is_mut = other.is_mut; has_ref = other.has_ref; lifetime = other.lifetime; + locus = other.locus; return *this; } @@ -352,6 +377,12 @@ namespace Rust { // move constructors SelfParam(SelfParam&& other) = default; SelfParam& operator=(SelfParam&& other) = default; + + ::std::string as_string() const; + + location_t get_locus() const { + return locus; + } }; // Qualifiers for function, i.e. const, unsafe, extern etc. @@ -367,6 +398,8 @@ namespace Rust { ::std::string extern_abi; // e.g. extern "C" fn() -> i32 {} // TODO: maybe ensure that extern_abi only exists if extern exists? + // should this store location info? + public: // Constructor with no extern (and hence no extern abi) FunctionQualifiers(AsyncConstStatus const_status, bool has_unsafe) : @@ -399,13 +432,18 @@ namespace Rust { // Type type; ::std::unique_ptr<Type> type; + location_t locus; + public: - FunctionParam(Pattern* param_name, Type* param_type) : - param_name(param_name), type(param_type) {} + FunctionParam(::std::unique_ptr<Pattern> param_name, ::std::unique_ptr<Type> param_type, + location_t locus) : + param_name(::std::move(param_name)), + type(::std::move(param_type)), locus(locus) {} // Copy constructor uses clone FunctionParam(FunctionParam const& other) : - param_name(other.param_name->clone_pattern()), type(other.type->clone_type()) {} + param_name(other.param_name->clone_pattern()), type(other.type->clone_type()), + locus(other.locus) {} // Destructor - define here if required @@ -413,6 +451,7 @@ namespace Rust { FunctionParam& operator=(FunctionParam const& other) { param_name = other.param_name->clone_pattern(); type = other.type->clone_type(); + locus = other.locus; return *this; } @@ -428,15 +467,103 @@ namespace Rust { // Creates an error FunctionParam. static FunctionParam create_error() { - return FunctionParam(NULL, NULL); + return FunctionParam(NULL, NULL, UNKNOWN_LOCATION); } ::std::string as_string() const; + + location_t get_locus() const { + return locus; + } }; - // A method (function belonging to a type) - struct Method { + // Visibility of item - if the item has it, then it is some form of public + struct Visibility { + public: + enum PublicVisType { NONE, CRATE, SELF, SUPER, IN_PATH }; + private: + // bool is_pub; + + // if vis is public, one of these + PublicVisType public_vis_type; + + // Only assigned if public_vis_type is IN_PATH + SimplePath in_path; + + // should this store location info? + + public: + // Creates a Visibility - TODO make constructor protected or private? + Visibility(PublicVisType public_vis_type, SimplePath in_path) : + public_vis_type(public_vis_type), in_path(::std::move(in_path)) { + if (public_vis_type != IN_PATH && !in_path.is_empty()) { + // error - invalid state + + // just ignore path if vis type is not that + } + } + + // Returns whether visibility is in an error state. + inline bool is_error() const { + return public_vis_type == IN_PATH && in_path.is_empty(); + } + + // Creates an error visibility. + static Visibility create_error() { + return Visibility(IN_PATH, SimplePath::create_empty()); + } + + // Unique pointer custom clone function + /*::std::unique_ptr<Visibility> clone_visibility() const { + return ::std::unique_ptr<Visibility>(clone_visibility_impl()); + }*/ + + /* TODO: think of a way to only allow valid Visibility states - polymorphism is one + * idea but may be too resource-intensive. */ + + // Creates a public visibility with no further features/arguments. + static Visibility create_public() { + return Visibility(NONE, SimplePath::create_empty()); + } + + // Creates a public visibility with crate-relative paths or whatever. + static Visibility create_crate() { + return Visibility(CRATE, SimplePath::create_empty()); + } + + // Creates a public visibility with self-relative paths or whatever. + static Visibility create_self() { + return Visibility(SELF, SimplePath::create_empty()); + } + + // Creates a public visibility with parent module-relative paths or whatever. + static Visibility create_super() { + return Visibility(SUPER, SimplePath::create_empty()); + } + + // Creates a public visibility with a given path or whatever. + static Visibility create_in_path(SimplePath in_path) { + return Visibility(IN_PATH, ::std::move(in_path)); + } + + ::std::string as_string() const; + + protected: + // Clone function implementation - not currently virtual but may be if polymorphism used + /*virtual*/ Visibility* clone_visibility_impl() const { + return new Visibility(*this); + } + }; + + // A method (function belonging to a type) + class Method + : public InherentImplItem + , public TraitImplItem { + // moved from impl items for consistency + ::std::vector<Attribute> outer_attrs; + Visibility vis; + FunctionQualifiers qualifiers; Identifier method_name; @@ -460,7 +587,7 @@ namespace Rust { // BlockExpr* expr; ::std::unique_ptr<BlockExpr> expr; - // TODO: move visibility to method struct for consistency? + location_t locus; public: /*~Method() { @@ -476,7 +603,8 @@ namespace Rust { static Method create_error() { return Method("", FunctionQualifiers(FunctionQualifiers::NONE, true), ::std::vector< ::std::unique_ptr<GenericParam> >(), SelfParam::create_error(), - ::std::vector<FunctionParam>(), NULL, WhereClause::create_empty(), NULL); + ::std::vector<FunctionParam>(), NULL, WhereClause::create_empty(), NULL, + Visibility::create_error(), ::std::vector<Attribute>()); } // Returns whether the method has generic parameters. @@ -499,25 +627,34 @@ namespace Rust { return !where_clause.is_empty(); } + // Returns whether method has a non-default visibility. + inline bool has_visibility() const { + return !vis.is_error(); + } + // Mega-constructor with all possible fields Method(Identifier method_name, FunctionQualifiers qualifiers, ::std::vector< ::std::unique_ptr<GenericParam> > generic_params, SelfParam self_param, - ::std::vector<FunctionParam> function_params, Type* return_type, - WhereClause where_clause, BlockExpr* function_body) : - qualifiers(::std::move(qualifiers)), + ::std::vector<FunctionParam> function_params, ::std::unique_ptr<Type> return_type, + WhereClause where_clause, ::std::unique_ptr<BlockExpr> function_body, Visibility vis, + ::std::vector<Attribute> outer_attrs, location_t locus = UNKNOWN_LOCATION) : + outer_attrs(::std::move(outer_attrs)), + vis(::std::move(vis)), qualifiers(::std::move(qualifiers)), method_name(::std::move(method_name)), generic_params(::std::move(generic_params)), self_param(::std::move(self_param)), function_params(::std::move(function_params)), - return_type(return_type), where_clause(::std::move(where_clause)), expr(function_body) { - } + return_type(::std::move(return_type)), where_clause(::std::move(where_clause)), + expr(::std::move(function_body)), locus(locus) {} // TODO: add constructor with less fields // Copy constructor with clone Method(Method const& other) : - qualifiers(other.qualifiers), method_name(other.method_name), + outer_attrs(other.outer_attrs), vis(other.vis), qualifiers(other.qualifiers), + method_name(other.method_name), /*generic_params(other.generic_params),*/ self_param(other.self_param), function_params(other.function_params), return_type(other.return_type->clone_type()), - where_clause(other.where_clause), expr(other.expr->clone_block_expr()) { + where_clause(other.where_clause), expr(other.expr->clone_block_expr()), + locus(other.locus) { // crappy vector unique pointer clone - TODO is there a better way of doing this? generic_params.reserve(other.generic_params.size()); @@ -526,11 +663,13 @@ namespace Rust { } } - ~Method() = default; + //~Method() = default; // Overloaded assignment operator to clone Method& operator=(Method const& other) { method_name = other.method_name; + outer_attrs = other.outer_attrs; + vis = other.vis; qualifiers = other.qualifiers; // generic_params = other.generic_params; self_param = other.self_param; @@ -538,6 +677,7 @@ namespace Rust { return_type = other.return_type->clone_type(); where_clause = other.where_clause; expr = other.expr->clone_block_expr(); + locus = other.locus; // crappy vector unique pointer clone - TODO is there a better way of doing this? generic_params.reserve(other.generic_params.size()); @@ -552,82 +692,20 @@ namespace Rust { // move constructors Method(Method&& other) = default; Method& operator=(Method&& other) = default; - }; - - // Visibility of item - if the item has it, then it is some form of public - struct Visibility { - public: - enum PublicVisType { NONE, CRATE, SELF, SUPER, IN_PATH }; - - private: - // bool is_pub; - - // if vis is public, one of these - PublicVisType public_vis_type; - - // Only assigned if public_vis_type is IN_PATH - SimplePath in_path; - public: - // Creates a Visibility - TODO make constructor protected or private? - Visibility(PublicVisType public_vis_type, SimplePath in_path) : - public_vis_type(public_vis_type), in_path(::std::move(in_path)) { - if (public_vis_type != IN_PATH && !in_path.is_empty()) { - // error - invalid state - - // just ignore path if vis type is not that - } - } - - // Returns whether visibility is in an error state. - inline bool is_error() const { - return public_vis_type == IN_PATH && in_path.is_empty(); - } - - // Creates an error visibility. - static Visibility create_error() { - return Visibility(IN_PATH, SimplePath::create_empty()); - } - - // Unique pointer custom clone function - /*::std::unique_ptr<Visibility> clone_visibility() const { - return ::std::unique_ptr<Visibility>(clone_visibility_impl()); - }*/ - - /* TODO: think of a way to only allow valid Visibility states - polymorphism is one - * idea but may be too resource-intensive. */ - - // Creates a public visibility with no further features/arguments. - static Visibility create_public() { - return Visibility(NONE, SimplePath::create_empty()); - } - - // Creates a public visibility with crate-relative paths or whatever. - static Visibility create_crate() { - return Visibility(CRATE, SimplePath::create_empty()); - } + ::std::string as_string() const; - // Creates a public visibility with self-relative paths or whatever. - static Visibility create_self() { - return Visibility(SELF, SimplePath::create_empty()); - } + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; - // Creates a public visibility with parent module-relative paths or whatever. - static Visibility create_super() { - return Visibility(SUPER, SimplePath::create_empty()); - } - - // Creates a public visibility with a given path or whatever. - static Visibility create_in_path(SimplePath in_path) { - return Visibility(IN_PATH, ::std::move(in_path)); + protected: + // Use covariance to implement clone function as returning this object rather than base + virtual Method* clone_inherent_impl_item_impl() const OVERRIDE { + return new Method(*this); } - ::std::string as_string() const; - - protected: - // Clone function implementation - not currently virtual but may be if polymorphism used - /*virtual*/ Visibility* clone_visibility_impl() const { - return new Visibility(*this); + // Use covariance to implement clone function as returning this object rather than base + virtual Method* clone_trait_impl_item_impl() const OVERRIDE { + return new Method(*this); } }; @@ -671,14 +749,23 @@ namespace Rust { // Rust module item - abstract base class class Module : public VisItem { - // TODO: module name? (identifier) - why don't I have this? + Identifier module_name; + + location_t locus; + protected: - // Outer attributes constructor - Module(Visibility visibility, ::std::vector<Attribute> outer_attrs) : - VisItem(::std::move(visibility), ::std::move(outer_attrs)) {} + // Protected constructor + Module(Identifier module_name, Visibility visibility, location_t locus, + ::std::vector<Attribute> outer_attrs = ::std::vector<Attribute>()) : + VisItem(::std::move(visibility), ::std::move(outer_attrs)), + module_name(module_name), locus(locus) {} - // No outer attributes constructor - Module(Visibility visibility) : VisItem(::std::move(visibility)) {} + public: + virtual ::std::string as_string() const; + + location_t get_locus() const { + return locus; + } }; // Module with a body, defined in file @@ -703,12 +790,13 @@ namespace Rust { } // Full constructor - ModuleBodied(::std::vector< ::std::unique_ptr<Item> > items - = ::std::vector< ::std::unique_ptr<Item> >(), + ModuleBodied(Identifier name, location_t locus, + ::std::vector< ::std::unique_ptr<Item> > items + = ::std::vector< ::std::unique_ptr<Item> >(), Visibility visibility = Visibility::create_error(), ::std::vector<Attribute> inner_attrs = ::std::vector<Attribute>(), ::std::vector<Attribute> outer_attrs = ::std::vector<Attribute>()) : - Module(::std::move(visibility), ::std::move(outer_attrs)), + Module(::std::move(name), ::std::move(visibility), locus, ::std::move(outer_attrs)), inner_attrs(::std::move(inner_attrs)), items(::std::move(items)) {} // Copy constructor with vector clone @@ -740,6 +828,11 @@ namespace Rust { ModuleBodied(ModuleBodied&& other) = default; ModuleBodied& operator=(ModuleBodied&& other) = default; + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + + // Override that runs the function recursively on all items contained within the module. + virtual void add_crate_name(::std::vector< ::std::string>& names) const OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual ModuleBodied* clone_item_impl() const OVERRIDE { @@ -758,8 +851,11 @@ namespace Rust { ::std::string as_string() const; // Full constructor - ModuleNoBody(Visibility visibility, ::std::vector<Attribute> outer_attrs) : - Module(::std::move(visibility), ::std::move(outer_attrs)) {} + ModuleNoBody(Identifier name, Visibility visibility, ::std::vector<Attribute> outer_attrs, + location_t locus) : + Module(::std::move(name), ::std::move(visibility), locus, ::std::move(outer_attrs)) {} + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; protected: // Use covariance to implement clone function as returning this object rather than base @@ -782,6 +878,8 @@ namespace Rust { // this is either an identifier or "_", with _ parsed to string ::std::string as_clause_name; + location_t locus; + /* e.g. "extern crate foo as _" "extern crate foo" @@ -801,10 +899,22 @@ namespace Rust { // Constructor ExternCrate(::std::string referenced_crate, Visibility visibility, - ::std::vector<Attribute> outer_attrs, ::std::string as_clause_name = ::std::string()) : + ::std::vector<Attribute> outer_attrs, location_t locus, + ::std::string as_clause_name = ::std::string()) : VisItem(::std::move(visibility), ::std::move(outer_attrs)), referenced_crate(::std::move(referenced_crate)), - as_clause_name(::std::move(as_clause_name)) {} + as_clause_name(::std::move(as_clause_name)), locus(locus) {} + + location_t get_locus() const { + return locus; + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + + // Override that adds extern crate name in decl to passed list of names. + virtual void add_crate_name(::std::vector< ::std::string>& names) const OVERRIDE { + names.push_back(referenced_crate); + } protected: // Use covariance to implement clone function as returning this object rather than base @@ -820,6 +930,8 @@ namespace Rust { // The path-ish thing referred to in a use declaration - abstract base class class UseTree { + location_t locus; + public: virtual ~UseTree() {} @@ -830,9 +942,17 @@ namespace Rust { virtual ::std::string as_string() const = 0; + location_t get_locus() const { + return locus; + } + + virtual void accept_vis(ASTVisitor& vis) = 0; + protected: // Clone function implementation as pure virtual method virtual UseTree* clone_use_tree_impl() const = 0; + + UseTree(location_t locus) : locus(locus) {} }; // Use tree with a glob (wildcard) operator @@ -845,8 +965,8 @@ namespace Rust { SimplePath path; public: - UseTreeGlob(PathType glob_type, SimplePath path) : - glob_type(glob_type), path(::std::move(path)) {} + UseTreeGlob(PathType glob_type, SimplePath path, location_t locus) : + UseTree(locus), glob_type(glob_type), path(::std::move(path)) {} // Returns whether has path. Should be made redundant by PathType PATH_PREFIXED. inline bool has_path() const { @@ -855,6 +975,8 @@ namespace Rust { ::std::string as_string() const; + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + // TODO: find way to ensure only PATH_PREFIXED glob_type has path - factory methods? protected: // Use covariance to implement clone function as returning this object rather than base @@ -876,12 +998,13 @@ namespace Rust { public: UseTreeList(PathType path_type, SimplePath path, - ::std::vector< ::std::unique_ptr<UseTree> > trees) : - path_type(path_type), - path(::std::move(path)), trees(::std::move(trees)) {} + ::std::vector< ::std::unique_ptr<UseTree> > trees, location_t locus) : + UseTree(locus), + path_type(path_type), path(::std::move(path)), trees(::std::move(trees)) {} // copy constructor with vector clone - UseTreeList(UseTreeList const& other) : path_type(other.path_type), path(other.path) { + UseTreeList(UseTreeList const& other) : + UseTree(other), path_type(other.path_type), path(other.path) { // crappy vector unique pointer clone - TODO is there a better way of doing this? trees.reserve(other.trees.size()); @@ -892,6 +1015,7 @@ namespace Rust { // overloaded assignment operator with vector clone UseTreeList& operator=(UseTreeList const& other) { + UseTree::operator=(other); path_type = other.path_type; path = other.path; @@ -921,6 +1045,8 @@ namespace Rust { ::std::string as_string() const; + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + // TODO: find way to ensure only PATH_PREFIXED path_type has path - factory methods? protected: // Use covariance to implement clone function as returning this object rather than base @@ -941,10 +1067,10 @@ namespace Rust { Identifier identifier; // only if NewBindType is IDENTIFIER public: - UseTreeRebind( - NewBindType bind_type, SimplePath path, Identifier identifier = ::std::string()) : - path(::std::move(path)), - bind_type(bind_type), identifier(::std::move(identifier)) {} + UseTreeRebind(NewBindType bind_type, SimplePath path, location_t locus, + Identifier identifier = ::std::string()) : + UseTree(locus), + path(::std::move(path)), bind_type(bind_type), identifier(::std::move(identifier)) {} // Returns whether has path (this should always be true). inline bool has_path() const { @@ -958,6 +1084,8 @@ namespace Rust { ::std::string as_string() const; + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + // TODO: find way to ensure only PATH_PREFIXED path_type has path - factory methods? protected: // Use covariance to implement clone function as returning this object rather than base @@ -970,17 +1098,19 @@ namespace Rust { class UseDeclaration : public VisItem { ::std::unique_ptr<UseTree> use_tree; + location_t locus; + public: ::std::string as_string() const; - UseDeclaration( - UseTree* use_tree, Visibility visibility, ::std::vector<Attribute> outer_attrs) : + UseDeclaration(::std::unique_ptr<UseTree> use_tree, Visibility visibility, + ::std::vector<Attribute> outer_attrs, location_t locus) : VisItem(::std::move(visibility), ::std::move(outer_attrs)), - use_tree(use_tree) {} + use_tree(::std::move(use_tree)), locus(locus) {} // Copy constructor with clone UseDeclaration(UseDeclaration const& other) : - VisItem(other), use_tree(other.use_tree->clone_use_tree()) {} + VisItem(other), use_tree(other.use_tree->clone_use_tree()), locus(other.locus) {} // Destructor - define here if required @@ -990,6 +1120,7 @@ namespace Rust { use_tree = other.use_tree->clone_use_tree(); // visibility = other.visibility->clone_visibility(); // outer_attrs = other.outer_attrs; + locus = other.locus; return *this; } @@ -998,6 +1129,12 @@ namespace Rust { UseDeclaration(UseDeclaration&& other) = default; UseDeclaration& operator=(UseDeclaration&& other) = default; + location_t get_locus() const { + return locus; + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual UseDeclaration* clone_item_impl() const OVERRIDE { @@ -1016,7 +1153,10 @@ namespace Rust { };*/ // Rust function declaration AST node - class Function : public VisItem { + class Function + : public VisItem + , public InherentImplItem + , public TraitImplItem { FunctionQualifiers qualifiers; Identifier function_name; @@ -1039,6 +1179,8 @@ namespace Rust { // BlockExpr* function_body; ::std::unique_ptr<BlockExpr> function_body; + location_t locus; + public: /*~Function() { delete function_body; @@ -1068,14 +1210,15 @@ namespace Rust { // Mega-constructor with all possible fields Function(Identifier function_name, FunctionQualifiers qualifiers, ::std::vector< ::std::unique_ptr<GenericParam> > generic_params, - ::std::vector<FunctionParam> function_params, Type* return_type, - WhereClause where_clause, BlockExpr* function_body, Visibility vis, - ::std::vector<Attribute> outer_attrs) : + ::std::vector<FunctionParam> function_params, ::std::unique_ptr<Type> return_type, + WhereClause where_clause, ::std::unique_ptr<BlockExpr> function_body, Visibility vis, + ::std::vector<Attribute> outer_attrs, location_t locus) : VisItem(::std::move(vis), ::std::move(outer_attrs)), qualifiers(::std::move(qualifiers)), function_name(::std::move(function_name)), generic_params(::std::move(generic_params)), - function_params(::std::move(function_params)), return_type(return_type), - where_clause(::std::move(where_clause)), function_body(function_body) {} + function_params(::std::move(function_params)), return_type(::std::move(return_type)), + where_clause(::std::move(where_clause)), function_body(::std::move(function_body)), + locus(locus) {} // TODO: add constructor with less fields @@ -1084,7 +1227,7 @@ namespace Rust { VisItem(other), qualifiers(other.qualifiers), function_name(other.function_name), /*generic_params(other.generic_params),*/ function_params(other.function_params), return_type(other.return_type->clone_type()), where_clause(other.where_clause), - function_body(other.function_body->clone_block_expr()) { + function_body(other.function_body->clone_block_expr()), locus(other.locus) { // crappy vector unique pointer clone - TODO is there a better way of doing this? generic_params.reserve(other.generic_params.size()); @@ -1107,6 +1250,7 @@ namespace Rust { function_body = other.function_body->clone_block_expr(); // visibility = other.visibility->clone_visibility(); // outer_attrs = other.outer_attrs; + locus = other.locus; // crappy vector unique pointer clone - TODO is there a better way of doing this? generic_params.reserve(other.generic_params.size()); @@ -1122,6 +1266,12 @@ namespace Rust { Function(Function&& other) = default; Function& operator=(Function&& other) = default; + location_t get_locus() const { + return locus; + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual Function* clone_item_impl() const OVERRIDE { @@ -1129,13 +1279,25 @@ namespace Rust { } // Use covariance to implement clone function as returning this object rather than base + virtual Function* clone_inherent_impl_item_impl() const OVERRIDE { + return new Function(*this); + } + + // Use covariance to implement clone function as returning this object rather than base + virtual Function* clone_trait_impl_item_impl() const OVERRIDE { + return new Function(*this); + } + + // Use covariance to implement clone function as returning this object rather than base /*virtual Function* clone_statement_impl() const OVERRIDE { return new Function(*this); }*/ }; // Rust type alias (i.e. typedef) AST node - class TypeAlias : public VisItem { + class TypeAlias + : public VisItem + , public TraitImplItem { Identifier new_type_name; // bool has_generics; @@ -1148,6 +1310,8 @@ namespace Rust { // Type exiting_type; ::std::unique_ptr<Type> existing_type; + location_t locus; + public: ::std::string as_string() const; @@ -1164,17 +1328,19 @@ namespace Rust { // Mega-constructor with all possible fields TypeAlias(Identifier new_type_name, ::std::vector< ::std::unique_ptr<GenericParam> > generic_params, - WhereClause where_clause, Type* existing_type, Visibility vis, - ::std::vector<Attribute> outer_attrs) : + WhereClause where_clause, ::std::unique_ptr<Type> existing_type, Visibility vis, + ::std::vector<Attribute> outer_attrs, location_t locus) : VisItem(::std::move(vis), ::std::move(outer_attrs)), new_type_name(::std::move(new_type_name)), generic_params(::std::move(generic_params)), - where_clause(::std::move(where_clause)), existing_type(existing_type) {} + where_clause(::std::move(where_clause)), existing_type(::std::move(existing_type)), + locus(locus) {} // Copy constructor TypeAlias(TypeAlias const& other) : VisItem(other), new_type_name(other.new_type_name), /*generic_params(other.generic_params),*/ - where_clause(other.where_clause), existing_type(other.existing_type->clone_type()) { + where_clause(other.where_clause), existing_type(other.existing_type->clone_type()), + locus(other.locus) { // crappy vector unique pointer clone - TODO is there a better way of doing this? generic_params.reserve(other.generic_params.size()); @@ -1194,6 +1360,7 @@ namespace Rust { existing_type = other.existing_type->clone_type(); // visibility = other.visibility->clone_visibility(); // outer_attrs = other.outer_attrs; + locus = other.locus; // crappy vector unique pointer clone - TODO is there a better way of doing this? generic_params.reserve(other.generic_params.size()); @@ -1209,6 +1376,12 @@ namespace Rust { TypeAlias(TypeAlias&& other) = default; TypeAlias& operator=(TypeAlias&& other) = default; + location_t get_locus() const { + return locus; + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual TypeAlias* clone_item_impl() const OVERRIDE { @@ -1216,6 +1389,11 @@ namespace Rust { } // Use covariance to implement clone function as returning this object rather than base + virtual TypeAlias* clone_trait_impl_item_impl() const OVERRIDE { + return new TypeAlias(*this); + } + + // Use covariance to implement clone function as returning this object rather than base /*virtual TypeAlias* clone_statement_impl() const OVERRIDE { return new TypeAlias(*this); }*/ @@ -1224,6 +1402,7 @@ namespace Rust { // Rust base struct declaration AST node - abstract base class class Struct : public VisItem { protected: + // protected to enable access by derived classes - allows better as_string Identifier struct_name; // bool has_generics; @@ -1233,6 +1412,8 @@ namespace Rust { // bool has_where_clause; WhereClause where_clause; + location_t locus; + public: // Returns whether struct has generic parameters. inline bool has_generics() const { @@ -1244,18 +1425,23 @@ namespace Rust { return !where_clause.is_empty(); } + location_t get_locus() const { + return locus; + } + protected: Struct(Identifier struct_name, ::std::vector< ::std::unique_ptr<GenericParam> > generic_params, - WhereClause where_clause, Visibility vis, + WhereClause where_clause, Visibility vis, location_t locus, ::std::vector<Attribute> outer_attrs = ::std::vector<Attribute>()) : VisItem(::std::move(vis), ::std::move(outer_attrs)), struct_name(::std::move(struct_name)), generic_params(::std::move(generic_params)), - where_clause(::std::move(where_clause)) {} + where_clause(::std::move(where_clause)), locus(locus) {} // Copy constructor with vector clone Struct(Struct const& other) : - VisItem(other), struct_name(other.struct_name), where_clause(other.where_clause) { + VisItem(other), struct_name(other.struct_name), where_clause(other.where_clause), + locus(other.locus) { // crappy vector unique pointer clone - TODO is there a better way of doing this? generic_params.reserve(other.generic_params.size()); @@ -1269,6 +1455,7 @@ namespace Rust { VisItem::operator=(other); struct_name = other.struct_name; where_clause = other.where_clause; + locus = other.locus; // crappy vector unique pointer clone - TODO is there a better way of doing this? generic_params.reserve(other.generic_params.size()); @@ -1287,6 +1474,7 @@ namespace Rust { // A single field in a struct struct StructField { + private: // bool has_outer_attributes; ::std::vector<Attribute> outer_attrs; @@ -1297,6 +1485,8 @@ namespace Rust { // Type field_type; ::std::unique_ptr<Type> field_type; + // should this store location info? + public: // Returns whether struct field has any outer attributes. inline bool has_outer_attributes() const { @@ -1308,11 +1498,11 @@ namespace Rust { return !visibility.is_error(); } - StructField(Identifier field_name, Type* field_type, Visibility vis, + StructField(Identifier field_name, ::std::unique_ptr<Type> field_type, Visibility vis, ::std::vector<Attribute> outer_attrs = ::std::vector<Attribute>()) : outer_attrs(::std::move(outer_attrs)), visibility(::std::move(vis)), field_name(::std::move(field_name)), - field_type(field_type) {} + field_type(::std::move(field_type)) {} // Copy constructor StructField(StructField const& other) : @@ -1345,6 +1535,8 @@ namespace Rust { static StructField create_error() { return StructField(::std::string(""), NULL, Visibility::create_error()); } + + ::std::string as_string() const; }; // Rust struct declaration with true struct type AST node @@ -1359,17 +1551,18 @@ namespace Rust { StructStruct(::std::vector<StructField> fields, Identifier struct_name, ::std::vector< ::std::unique_ptr<GenericParam> > generic_params, WhereClause where_clause, bool is_unit, Visibility vis, - ::std::vector<Attribute> outer_attrs) : + ::std::vector<Attribute> outer_attrs, location_t locus) : Struct(::std::move(struct_name), ::std::move(generic_params), ::std::move(where_clause), - ::std::move(vis), ::std::move(outer_attrs)), + ::std::move(vis), locus, ::std::move(outer_attrs)), fields(::std::move(fields)), is_unit(is_unit) {} // Unit struct constructor StructStruct(Identifier struct_name, ::std::vector< ::std::unique_ptr<GenericParam> > generic_params, - WhereClause where_clause, Visibility vis, ::std::vector<Attribute> outer_attrs) : + WhereClause where_clause, Visibility vis, ::std::vector<Attribute> outer_attrs, + location_t locus) : Struct(::std::move(struct_name), ::std::move(generic_params), ::std::move(where_clause), - ::std::move(vis), ::std::move(outer_attrs)), + ::std::move(vis), locus, ::std::move(outer_attrs)), is_unit(true) {} // TODO: can a unit struct have generic fields? assuming yes for now. @@ -1379,6 +1572,8 @@ namespace Rust { return is_unit; } + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual StructStruct* clone_item_impl() const OVERRIDE { @@ -1403,6 +1598,8 @@ namespace Rust { // Type field_type; ::std::unique_ptr<Type> field_type; + // should this store location info? + public: // Returns whether tuple field has outer attributes. inline bool has_outer_attributes() const { @@ -1415,10 +1612,10 @@ namespace Rust { } // Complete constructor - TupleField(Type* field_type, Visibility vis, + TupleField(::std::unique_ptr<Type> field_type, Visibility vis, ::std::vector<Attribute> outer_attrs = ::std::vector<Attribute>()) : outer_attrs(::std::move(outer_attrs)), - visibility(::std::move(vis)), field_type(field_type) {} + visibility(::std::move(vis)), field_type(::std::move(field_type)) {} // Copy constructor with clone TupleField(TupleField const& other) : @@ -1449,6 +1646,8 @@ namespace Rust { static TupleField create_error() { return TupleField(NULL, Visibility::create_error()); } + + ::std::string as_string() const; }; // Rust tuple declared using struct keyword AST node @@ -1461,11 +1660,14 @@ namespace Rust { // Mega-constructor with all possible fields TupleStruct(::std::vector<TupleField> fields, Identifier struct_name, ::std::vector< ::std::unique_ptr<GenericParam> > generic_params, - WhereClause where_clause, Visibility vis, ::std::vector<Attribute> outer_attrs) : + WhereClause where_clause, Visibility vis, ::std::vector<Attribute> outer_attrs, + location_t locus) : Struct(::std::move(struct_name), ::std::move(generic_params), ::std::move(where_clause), - ::std::move(vis), ::std::move(outer_attrs)), + ::std::move(vis), locus, ::std::move(outer_attrs)), fields(::std::move(fields)) {} + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual TupleStruct* clone_item_impl() const OVERRIDE { @@ -1485,6 +1687,8 @@ namespace Rust { Identifier variant_name; + location_t locus; + public: virtual ~EnumItem() {} @@ -1493,14 +1697,21 @@ namespace Rust { return !outer_attrs.empty(); } - EnumItem(Identifier variant_name, ::std::vector<Attribute> outer_attrs) : - outer_attrs(::std::move(outer_attrs)), variant_name(::std::move(variant_name)) {} + EnumItem( + Identifier variant_name, ::std::vector<Attribute> outer_attrs, location_t locus) : + outer_attrs(::std::move(outer_attrs)), + variant_name(::std::move(variant_name)), locus(locus) {} // Unique pointer custom clone function ::std::unique_ptr<EnumItem> clone_enum_item() const { return ::std::unique_ptr<EnumItem>(clone_enum_item_impl()); } + virtual ::std::string as_string() const; + + // not pure virtual as not abstract + virtual void accept_vis(ASTVisitor& vis); + protected: // Clone function implementation as (not pure) virtual method virtual EnumItem* clone_enum_item_impl() const { @@ -1520,10 +1731,14 @@ namespace Rust { } EnumItemTuple(Identifier variant_name, ::std::vector<TupleField> tuple_fields, - ::std::vector<Attribute> outer_attrs) : - EnumItem(::std::move(variant_name), ::std::move(outer_attrs)), + ::std::vector<Attribute> outer_attrs, location_t locus) : + EnumItem(::std::move(variant_name), ::std::move(outer_attrs), locus), tuple_fields(::std::move(tuple_fields)) {} + ::std::string as_string() const; + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Clone function implementation as (not pure) virtual method virtual EnumItemTuple* clone_enum_item_impl() const { @@ -1543,10 +1758,14 @@ namespace Rust { } EnumItemStruct(Identifier variant_name, ::std::vector<StructField> struct_fields, - ::std::vector<Attribute> outer_attrs) : - EnumItem(::std::move(variant_name), ::std::move(outer_attrs)), + ::std::vector<Attribute> outer_attrs, location_t locus) : + EnumItem(::std::move(variant_name), ::std::move(outer_attrs), locus), struct_fields(::std::move(struct_fields)) {} + ::std::string as_string() const; + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Clone function implementation as (not pure) virtual method virtual EnumItemStruct* clone_enum_item_impl() const { @@ -1564,10 +1783,10 @@ namespace Rust { delete expression; }*/ - EnumItemDiscriminant( - Identifier variant_name, Expr* expr, ::std::vector<Attribute> outer_attrs) : - EnumItem(::std::move(variant_name), ::std::move(outer_attrs)), - expression(expr) {} + EnumItemDiscriminant(Identifier variant_name, ::std::unique_ptr<Expr> expr, + ::std::vector<Attribute> outer_attrs, location_t locus) : + EnumItem(::std::move(variant_name), ::std::move(outer_attrs), locus), + expression(::std::move(expr)) {} // Copy constructor with clone EnumItemDiscriminant(EnumItemDiscriminant const& other) : @@ -1589,6 +1808,10 @@ namespace Rust { EnumItemDiscriminant(EnumItemDiscriminant&& other) = default; EnumItemDiscriminant& operator=(EnumItemDiscriminant&& other) = default; + ::std::string as_string() const; + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Clone function implementation as (not pure) virtual method virtual EnumItemDiscriminant* clone_enum_item_impl() const { @@ -1609,6 +1832,8 @@ namespace Rust { ::std::vector< ::std::unique_ptr<EnumItem> > items; + location_t locus; + public: ::std::string as_string() const; @@ -1632,16 +1857,17 @@ namespace Rust { Enum(Identifier enum_name, Visibility vis, ::std::vector< ::std::unique_ptr<GenericParam> > generic_params, WhereClause where_clause, ::std::vector< ::std::unique_ptr<EnumItem> > items, - ::std::vector<Attribute> outer_attrs) : + ::std::vector<Attribute> outer_attrs, location_t locus) : VisItem(::std::move(vis), ::std::move(outer_attrs)), enum_name(::std::move(enum_name)), generic_params(::std::move(generic_params)), - where_clause(::std::move(where_clause)), items(::std::move(items)) {} + where_clause(::std::move(where_clause)), items(::std::move(items)), locus(locus) {} // TODO: constructor with less arguments // Copy constructor with vector clone Enum(Enum const& other) : - VisItem(other), enum_name(other.enum_name), where_clause(other.where_clause) { + VisItem(other), enum_name(other.enum_name), where_clause(other.where_clause), + locus(other.locus) { // crappy vector unique pointer clone - TODO is there a better way of doing this? generic_params.reserve(other.generic_params.size()); @@ -1662,6 +1888,7 @@ namespace Rust { VisItem::operator=(other); enum_name = other.enum_name; where_clause = other.where_clause; + locus = other.locus; // crappy vector unique pointer clone - TODO is there a better way of doing this? generic_params.reserve(other.generic_params.size()); @@ -1684,6 +1911,12 @@ namespace Rust { Enum(Enum&& other) = default; Enum& operator=(Enum&& other) = default; + location_t get_locus() const { + return locus; + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual Enum* clone_item_impl() const OVERRIDE { @@ -1709,6 +1942,8 @@ namespace Rust { ::std::vector<StructField> variants; + location_t locus; + public: ::std::string as_string() const; @@ -1725,15 +1960,16 @@ namespace Rust { Union(Identifier union_name, Visibility vis, ::std::vector< ::std::unique_ptr<GenericParam> > generic_params, WhereClause where_clause, ::std::vector<StructField> variants, - ::std::vector<Attribute> outer_attrs) : + ::std::vector<Attribute> outer_attrs, location_t locus) : VisItem(::std::move(vis), ::std::move(outer_attrs)), union_name(::std::move(union_name)), generic_params(::std::move(generic_params)), - where_clause(::std::move(where_clause)), variants(::std::move(variants)) {} + where_clause(::std::move(where_clause)), variants(::std::move(variants)), locus(locus) { + } // copy constructor with vector clone Union(Union const& other) : VisItem(other), union_name(other.union_name), where_clause(other.where_clause), - variants(other.variants) { + variants(other.variants), locus(other.locus) { // crappy vector unique pointer clone - TODO is there a better way of doing this? generic_params.reserve(other.generic_params.size()); @@ -1748,6 +1984,7 @@ namespace Rust { union_name = other.union_name; where_clause = other.where_clause; variants = other.variants; + locus = other.locus; // crappy vector unique pointer clone - TODO is there a better way of doing this? generic_params.reserve(other.generic_params.size()); @@ -1763,6 +2000,12 @@ namespace Rust { Union(Union&& other) = default; Union& operator=(Union&& other) = default; + location_t get_locus() const { + return locus; + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual Union* clone_item_impl() const OVERRIDE { @@ -1776,7 +2019,10 @@ namespace Rust { }; // "Constant item" AST node - used for constant, compile-time expressions within module scope - class ConstantItem : public VisItem { + class ConstantItem + : public VisItem + , public InherentImplItem + , public TraitImplItem { // either has an identifier or "_" - maybe handle in identifier? // bool identifier_is_underscore; // if no identifier declared, identifier will be "_" @@ -1788,6 +2034,8 @@ namespace Rust { // Expr* const_expr; ::std::unique_ptr<Expr> const_expr; + location_t locus; + public: /*~ConstantItem() { delete const_expr; @@ -1795,14 +2043,16 @@ namespace Rust { ::std::string as_string() const; - ConstantItem(Identifier ident, Visibility vis, Type* type, Expr* const_expr, - ::std::vector<Attribute> outer_attrs) : + ConstantItem(Identifier ident, Visibility vis, ::std::unique_ptr<Type> type, + ::std::unique_ptr<Expr> const_expr, ::std::vector<Attribute> outer_attrs, + location_t locus) : VisItem(::std::move(vis), ::std::move(outer_attrs)), - identifier(::std::move(ident)), type(type), const_expr(const_expr) {} + identifier(::std::move(ident)), type(::std::move(type)), + const_expr(::std::move(const_expr)), locus(locus) {} ConstantItem(ConstantItem const& other) : VisItem(other), identifier(other.identifier), type(other.type->clone_type()), - const_expr(other.const_expr->clone_expr()) {} + const_expr(other.const_expr->clone_expr()), locus(other.locus) {} // Destructor - define here if required @@ -1812,6 +2062,7 @@ namespace Rust { identifier = other.identifier; type = other.type->clone_type(); const_expr = other.const_expr->clone_expr(); + locus = other.locus; return *this; } @@ -1826,6 +2077,12 @@ namespace Rust { return identifier == ::std::string("_"); } + location_t get_locus() const { + return locus; + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual ConstantItem* clone_item_impl() const OVERRIDE { @@ -1833,6 +2090,16 @@ namespace Rust { } // Use covariance to implement clone function as returning this object rather than base + virtual ConstantItem* clone_inherent_impl_item_impl() const OVERRIDE { + return new ConstantItem(*this); + } + + // Use covariance to implement clone function as returning this object rather than base + virtual ConstantItem* clone_trait_impl_item_impl() const OVERRIDE { + return new ConstantItem(*this); + } + + // Use covariance to implement clone function as returning this object rather than base /*virtual ConstantItem* clone_statement_impl() const OVERRIDE { return new ConstantItem(*this); }*/ @@ -1850,6 +2117,8 @@ namespace Rust { // Expr* expr; ::std::unique_ptr<Expr> expr; + location_t locus; + public: /*~StaticItem() { delete expr; @@ -1857,15 +2126,17 @@ namespace Rust { ::std::string as_string() const; - StaticItem(Identifier name, bool is_mut, Type* type, Expr* expr, Visibility vis, - ::std::vector<Attribute> outer_attrs) : + StaticItem(Identifier name, bool is_mut, ::std::unique_ptr<Type> type, + ::std::unique_ptr<Expr> expr, Visibility vis, ::std::vector<Attribute> outer_attrs, + location_t locus) : VisItem(::std::move(vis), ::std::move(outer_attrs)), - has_mut(is_mut), name(::std::move(name)), type(type), expr(expr) {} + has_mut(is_mut), name(::std::move(name)), type(::std::move(type)), + expr(::std::move(expr)), locus(locus) {} // Copy constructor with clone StaticItem(StaticItem const& other) : VisItem(other), has_mut(other.has_mut), name(other.name), - type(other.type->clone_type()), expr(other.expr->clone_expr()) {} + type(other.type->clone_type()), expr(other.expr->clone_expr()), locus(other.locus) {} // Destructor - define here if required @@ -1876,6 +2147,7 @@ namespace Rust { has_mut = other.has_mut; type = other.type->clone_type(); expr = other.expr->clone_expr(); + locus = other.locus; return *this; } @@ -1884,6 +2156,12 @@ namespace Rust { StaticItem(StaticItem&& other) = default; StaticItem& operator=(StaticItem&& other) = default; + location_t get_locus() const { + return locus; + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual StaticItem* clone_item_impl() const OVERRIDE { @@ -1898,6 +2176,7 @@ namespace Rust { // Function declaration in traits struct TraitFunctionDecl { + private: // TODO: delete and replace with Function decl item? no as no body in this. FunctionQualifiers qualifiers; Identifier function_name; @@ -1917,6 +2196,8 @@ namespace Rust { // bool has_where_clause; WhereClause where_clause; + // should this store location info? + public: // Returns whether function decl has generic parameters. inline bool has_generics() const { @@ -1941,11 +2222,11 @@ namespace Rust { // Mega-constructor TraitFunctionDecl(Identifier function_name, FunctionQualifiers qualifiers, ::std::vector< ::std::unique_ptr<GenericParam> > generic_params, - ::std::vector<FunctionParam> function_params, Type* return_type, + ::std::vector<FunctionParam> function_params, ::std::unique_ptr<Type> return_type, WhereClause where_clause) : qualifiers(::std::move(qualifiers)), function_name(::std::move(function_name)), generic_params(::std::move(generic_params)), - function_params(::std::move(function_params)), return_type(return_type), + function_params(::std::move(function_params)), return_type(::std::move(return_type)), where_clause(::std::move(where_clause)) {} // Copy constructor with clone @@ -1985,35 +2266,55 @@ namespace Rust { // move constructors TraitFunctionDecl(TraitFunctionDecl&& other) = default; TraitFunctionDecl& operator=(TraitFunctionDecl&& other) = default; + + ::std::string as_string() const; }; // Actual trait item function declaration within traits class TraitItemFunc : public TraitItem { + ::std::vector<Attribute> outer_attrs; TraitFunctionDecl decl; // BlockExpr* block_expr; ::std::unique_ptr<BlockExpr> block_expr; + location_t locus; + public: /*~TraitItemFunc() { delete block_expr; }*/ - TraitItemFunc( - TraitFunctionDecl decl, BlockExpr* block_expr, ::std::vector<Attribute> outer_attrs) : - TraitItem(::std::move(outer_attrs)), - decl(::std::move(decl)), block_expr(block_expr) {} + // Returns whether function has a definition or is just a declaration. + inline bool has_definition() const { + return block_expr != NULL; + } + + TraitItemFunc(TraitFunctionDecl decl, ::std::unique_ptr<BlockExpr> block_expr, + ::std::vector<Attribute> outer_attrs, location_t locus) : + outer_attrs(::std::move(outer_attrs)), + decl(::std::move(decl)), block_expr(::std::move(block_expr)), locus(locus) {} // Copy constructor with clone TraitItemFunc(TraitItemFunc const& other) : - TraitItem(other), decl(other.decl), block_expr(other.block_expr->clone_block_expr()) {} + outer_attrs(other.outer_attrs), + decl(other.decl) /*, block_expr(other.block_expr->clone_block_expr())*/, + locus(other.locus) { + if (other.block_expr != NULL) { + block_expr = other.block_expr->clone_block_expr(); + } + } // Destructor - define here if required // Overloaded assignment operator to clone TraitItemFunc& operator=(TraitItemFunc const& other) { TraitItem::operator=(other); + outer_attrs = other.outer_attrs; decl = other.decl; - block_expr = other.block_expr->clone_block_expr(); + locus = other.locus; + if (other.block_expr != NULL) { + block_expr = other.block_expr->clone_block_expr(); + } return *this; } @@ -2022,6 +2323,14 @@ namespace Rust { TraitItemFunc(TraitItemFunc&& other) = default; TraitItemFunc& operator=(TraitItemFunc&& other) = default; + ::std::string as_string() const; + + location_t get_locus() const { + return locus; + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Clone function implementation as (not pure) virtual method virtual TraitItemFunc* clone_trait_item_impl() const { @@ -2031,6 +2340,7 @@ namespace Rust { // Method declaration within traits struct TraitMethodDecl { + private: // TODO: delete and replace with Function decl item? no as no body. FunctionQualifiers qualifiers; Identifier function_name; @@ -2052,6 +2362,8 @@ namespace Rust { // bool has_where_clause; WhereClause where_clause; + // should this store location info? + public: // Returns whether method decl has generic parameters. inline bool has_generics() const { @@ -2076,12 +2388,12 @@ namespace Rust { // Mega-constructor TraitMethodDecl(Identifier function_name, FunctionQualifiers qualifiers, ::std::vector< ::std::unique_ptr<GenericParam> > generic_params, SelfParam self_param, - ::std::vector<FunctionParam> function_params, Type* return_type, + ::std::vector<FunctionParam> function_params, ::std::unique_ptr<Type> return_type, WhereClause where_clause) : qualifiers(::std::move(qualifiers)), function_name(::std::move(function_name)), generic_params(::std::move(generic_params)), self_param(::std::move(self_param)), function_params(::std::move(function_params)), - return_type(return_type), where_clause(::std::move(where_clause)) {} + return_type(::std::move(return_type)), where_clause(::std::move(where_clause)) {} // Copy constructor with clone TraitMethodDecl(TraitMethodDecl const& other) : @@ -2122,35 +2434,48 @@ namespace Rust { // move constructors TraitMethodDecl(TraitMethodDecl&& other) = default; TraitMethodDecl& operator=(TraitMethodDecl&& other) = default; + + ::std::string as_string() const; }; // Actual trait item method declaration within traits class TraitItemMethod : public TraitItem { + ::std::vector<Attribute> outer_attrs; TraitMethodDecl decl; // BlockExpr* block_expr; ::std::unique_ptr<BlockExpr> block_expr; + location_t locus; + public: /*~TraitItemMethod() { delete block_expr; }*/ - TraitItemMethod( - TraitMethodDecl decl, BlockExpr* block_expr, ::std::vector<Attribute> outer_attrs) : - TraitItem(::std::move(outer_attrs)), - decl(::std::move(decl)), block_expr(block_expr) {} + // Returns whether method has a definition or is just a declaration. + inline bool has_definition() const { + return block_expr != NULL; + } + + TraitItemMethod(TraitMethodDecl decl, ::std::unique_ptr<BlockExpr> block_expr, + ::std::vector<Attribute> outer_attrs, location_t locus) : + outer_attrs(::std::move(outer_attrs)), + decl(::std::move(decl)), block_expr(::std::move(block_expr)), locus(locus) {} // Copy constructor with clone TraitItemMethod(TraitItemMethod const& other) : - TraitItem(other), decl(other.decl), block_expr(other.block_expr->clone_block_expr()) {} + outer_attrs(other.outer_attrs), decl(other.decl), + block_expr(other.block_expr->clone_block_expr()), locus(other.locus) {} // Destructor - define here if required // Overloaded assignment operator to clone TraitItemMethod& operator=(TraitItemMethod const& other) { TraitItem::operator=(other); + outer_attrs = other.outer_attrs; decl = other.decl; block_expr = other.block_expr->clone_block_expr(); + locus = other.locus; return *this; } @@ -2159,6 +2484,14 @@ namespace Rust { TraitItemMethod(TraitItemMethod&& other) = default; TraitItemMethod& operator=(TraitItemMethod&& other) = default; + ::std::string as_string() const; + + location_t get_locus() const { + return locus; + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Clone function implementation as (not pure) virtual method virtual TraitItemMethod* clone_trait_item_impl() const { @@ -2168,6 +2501,7 @@ namespace Rust { // Constant item within traits class TraitItemConst : public TraitItem { + ::std::vector<Attribute> outer_attrs; Identifier name; // Type type; ::std::unique_ptr<Type> type; @@ -2176,6 +2510,8 @@ namespace Rust { // Expr* expr; ::std::unique_ptr<Expr> expr; + location_t locus; + public: /*~TraitItemConst() { delete expr; @@ -2186,24 +2522,27 @@ namespace Rust { return expr != NULL; } - TraitItemConst( - Identifier name, Type* type, Expr* expr, ::std::vector<Attribute> outer_attrs) : - TraitItem(::std::move(outer_attrs)), - name(::std::move(name)), type(type), expr(expr) {} + TraitItemConst(Identifier name, ::std::unique_ptr<Type> type, + ::std::unique_ptr<Expr> expr, ::std::vector<Attribute> outer_attrs, location_t locus) : + outer_attrs(::std::move(outer_attrs)), + name(::std::move(name)), type(::std::move(type)), expr(::std::move(expr)), + locus(locus) {} // Copy constructor with clones TraitItemConst(TraitItemConst const& other) : - TraitItem(other), name(other.name), type(other.type->clone_type()), - expr(other.expr->clone_expr()) {} + outer_attrs(other.outer_attrs), name(other.name), type(other.type->clone_type()), + expr(other.expr->clone_expr()), locus(other.locus) {} // Destructor - define here if required // Overloaded assignment operator to clone TraitItemConst& operator=(TraitItemConst const& other) { TraitItem::operator=(other); + outer_attrs = other.outer_attrs; name = other.name; type = other.type->clone_type(); expr = other.expr->clone_expr(); + locus = other.locus; return *this; } @@ -2212,6 +2551,14 @@ namespace Rust { TraitItemConst(TraitItemConst&& other) = default; TraitItemConst& operator=(TraitItemConst&& other) = default; + ::std::string as_string() const; + + location_t get_locus() const { + return locus; + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Clone function implementation as (not pure) virtual method virtual TraitItemConst* clone_trait_item_impl() const { @@ -2221,12 +2568,16 @@ namespace Rust { // Type items within traits class TraitItemType : public TraitItem { + ::std::vector<Attribute> outer_attrs; + Identifier name; // bool has_type_param_bounds; // TypeParamBounds type_param_bounds; ::std::vector< ::std::unique_ptr<TypeParamBound> > type_param_bounds; // inlined form + location_t locus; + public: // Returns whether trait item type has type param bounds. inline bool has_type_param_bounds() const { @@ -2235,12 +2586,14 @@ namespace Rust { TraitItemType(Identifier name, ::std::vector< ::std::unique_ptr<TypeParamBound> > type_param_bounds, - ::std::vector<Attribute> outer_attrs) : - TraitItem(::std::move(outer_attrs)), - name(::std::move(name)), type_param_bounds(::std::move(type_param_bounds)) {} + ::std::vector<Attribute> outer_attrs, location_t locus) : + outer_attrs(::std::move(outer_attrs)), + name(::std::move(name)), type_param_bounds(::std::move(type_param_bounds)), + locus(locus) {} // Copy constructor with vector clone - TraitItemType(TraitItemType const& other) : TraitItem(other), name(other.name) { + TraitItemType(TraitItemType const& other) : + outer_attrs(other.outer_attrs), name(other.name), locus(other.locus) { // crappy vector unique pointer clone - TODO is there a better way of doing this? type_param_bounds.reserve(other.type_param_bounds.size()); @@ -2252,7 +2605,9 @@ namespace Rust { // Overloaded assignment operator with vector clone TraitItemType& operator=(TraitItemType const& other) { TraitItem::operator=(other); + outer_attrs = other.outer_attrs; name = other.name; + locus = other.locus; // crappy vector unique pointer clone - TODO is there a better way of doing this? type_param_bounds.reserve(other.type_param_bounds.size()); @@ -2268,6 +2623,14 @@ namespace Rust { TraitItemType(TraitItemType&& other) = default; TraitItemType& operator=(TraitItemType&& other) = default; + ::std::string as_string() const; + + location_t get_locus() const { + return locus; + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Clone function implementation as (not pure) virtual method virtual TraitItemType* clone_trait_item_impl() const { @@ -2308,6 +2671,8 @@ namespace Rust { // bool has_trait_items; ::std::vector< ::std::unique_ptr<TraitItem> > trait_items; + location_t locus; + public: ::std::string as_string() const; @@ -2336,17 +2701,18 @@ namespace Rust { ::std::vector< ::std::unique_ptr<GenericParam> > generic_params, ::std::vector< ::std::unique_ptr<TypeParamBound> > type_param_bounds, WhereClause where_clause, ::std::vector< ::std::unique_ptr<TraitItem> > trait_items, - Visibility vis, ::std::vector<Attribute> outer_attrs) : + Visibility vis, ::std::vector<Attribute> outer_attrs, location_t locus) : VisItem(::std::move(vis), ::std::move(outer_attrs)), has_unsafe(is_unsafe), name(::std::move(name)), generic_params(::std::move(generic_params)), type_param_bounds(::std::move(type_param_bounds)), - where_clause(::std::move(where_clause)), trait_items(::std::move(trait_items)) {} + where_clause(::std::move(where_clause)), trait_items(::std::move(trait_items)), + locus(locus) {} // Copy constructor with vector clone Trait(Trait const& other) : VisItem(other), has_unsafe(other.has_unsafe), name(other.name), - where_clause(other.where_clause) { + where_clause(other.where_clause), locus(other.locus) { // crappy vector unique pointer clone - TODO is there a better way of doing this? generic_params.reserve(other.generic_params.size()); @@ -2375,6 +2741,7 @@ namespace Rust { name = other.name; has_unsafe = other.has_unsafe; where_clause = other.where_clause; + locus = other.locus; // crappy vector unique pointer clone - TODO is there a better way of doing this? generic_params.reserve(other.generic_params.size()); @@ -2404,6 +2771,12 @@ namespace Rust { Trait(Trait&& other) = default; Trait& operator=(Trait&& other) = default; + location_t get_locus() const { + return locus; + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual Trait* clone_item_impl() const OVERRIDE { @@ -2418,6 +2791,8 @@ namespace Rust { // Implementation item declaration AST node - abstract base class class Impl : public VisItem { + // must be protected to allow subclasses to access them properly + protected: // bool has_generics; // Generics generic_params; ::std::vector< ::std::unique_ptr<GenericParam> > generic_params; // inlined @@ -2431,6 +2806,10 @@ namespace Rust { // bool has_inner_attrs; ::std::vector<Attribute> inner_attrs; + private: + // doesn't really need to be protected as write access probably not needed + location_t locus; + public: // Returns whether impl has generic parameters. inline bool has_generics() const { @@ -2447,19 +2826,26 @@ namespace Rust { return !inner_attrs.empty(); } + location_t get_locus() const { + return locus; + } + + protected: // Mega-constructor - Impl(::std::vector< ::std::unique_ptr<GenericParam> > generic_params, Type* trait_type, - WhereClause where_clause, Visibility vis, ::std::vector<Attribute> inner_attrs, - ::std::vector<Attribute> outer_attrs) : + Impl(::std::vector< ::std::unique_ptr<GenericParam> > generic_params, + ::std::unique_ptr<Type> trait_type, WhereClause where_clause, Visibility vis, + ::std::vector<Attribute> inner_attrs, ::std::vector<Attribute> outer_attrs, + location_t locus) : VisItem(::std::move(vis), ::std::move(outer_attrs)), - generic_params(::std::move(generic_params)), trait_type(trait_type), - where_clause(::std::move(where_clause)), inner_attrs(::std::move(inner_attrs)) {} + generic_params(::std::move(generic_params)), trait_type(::std::move(trait_type)), + where_clause(::std::move(where_clause)), inner_attrs(::std::move(inner_attrs)), + locus(locus) {} // Copy constructor Impl(Impl const& other) : VisItem(other), /*generic_params(other.generic_params),*/ trait_type(other.trait_type->clone_type()), - where_clause(other.where_clause), inner_attrs(other.inner_attrs) { + where_clause(other.where_clause), inner_attrs(other.inner_attrs), locus(other.locus) { // crappy vector unique pointer clone - TODO is there a better way of doing this? generic_params.reserve(other.generic_params.size()); @@ -2477,6 +2863,7 @@ namespace Rust { trait_type = other.trait_type->clone_type(); where_clause = other.where_clause; inner_attrs = other.inner_attrs; + locus = other.locus; // crappy vector unique pointer clone - TODO is there a better way of doing this? generic_params.reserve(other.generic_params.size()); @@ -2493,188 +2880,6 @@ namespace Rust { Impl& operator=(Impl&& other) = default; }; - // Abstract base class for items used within an inherent impl block (the impl name {} one) - class InherentImplItem { - protected: - // bool has_outer_attrs; - // TODO: remove and rely on virtual functions and VisItem-derived attributes? - ::std::vector<Attribute> outer_attrs; - - InherentImplItem(::std::vector<Attribute> outer_attrs = ::std::vector<Attribute>()) : - outer_attrs(::std::move(outer_attrs)) {} - - // Clone function implementation as pure virtual method - virtual InherentImplItem* clone_inherent_impl_item_impl() const = 0; - - public: - // Returns whether item has outer attributes. - inline bool has_outer_attrs() const { - return !outer_attrs.empty(); - } - - virtual ~InherentImplItem() {} - - // Unique pointer custom clone function - ::std::unique_ptr<InherentImplItem> clone_inherent_impl_item() const { - return ::std::unique_ptr<InherentImplItem>(clone_inherent_impl_item_impl()); - } - }; - - // Macro item used within an inherent impl block - class InherentImplItemMacro : public InherentImplItem { - MacroInvocationSemi macro; - - public: - InherentImplItemMacro(MacroInvocationSemi macro, ::std::vector<Attribute> outer_attrs) : - InherentImplItem(::std::move(outer_attrs)), macro(::std::move(macro)) {} - - protected: - // Use covariance to implement clone function as returning this object rather than base - virtual InherentImplItemMacro* clone_inherent_impl_item_impl() const OVERRIDE { - return new InherentImplItemMacro(*this); - } - }; - - // Constant item used within an inherent impl block - class InherentImplItemConstant : public InherentImplItem { - // bool has_visibility; - // FIXME: ConstantItem already has vis, so this is redundant - // Visibility visibility; - - ConstantItem constant_item; - - public: - // Returns whether item has a non-default (i.e. non-private) visibility. - inline bool has_visibility() const { - // return !visibility.is_error(); - return constant_item.has_visibility(); - } - - InherentImplItemConstant( - ConstantItem constant_item, /*Visibility vis,*/ ::std::vector<Attribute> outer_attrs) : - InherentImplItem(::std::move(outer_attrs)), - constant_item(::std::move(constant_item)) - /*, visibility(vis),*/ {} - - // Copy constructor with clone - InherentImplItemConstant(InherentImplItemConstant const& other) : - InherentImplItem(other), constant_item(other.constant_item) - /*, visibility(other.visibility),*/ {} - - // Destructor - define here if required - - // Overloaded assignment operator to clone - InherentImplItemConstant& operator=(InherentImplItemConstant const& other) { - InherentImplItem::operator=(other); - constant_item = other.constant_item; - // visibility = other.visibility; - - return *this; - } - - // move constructors - InherentImplItemConstant(InherentImplItemConstant&& other) = default; - InherentImplItemConstant& operator=(InherentImplItemConstant&& other) = default; - - protected: - // Use covariance to implement clone function as returning this object rather than base - virtual InherentImplItemConstant* clone_inherent_impl_item_impl() const OVERRIDE { - return new InherentImplItemConstant(*this); - } - }; - - // Function item used within an inherent impl block - class InherentImplItemFunction : public InherentImplItem { - // bool has_visibility; - // FIXME: function already has vis, so this is redundant - // Visibility visibility; - - Function function; - - public: - // Returns whether item has a non-default (i.e. non-private) visibility. - inline bool has_visibility() const { - // return !visibility.is_error(); - return function.has_visibility(); - } - - InherentImplItemFunction( - Function function, /*Visibility vis,*/ ::std::vector<Attribute> outer_attrs) : - InherentImplItem(::std::move(outer_attrs)), - function(::std::move(function)) - /*, visibility(vis),*/ {} - - // Copy constructor with clone - InherentImplItemFunction(InherentImplItemFunction const& other) : - InherentImplItem(other), function(other.function) /*, visibility(other.visibility),*/ {} - - // Destructor - define here if required - - // Overloaded assignment operator to clone - InherentImplItemFunction& operator=(InherentImplItemFunction const& other) { - InherentImplItem::operator=(other); - function = other.function; - // visibility = other.visibility; - - return *this; - } - - // move constructors - InherentImplItemFunction(InherentImplItemFunction&& other) = default; - InherentImplItemFunction& operator=(InherentImplItemFunction&& other) = default; - - protected: - // Use covariance to implement clone function as returning this object rather than base - virtual InherentImplItemFunction* clone_inherent_impl_item_impl() const OVERRIDE { - return new InherentImplItemFunction(*this); - } - }; - - // Method item used within an inherent impl block - class InherentImplItemMethod : public InherentImplItem { - // bool has_visibility; - // TODO: move visibility to method to be consistent with other inherent impl items? - Visibility visibility; - - Method method; - - public: - // Returns whether the inherent impl item method has non-default (non-private) visibility. - inline bool has_visibility() const { - return !visibility.is_error(); - } - - InherentImplItemMethod( - Method method, Visibility vis, ::std::vector<Attribute> outer_attrs) : - InherentImplItem(::std::move(outer_attrs)), - visibility(::std::move(vis)), method(::std::move(method)) {} - - // Copy constructor with clone - InherentImplItemMethod(InherentImplItemMethod const& other) : - InherentImplItem(other), visibility(other.visibility), method(other.method) {} - - // Destructor - define here if required - - // Overloaded assignment operator to clone - InherentImplItemMethod& operator=(InherentImplItemMethod const& other) { - InherentImplItem::operator=(other); - method = other.method; - visibility = other.visibility; - - return *this; - } - - // move constructors - InherentImplItemMethod(InherentImplItemMethod&& other) = default; - InherentImplItemMethod& operator=(InherentImplItemMethod&& other) = default; - - protected: - // Use covariance to implement clone function as returning this object rather than base - virtual InherentImplItemMethod* clone_inherent_impl_item_impl() const OVERRIDE { - return new InherentImplItemMethod(*this); - } - }; - // Regular "impl foo" impl block declaration AST node class InherentImpl : public Impl { // bool has_impl_items; @@ -2690,11 +2895,12 @@ namespace Rust { // Mega-constructor InherentImpl(::std::vector< ::std::unique_ptr<InherentImplItem> > impl_items, - ::std::vector< ::std::unique_ptr<GenericParam> > generic_params, Type* trait_type, - WhereClause where_clause, Visibility vis, ::std::vector<Attribute> inner_attrs, - ::std::vector<Attribute> outer_attrs) : - Impl(::std::move(generic_params), trait_type, ::std::move(where_clause), - ::std::move(vis), ::std::move(inner_attrs), ::std::move(outer_attrs)), + ::std::vector< ::std::unique_ptr<GenericParam> > generic_params, + ::std::unique_ptr<Type> trait_type, WhereClause where_clause, Visibility vis, + ::std::vector<Attribute> inner_attrs, ::std::vector<Attribute> outer_attrs, + location_t locus) : + Impl(::std::move(generic_params), ::std::move(trait_type), ::std::move(where_clause), + ::std::move(vis), ::std::move(inner_attrs), ::std::move(outer_attrs), locus), impl_items(::std::move(impl_items)) {} // Copy constructor with vector clone @@ -2725,6 +2931,8 @@ namespace Rust { InherentImpl(InherentImpl&& other) = default; InherentImpl& operator=(InherentImpl&& other) = default; + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual InherentImpl* clone_item_impl() const OVERRIDE { @@ -2737,235 +2945,6 @@ namespace Rust { }*/ }; - // Abstract base class for items used in a trait impl - class TraitImplItem { - protected: - // bool has_outer_attrs; - ::std::vector<Attribute> outer_attrs; - // TODO: don't have outer attributes and rely on VisItem outer attributes only? - - TraitImplItem(::std::vector<Attribute> outer_attrs = ::std::vector<Attribute>()) : - outer_attrs(::std::move(outer_attrs)) {} - - // Clone function implementation as pure virtual method - virtual TraitImplItem* clone_trait_impl_item_impl() const = 0; - - public: - virtual ~TraitImplItem(){}; - - // Returns whether trait impl item has outer attributes. - inline bool has_outer_attrs() const { - return !outer_attrs.empty(); - } - - // Unique pointer custom clone function - ::std::unique_ptr<TraitImplItem> clone_trait_impl_item() const { - return ::std::unique_ptr<TraitImplItem>(clone_trait_impl_item_impl()); - } - }; - - // Macro invocation item in a trait impl - class TraitImplItemMacro : public TraitImplItem { - MacroInvocationSemi macro; - - public: - TraitImplItemMacro(MacroInvocationSemi macro, ::std::vector<Attribute> outer_attrs) : - TraitImplItem(::std::move(outer_attrs)), macro(::std::move(macro)) {} - - protected: - // Use covariance to implement clone function as returning this object rather than base - virtual TraitImplItemMacro* clone_trait_impl_item_impl() const OVERRIDE { - return new TraitImplItemMacro(*this); - } - }; - - // Type alias item in a trait impl - class TraitImplItemTypeAlias : public TraitImplItem { - // bool has_visibility; - // FIXME: don't double up visibility because TypeAlias already has it - // Visibility visibility; - - TypeAlias type_alias; - - public: - // Returns whether trait impl item has a non-default visibility. - inline bool has_visibility() const { - // return !visibility.is_error(); - return type_alias.has_visibility(); - } - - TraitImplItemTypeAlias( - TypeAlias type_alias, /*Visibility vis,*/ ::std::vector<Attribute> outer_attrs) : - TraitImplItem(::std::move(outer_attrs)), - type_alias(::std::move(type_alias)) - /*, visibility(vis),*/ {} - - // Copy constructor - TraitImplItemTypeAlias(TraitImplItemTypeAlias const& other) : - TraitImplItem(other), type_alias(other.type_alias) /*, visibility(other.visibility),*/ { - } - - // Destructor - define here if required - - // Overloaded assignment operator to clone - TraitImplItemTypeAlias& operator=(TraitImplItemTypeAlias const& other) { - TraitImplItem::operator=(other); - type_alias = other.type_alias; - // visibility = other.visibility; - - return *this; - } - - // move constructors - TraitImplItemTypeAlias(TraitImplItemTypeAlias&& other) = default; - TraitImplItemTypeAlias& operator=(TraitImplItemTypeAlias&& other) = default; - - protected: - // Use covariance to implement clone function as returning this object rather than base - virtual TraitImplItemTypeAlias* clone_trait_impl_item_impl() const OVERRIDE { - return new TraitImplItemTypeAlias(*this); - } - }; - - // Constant item in a trait impl - class TraitImplItemConstant : public TraitImplItem { - // bool has_visibility; - // FIXME: this is redundant as VisItem has it - // Visibility visibility; - - ConstantItem constant_item; - - public: - // Returns whether item has a non-default (i.e. non-private) visibility. - inline bool has_visibility() const { - // return !visibility.is_error(); - return constant_item.has_visibility(); - } - - TraitImplItemConstant( - ConstantItem constant_item, /*Visibility vis,*/ ::std::vector<Attribute> outer_attrs) : - TraitImplItem(::std::move(outer_attrs)), - constant_item(::std::move(constant_item)) - /*, visibility(vis),*/ {} - - // Copy constructor with clone - TraitImplItemConstant(TraitImplItemConstant const& other) : - TraitImplItem(other), constant_item(other.constant_item) - /*, visibility(other.visibility),*/ {} - - // Destructor - define here if required - - // Overloaded assignment operator to clone - TraitImplItemConstant& operator=(TraitImplItemConstant const& other) { - TraitImplItem::operator=(other); - constant_item = other.constant_item; - // visibility = other.visibility; - - return *this; - } - - // move constructors as not supported in c++03 - TraitImplItemConstant(TraitImplItemConstant&& other) = default; - TraitImplItemConstant& operator=(TraitImplItemConstant&& other) = default; - - protected: - // Use covariance to implement clone function as returning this object rather than base - virtual TraitImplItemConstant* clone_trait_impl_item_impl() const OVERRIDE { - return new TraitImplItemConstant(*this); - } - }; - - /// Function item in a trait impl - class TraitImplItemFunction : public TraitImplItem { - // bool has_visibility; - // FIXME: redundant - VisItem already has visibility - // Visibility visibility; - - Function function; - - public: - // Returns whether item has a non-default (i.e. non-private) visibility. - inline bool has_visibility() const { - // return !visibility.is_error(); - return function.has_visibility(); - } - - TraitImplItemFunction( - Function function, /*Visibility vis,*/ ::std::vector<Attribute> outer_attrs) : - TraitImplItem(::std::move(outer_attrs)), - function(::std::move(function)) - /*, visibility(vis),*/ {} - - // Copy constructor with clone - TraitImplItemFunction(TraitImplItemFunction const& other) : - TraitImplItem(other), function(other.function) /*, visibility(other.visibility),*/ {} - - // Destructor - define here if required - - // Overloaded assignment operator to clone - TraitImplItemFunction& operator=(TraitImplItemFunction const& other) { - TraitImplItem::operator=(other); - function = other.function; - // visibility = other.visibility; - - return *this; - } - - // move constructors - TraitImplItemFunction(TraitImplItemFunction&& other) = default; - TraitImplItemFunction& operator=(TraitImplItemFunction&& other) = default; - - protected: - // Use covariance to implement clone function as returning this object rather than base - virtual TraitImplItemFunction* clone_trait_impl_item_impl() const OVERRIDE { - return new TraitImplItemFunction(*this); - } - }; - - // Method item in a trait impl - class TraitImplItemMethod : public TraitImplItem { - // bool has_visibility; - Visibility visibility; - - // TODO: add visibility to Method for consistency? - Method method; - - public: - // Returns whether the trait impl item method has non-default (non-private) visibility. - inline bool has_visibility() const { - return !visibility.is_error(); - } - - TraitImplItemMethod(Method method, Visibility vis, ::std::vector<Attribute> outer_attrs) : - TraitImplItem(::std::move(outer_attrs)), visibility(::std::move(vis)), - method(::std::move(method)) {} - - // Copy constructor with clone - TraitImplItemMethod(TraitImplItemMethod const& other) : - TraitImplItem(other), visibility(other.visibility), method(other.method) {} - - // Destructor - define here if required - - // Overloaded assignment operator to clone - TraitImplItemMethod& operator=(TraitImplItemMethod const& other) { - TraitImplItem::operator=(other); - method = other.method; - visibility = other.visibility; - - return *this; - } - - // move constructors - TraitImplItemMethod(TraitImplItemMethod&& other) = default; - TraitImplItemMethod& operator=(TraitImplItemMethod&& other) = default; - - protected: - // Use covariance to implement clone function as returning this object rather than base - virtual TraitImplItemMethod* clone_trait_impl_item_impl() const OVERRIDE { - return new TraitImplItemMethod(*this); - } - }; - // The "impl footrait for foo" impl block declaration AST node class TraitImpl : public Impl { bool has_unsafe; @@ -2988,11 +2967,12 @@ namespace Rust { // Mega-constructor TraitImpl(TypePath trait_path, bool is_unsafe, bool has_exclam, ::std::vector< ::std::unique_ptr<TraitImplItem> > impl_items, - ::std::vector< ::std::unique_ptr<GenericParam> > generic_params, Type* trait_type, - WhereClause where_clause, Visibility vis, ::std::vector<Attribute> inner_attrs, - ::std::vector<Attribute> outer_attrs) : - Impl(::std::move(generic_params), trait_type, ::std::move(where_clause), - ::std::move(vis), ::std::move(inner_attrs), ::std::move(outer_attrs)), + ::std::vector< ::std::unique_ptr<GenericParam> > generic_params, + ::std::unique_ptr<Type> trait_type, WhereClause where_clause, Visibility vis, + ::std::vector<Attribute> inner_attrs, ::std::vector<Attribute> outer_attrs, + location_t locus) : + Impl(::std::move(generic_params), ::std::move(trait_type), ::std::move(where_clause), + ::std::move(vis), ::std::move(inner_attrs), ::std::move(outer_attrs), locus), has_unsafe(is_unsafe), has_exclam(has_exclam), trait_path(::std::move(trait_path)), impl_items(::std::move(impl_items)) {} @@ -3031,6 +3011,8 @@ namespace Rust { TraitImpl(TraitImpl&& other) = default; TraitImpl& operator=(TraitImpl&& other) = default; + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual TraitImpl* clone_item_impl() const OVERRIDE { @@ -3053,6 +3035,8 @@ namespace Rust { Identifier item_name; + location_t locus; + public: virtual ~ExternalItem() {} @@ -3071,21 +3055,31 @@ namespace Rust { return ::std::unique_ptr<ExternalItem>(clone_external_item_impl()); } + virtual ::std::string as_string() const; + + location_t get_locus() const { + return locus; + } + + virtual void accept_vis(ASTVisitor& vis) = 0; + protected: - ExternalItem(Identifier item_name, Visibility vis, ::std::vector<Attribute> outer_attrs) : - outer_attrs(::std::move(outer_attrs)), visibility(::std::move(vis)), - item_name(::std::move(item_name)) {} + ExternalItem(Identifier item_name, Visibility vis, ::std::vector<Attribute> outer_attrs, + location_t locus) : + outer_attrs(::std::move(outer_attrs)), + visibility(::std::move(vis)), item_name(::std::move(item_name)), locus(locus) {} // Copy constructor ExternalItem(ExternalItem const& other) : outer_attrs(other.outer_attrs), visibility(other.visibility), - item_name(other.item_name) {} + item_name(other.item_name), locus(other.locus) {} // Overloaded assignment operator to clone ExternalItem& operator=(ExternalItem const& other) { item_name = other.item_name; visibility = other.visibility; outer_attrs = other.outer_attrs; + locus = other.locus; return *this; } @@ -3096,6 +3090,11 @@ namespace Rust { // Clone function implementation as pure virtual method virtual ExternalItem* clone_external_item_impl() const = 0; + + // possibly make this public if required + ::std::string get_item_name() const { + return item_name; + } }; // A static item used in an extern block @@ -3106,10 +3105,10 @@ namespace Rust { ::std::unique_ptr<Type> item_type; public: - ExternalStaticItem(Identifier item_name, Type* item_type, bool is_mut, Visibility vis, - ::std::vector<Attribute> outer_attrs) : - ExternalItem(::std::move(item_name), ::std::move(vis), ::std::move(outer_attrs)), - has_mut(is_mut), item_type(item_type) {} + ExternalStaticItem(Identifier item_name, ::std::unique_ptr<Type> item_type, bool is_mut, + Visibility vis, ::std::vector<Attribute> outer_attrs, location_t locus) : + ExternalItem(::std::move(item_name), ::std::move(vis), ::std::move(outer_attrs), locus), + has_mut(is_mut), item_type(::std::move(item_type)) {} // Copy constructor ExternalStaticItem(ExternalStaticItem const& other) : @@ -3130,6 +3129,10 @@ namespace Rust { ExternalStaticItem(ExternalStaticItem&& other) = default; ExternalStaticItem& operator=(ExternalStaticItem&& other) = default; + ::std::string as_string() const; + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual ExternalStaticItem* clone_external_item_impl() const OVERRIDE { @@ -3146,6 +3149,8 @@ namespace Rust { // Type param_type; ::std::unique_ptr<Type> param_type; + // TODO: should this store location data? + public: // Returns whether the named function parameter has a name (i.e. name is not '_'). inline bool has_name() const { @@ -3163,8 +3168,8 @@ namespace Rust { return NamedFunctionParam("", NULL); } - NamedFunctionParam(Identifier name, Type* param_type) : - name(::std::move(name)), param_type(param_type) {} + NamedFunctionParam(Identifier name, ::std::unique_ptr<Type> param_type) : + name(::std::move(name)), param_type(::std::move(param_type)) {} // Copy constructor NamedFunctionParam(NamedFunctionParam const& other) : @@ -3184,6 +3189,8 @@ namespace Rust { // move constructors NamedFunctionParam(NamedFunctionParam&& other) = default; NamedFunctionParam& operator=(NamedFunctionParam&& other) = default; + + ::std::string as_string() const; }; // A function item used in an extern block @@ -3220,11 +3227,12 @@ namespace Rust { } ExternalFunctionItem(Identifier item_name, - ::std::vector< ::std::unique_ptr<GenericParam> > generic_params, Type* return_type, - WhereClause where_clause, ::std::vector<NamedFunctionParam> function_params, - bool has_variadics, Visibility vis, ::std::vector<Attribute> outer_attrs) : - ExternalItem(::std::move(item_name), ::std::move(vis), ::std::move(outer_attrs)), - generic_params(::std::move(generic_params)), return_type(return_type), + ::std::vector< ::std::unique_ptr<GenericParam> > generic_params, + ::std::unique_ptr<Type> return_type, WhereClause where_clause, + ::std::vector<NamedFunctionParam> function_params, bool has_variadics, Visibility vis, + ::std::vector<Attribute> outer_attrs, location_t locus) : + ExternalItem(::std::move(item_name), ::std::move(vis), ::std::move(outer_attrs), locus), + generic_params(::std::move(generic_params)), return_type(::std::move(return_type)), where_clause(::std::move(where_clause)), function_params(::std::move(function_params)), has_variadics(has_variadics) {} @@ -3267,6 +3275,10 @@ namespace Rust { ExternalFunctionItem(ExternalFunctionItem&& other) = default; ExternalFunctionItem& operator=(ExternalFunctionItem&& other) = default; + ::std::string as_string() const; + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual ExternalFunctionItem* clone_external_item_impl() const OVERRIDE { @@ -3277,7 +3289,7 @@ namespace Rust { // An extern block AST node class ExternBlock : public VisItem { // bool has_abi; - AbiName abi; + ::std::string abi; // bool has_inner_attrs; ::std::vector<Attribute> inner_attrs; @@ -3285,6 +3297,8 @@ namespace Rust { // bool has_extern_items; ::std::vector< ::std::unique_ptr<ExternalItem> > extern_items; + location_t locus; + public: ::std::string as_string() const; @@ -3300,19 +3314,20 @@ namespace Rust { // Returns whether extern block has ABI name. inline bool has_abi() const { - return !abi.is_empty(); + return !abi.empty(); } - ExternBlock(AbiName abi, ::std::vector< ::std::unique_ptr<ExternalItem> > extern_items, - Visibility vis, ::std::vector<Attribute> inner_attrs, - ::std::vector<Attribute> outer_attrs) : + ExternBlock(::std::string abi, + ::std::vector< ::std::unique_ptr<ExternalItem> > extern_items, Visibility vis, + ::std::vector<Attribute> inner_attrs, ::std::vector<Attribute> outer_attrs, + location_t locus) : VisItem(::std::move(vis), ::std::move(outer_attrs)), abi(::std::move(abi)), inner_attrs(::std::move(inner_attrs)), - extern_items(::std::move(extern_items)) {} + extern_items(::std::move(extern_items)), locus(locus) {} // Copy constructor with vector clone ExternBlock(ExternBlock const& other) : - VisItem(other), abi(other.abi), inner_attrs(other.inner_attrs) { + VisItem(other), abi(other.abi), inner_attrs(other.inner_attrs), locus(other.locus) { // crappy vector unique pointer clone - TODO is there a better way of doing this? extern_items.reserve(other.extern_items.size()); @@ -3326,6 +3341,7 @@ namespace Rust { VisItem::operator=(other); abi = other.abi; inner_attrs = other.inner_attrs; + locus = other.locus; // crappy vector unique pointer clone - TODO is there a better way of doing this? extern_items.reserve(other.extern_items.size()); @@ -3341,6 +3357,12 @@ namespace Rust { ExternBlock(ExternBlock&& other) = default; ExternBlock& operator=(ExternBlock&& other) = default; + location_t get_locus() const { + return locus; + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual ExternBlock* clone_item_impl() const OVERRIDE { @@ -3357,30 +3379,6 @@ namespace Rust { class MacroItem; class MacroInvocationSemi; class MacroRulesDefinition; - - /*// A macro item AST node - potentially abstract base class - class MacroItem : public Item { - }; - - // A macro invocation item (or statement) AST node - class MacroInvocationSemi : public MacroItem, public Statement { - SimplePath path; - enum DelimType { - PARENS, - SQUARE, - CURLY // all delim types except curly must have invocation end with a semicolon - } delim_type; - ::std::vector<TokenTree> token_trees; - - public: - ::std::string as_string() const; - }; - - // A macro rules definition item AST node - class MacroRulesDefinition : public MacroItem { - public: - ::std::string as_string() const; - };*/ } } diff --git a/gcc/rust/test3/ast/rust-macro.h b/gcc/rust/test3/ast/rust-macro.h index c028717..4c8237e 100644 --- a/gcc/rust/test3/ast/rust-macro.h +++ b/gcc/rust/test3/ast/rust-macro.h @@ -27,35 +27,35 @@ namespace Rust { }; inline MacroFragSpec get_frag_spec_from_str(::std::string str) { - if (str == "block") - return BLOCK; + if (str == "block") + return BLOCK; else if (str == "expr") - return EXPR; + return EXPR; else if (str == "ident") - return IDENT; + return IDENT; else if (str == "item") - return ITEM; + return ITEM; else if (str == "lifetime") - return LIFETIME; + return LIFETIME; else if (str == "literal") - return LITERAL; + return LITERAL; else if (str == "meta") - return META; + return META; else if (str == "pat") - return PAT; + return PAT; else if (str == "path") - return PATH; + return PATH; else if (str == "stmt") - return STMT; + return STMT; else if (str == "tt") - return TT; + return TT; else if (str == "ty") - return TY; + return TY; else if (str == "vis") - return VIS; + return VIS; else { - //error_at("invalid string '%s' used as fragment specifier", str->c_str()); - return INVALID; + // error_at("invalid string '%s' used as fragment specifier", str->c_str()); + return INVALID; } } @@ -64,6 +64,8 @@ namespace Rust { Identifier ident; MacroFragSpec frag_spec; + // TODO: should store location information? + public: MacroMatchFragment(Identifier ident, MacroFragSpec frag_spec) : ident(::std::move(ident)), frag_spec(frag_spec) {} @@ -80,6 +82,8 @@ namespace Rust { ::std::string as_string() const; + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual MacroMatchFragment* clone_macro_match_impl() const OVERRIDE { @@ -102,16 +106,18 @@ namespace Rust { // any token except delimiters and repetition operators ::std::unique_ptr<MacroRepSep> sep; + // TODO: should store location information? + public: // Returns whether macro match repetition has separator token. inline bool has_sep() const { return sep != NULL; } - MacroMatchRepetition(::std::vector< ::std::unique_ptr<MacroMatch> > matches, MacroRepOp op, - MacroRepSep* sep) : + MacroMatchRepetition(::std::vector< ::std::unique_ptr<MacroMatch> > matches, + MacroRepOp op, ::std::unique_ptr<MacroRepSep> sep) : matches(::std::move(matches)), - op(op), sep(sep) {} + op(op), sep(::std::move(sep)) {} // Copy constructor with clone MacroMatchRepetition(MacroMatchRepetition const& other) : @@ -148,6 +154,8 @@ namespace Rust { ::std::string as_string() const; + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual MacroMatchRepetition* clone_macro_match_impl() const OVERRIDE { @@ -164,6 +172,8 @@ namespace Rust { // TODO: think of way to mark invalid that doesn't take up more space bool is_invalid; + // TODO: should store location information? + public: MacroMatcher( DelimType delim_type, ::std::vector< ::std::unique_ptr<MacroMatch> > matches) : @@ -210,6 +220,8 @@ namespace Rust { ::std::string as_string() const; + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual MacroMatcher* clone_macro_match_impl() const OVERRIDE { @@ -225,8 +237,14 @@ namespace Rust { private: DelimTokenTree token_tree; + // TODO: should store location information? + public: MacroTranscriber(DelimTokenTree token_tree) : token_tree(::std::move(token_tree)) {} + + ::std::string as_string() const { + return token_tree.as_string(); + } }; // A macro rule? Matcher and transcriber pair? @@ -235,6 +253,8 @@ namespace Rust { MacroMatcher matcher; MacroTranscriber transcriber; + // TODO: should store location information? + public: MacroRule(MacroMatcher matcher, MacroTranscriber transcriber) : matcher(::std::move(matcher)), transcriber(::std::move(transcriber)) {} @@ -249,6 +269,8 @@ namespace Rust { return MacroRule( MacroMatcher::create_error(), MacroTranscriber(DelimTokenTree::create_empty())); } + + ::std::string as_string() const; }; // A macro rules definition item AST node @@ -260,13 +282,19 @@ namespace Rust { // MacroRules rules; ::std::vector<MacroRule> rules; // inlined form + location_t locus; + public: ::std::string as_string() const; MacroRulesDefinition(Identifier rule_name, DelimType delim_type, - ::std::vector<MacroRule> rules, ::std::vector<Attribute> outer_attrs) : - MacroItem(::std::move(outer_attrs)), rule_name(::std::move(rule_name)), - delim_type(delim_type), rules(::std::move(rules)) {} + ::std::vector<MacroRule> rules, ::std::vector<Attribute> outer_attrs, + location_t locus) : + MacroItem(::std::move(outer_attrs)), + rule_name(::std::move(rule_name)), delim_type(delim_type), rules(::std::move(rules)), + locus(locus) {} + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; protected: // Use covariance to implement clone function as returning this object rather than base @@ -283,13 +311,25 @@ namespace Rust { SimplePath path; DelimTokenTree token_tree; + location_t locus; + public: ::std::string as_string() const; - MacroInvocation( - SimplePath path, DelimTokenTree token_tree, ::std::vector<Attribute> outer_attrs) : - ExprWithoutBlock(::std::move(outer_attrs)), path(::std::move(path)), - token_tree(::std::move(token_tree)) {} + MacroInvocation(SimplePath path, DelimTokenTree token_tree, + ::std::vector<Attribute> outer_attrs, location_t locus) : + ExprWithoutBlock(::std::move(outer_attrs)), + path(::std::move(path)), token_tree(::std::move(token_tree)), locus(locus) {} + + location_t get_locus() const { + return locus; + } + + location_t get_locus_slow() const OVERRIDE { + return get_locus(); + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; protected: // Use covariance to implement clone function as returning this object rather than base @@ -317,6 +357,231 @@ namespace Rust { return new MacroInvocation(*this); } }; + + // more generic meta item path-only form + class MetaItemPath : public MetaItem { + SimplePath path; + + public: + MetaItemPath(SimplePath path) : path(::std::move(path)) {} + + ::std::string as_string() const OVERRIDE { + return path.as_string(); + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + + // HACK: used to simplify parsing - returns non-empty only in this case + virtual SimplePath to_path_item() const OVERRIDE { + // this should copy construct - TODO ensure it does + return path; + } + + virtual bool check_cfg_predicate(const Session& session) const OVERRIDE; + + protected: + // Use covariance to implement clone function as returning this type + virtual MetaItemPath* clone_meta_item_inner_impl() const OVERRIDE { + return new MetaItemPath(*this); + } + }; + + // more generic meta item sequence form + class MetaItemSeq : public MetaItem { + SimplePath path; + ::std::vector< ::std::unique_ptr<MetaItemInner> > seq; + + public: + MetaItemSeq(SimplePath path, ::std::vector< ::std::unique_ptr<MetaItemInner> > seq) : + path(::std::move(path)), seq(::std::move(seq)) {} + + // copy constructor with vector clone + MetaItemSeq(const MetaItemSeq& other) : path(other.path) { + // crappy vector unique pointer clone - TODO is there a better way of doing this? + seq.reserve(other.seq.size()); + + for (const auto& e : other.seq) { + seq.push_back(e->clone_meta_item_inner()); + } + } + + // destructor definition not required + + // overloaded assignment operator with vector clone + MetaItemSeq& operator=(const MetaItemSeq& other) { + MetaItem::operator=(other); + path = other.path; + // crappy vector unique pointer clone - TODO is there a better way of doing this? + seq.reserve(other.seq.size()); + + for (const auto& e : other.seq) { + seq.push_back(e->clone_meta_item_inner()); + } + + return *this; + } + + // default move constructors + MetaItemSeq(MetaItemSeq&& other) = default; + MetaItemSeq& operator=(MetaItemSeq&& other) = default; + + ::std::string as_string() const OVERRIDE; + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + + virtual bool check_cfg_predicate(const Session& session) const OVERRIDE; + + protected: + // Use covariance to implement clone function as returning this type + virtual MetaItemSeq* clone_meta_item_inner_impl() const OVERRIDE { + return new MetaItemSeq(*this); + } + }; + + // Preferred specialisation for single-identifier meta items. + class MetaWord : public MetaItem { + Identifier ident; + + public: + MetaWord(Identifier ident) : ident(::std::move(ident)) {} + + ::std::string as_string() const OVERRIDE { + return ident; + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + + virtual bool check_cfg_predicate(const Session& session) const OVERRIDE; + + protected: + // Use covariance to implement clone function as returning this type + virtual MetaWord* clone_meta_item_inner_impl() const OVERRIDE { + return new MetaWord(*this); + } + }; + + // Preferred specialisation for "identifier '=' string literal" meta items. + class MetaNameValueStr : public MetaItem { + Identifier ident; + ::std::string str; + + public: + MetaNameValueStr(Identifier ident, ::std::string str) : + ident(::std::move(ident)), str(::std::move(str)) {} + + ::std::string as_string() const OVERRIDE { + return ident + " = " + str; + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + + // HACK: used to simplify parsing - creates a copy of this + virtual MetaNameValueStr* to_meta_name_value_str() const OVERRIDE { + return clone_meta_item_inner_impl(); + } + + virtual bool check_cfg_predicate(const Session& session) const OVERRIDE; + + protected: + // Use covariance to implement clone function as returning this type + virtual MetaNameValueStr* clone_meta_item_inner_impl() const OVERRIDE { + return new MetaNameValueStr(*this); + } + }; + + // doubles up as MetaListIdents - determine via iterating through each path? + // Preferred specialisation for "identifier '(' SimplePath, SimplePath, ... ')'" + class MetaListPaths : public MetaItem { + Identifier ident; + ::std::vector<SimplePath> paths; + + public: + MetaListPaths(Identifier ident, ::std::vector<SimplePath> paths) : + ident(::std::move(ident)), paths(::std::move(paths)) {} + + ::std::string as_string() const OVERRIDE; + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + + virtual bool check_cfg_predicate(const Session& session) const OVERRIDE; + + private: + bool check_path_exists_in_cfg(const Session& session, const SimplePath& path) const; + + protected: + // Use covariance to implement clone function as returning this type + virtual MetaListPaths* clone_meta_item_inner_impl() const OVERRIDE { + return new MetaListPaths(*this); + } + }; + + // Preferred specialisation for "identifier '(' MetaNameValueStr, ... ')'" + class MetaListNameValueStr : public MetaItem { + Identifier ident; + ::std::vector<MetaNameValueStr> strs; + + public: + MetaListNameValueStr(Identifier ident, ::std::vector<MetaNameValueStr> strs) : + ident(::std::move(ident)), strs(::std::move(strs)) {} + + ::std::string as_string() const OVERRIDE; + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + + virtual bool check_cfg_predicate(const Session& session) const OVERRIDE; + + protected: + // Use covariance to implement clone function as returning this type + virtual MetaListNameValueStr* clone_meta_item_inner_impl() const OVERRIDE { + return new MetaListNameValueStr(*this); + } + }; + + // Object that parses macros from a token stream. + struct MacroParser { + private: + ::std::vector< ::std::unique_ptr<Token> > token_stream; + // probably have to make this mutable (mutable int stream_pos) otherwise const has to be + // removed up to DelimTokenTree or further ok since this changing would have an effect on + // the results of the methods run (i.e. not logically const), the parsing methods + // shouldn't be const + int stream_pos; + + public: + MacroParser( + ::std::vector< ::std::unique_ptr<Token> > token_stream, int stream_start_pos = 0) : + token_stream(::std::move(token_stream)), + stream_pos(stream_start_pos) {} + + ~MacroParser() = default; + + ::std::vector< ::std::unique_ptr<MetaItemInner> > parse_meta_item_seq(); + + private: + // Parses a MetaItemInner. + ::std::unique_ptr<MetaItemInner> parse_meta_item_inner(); + // Returns whether token can end a meta item. + bool is_end_meta_item_tok(TokenId id) const; + // Parses a simple path. + SimplePath parse_simple_path(); + // Parses a segment of a simple path (but not scope resolution operator). + SimplePathSegment parse_simple_path_segment(); + // Parses a MetaItemLitExpr. + ::std::unique_ptr<MetaItemLitExpr> parse_meta_item_lit(); + // Parses a literal. + Literal parse_literal(); + // Parses a meta item that begins with a simple path. + ::std::unique_ptr<MetaItem> parse_path_meta_item(); + + // TODO: should this be const? + ::std::unique_ptr<Token>& peek_token(int i = 0) { + return token_stream[stream_pos + i]; + } + + void skip_token(int i = 0) { + stream_pos += 1 + i; + } + }; } } diff --git a/gcc/rust/test3/ast/rust-path.h b/gcc/rust/test3/ast/rust-path.h index 1aba847..cddd062 100644 --- a/gcc/rust/test3/ast/rust-path.h +++ b/gcc/rust/test3/ast/rust-path.h @@ -20,6 +20,8 @@ namespace Rust { class PathIdentSegment { ::std::string segment_name; + // TODO: should this have location info stored? + // only allow identifiers, "super", "self", "Self", "crate", or "$crate" public: PathIdentSegment(::std::string segment_name) : segment_name(::std::move(segment_name)) {} @@ -27,6 +29,8 @@ namespace Rust { /* TODO: insert check in constructor for this? Or is this a semantic error best handled * then? */ + // TODO: does this require visitor. pretty sure this isn't polymorphic, but not entirely sure + // Creates an error PathIdentSegment. static PathIdentSegment create_error() { return PathIdentSegment(""); @@ -49,6 +53,8 @@ namespace Rust { // Type type; ::std::unique_ptr<Type> type; + location_t locus; + public: // Returns whether binding is in an error state. inline bool is_error() const { @@ -61,12 +67,14 @@ namespace Rust { } // Pointer type for type in constructor to enable polymorphism - GenericArgsBinding(Identifier ident, Type* type_ptr) : - identifier(::std::move(ident)), type(type_ptr) {} + GenericArgsBinding(Identifier ident, ::std::unique_ptr<Type> type_ptr, + location_t locus = UNKNOWN_LOCATION) : + identifier(::std::move(ident)), + type(::std::move(type_ptr)), locus(locus) {} // Copy constructor has to deep copy the type as it is a unique pointer GenericArgsBinding(GenericArgsBinding const& other) : - identifier(other.identifier), type(other.type->clone_type()) {} + identifier(other.identifier), type(other.type->clone_type()), locus(other.locus) {} // default destructor ~GenericArgsBinding() = default; @@ -75,12 +83,15 @@ namespace Rust { GenericArgsBinding& operator=(GenericArgsBinding const& other) { identifier = other.identifier; type = other.type->clone_type(); + locus = other.locus; return *this; } // move constructors GenericArgsBinding(GenericArgsBinding&& other) = default; GenericArgsBinding& operator=(GenericArgsBinding&& other) = default; + + ::std::string as_string() const; }; // Generic arguments allowed in each path expression segment - inline? @@ -90,6 +101,8 @@ namespace Rust { ::std::vector< ::std::unique_ptr<Type> > type_args; ::std::vector<GenericArgsBinding> binding_args; + location_t locus; + public: // Returns true if there are any generic arguments inline bool has_generic_args() const { @@ -98,13 +111,15 @@ namespace Rust { GenericArgs(::std::vector<Lifetime> lifetime_args, ::std::vector< ::std::unique_ptr<Type> > type_args, - ::std::vector<GenericArgsBinding> binding_args) : + ::std::vector<GenericArgsBinding> binding_args, location_t locus = UNKNOWN_LOCATION) : lifetime_args(::std::move(lifetime_args)), - type_args(::std::move(type_args)), binding_args(::std::move(binding_args)) {} + type_args(::std::move(type_args)), binding_args(::std::move(binding_args)), + locus(locus) {} // copy constructor with vector clone GenericArgs(GenericArgs const& other) : - lifetime_args(other.lifetime_args), binding_args(other.binding_args) { + lifetime_args(other.lifetime_args), binding_args(other.binding_args), + locus(other.locus) { // crappy vector unique pointer clone - TODO is there a better way of doing this? type_args.reserve(other.type_args.size()); @@ -119,6 +134,7 @@ namespace Rust { GenericArgs& operator=(GenericArgs const& other) { lifetime_args = other.lifetime_args; binding_args = other.binding_args; + locus = other.locus; // crappy vector unique pointer clone - TODO is there a better way of doing this? type_args.reserve(other.type_args.size()); @@ -151,6 +167,10 @@ namespace Rust { // bool has_generic_args; GenericArgs generic_args; + location_t locus; + + // TODO: does this require visitor? pretty sure not polymorphic + public: // Returns true if there are any generic arguments inline bool has_generic_args() const { @@ -158,20 +178,21 @@ namespace Rust { } // Constructor for segment (from IdentSegment and GenericArgs) - PathExprSegment( - PathIdentSegment segment_name, GenericArgs generic_args = GenericArgs::create_empty()) : + PathExprSegment(PathIdentSegment segment_name, location_t locus = UNKNOWN_LOCATION, + GenericArgs generic_args = GenericArgs::create_empty()) : segment_name(::std::move(segment_name)), - generic_args(::std::move(generic_args)) {} + generic_args(::std::move(generic_args)), locus(locus) {} // Constructor for segment with generic arguments (from segment name and all args) - PathExprSegment(::std::string segment_name, + PathExprSegment(::std::string segment_name, location_t locus, ::std::vector<Lifetime> lifetime_args = ::std::vector<Lifetime>(), ::std::vector< ::std::unique_ptr<Type> > type_args = ::std::vector< ::std::unique_ptr<Type> >(), ::std::vector<GenericArgsBinding> binding_args = ::std::vector<GenericArgsBinding>()) : segment_name(PathIdentSegment(::std::move(segment_name))), generic_args(GenericArgs( - ::std::move(lifetime_args), ::std::move(type_args), ::std::move(binding_args))) {} + ::std::move(lifetime_args), ::std::move(type_args), ::std::move(binding_args))), + locus(locus) {} // Returns whether path expression segment is in an error state. inline bool is_error() const { @@ -184,6 +205,10 @@ namespace Rust { } ::std::string as_string() const; + + inline location_t get_locus() const { + return locus; + } }; // AST node representing a pattern that involves a "path" - abstract base class @@ -208,20 +233,28 @@ namespace Rust { inline bool is_single_segment() const { return segments.size() == 1; } + + virtual ::std::string as_string() const; }; // AST node representing a path-in-expression pattern (path that allows generic arguments) - class PathInExpression : public PathPattern { + class PathInExpression + : public PathPattern + , public PathExpr { bool has_opening_scope_resolution; + location_t locus; + public: ::std::string as_string() const; // Constructor PathInExpression(::std::vector<PathExprSegment> path_segments, - bool has_opening_scope_resolution = false) : + location_t locus = UNKNOWN_LOCATION, bool has_opening_scope_resolution = false, + ::std::vector<Attribute> outer_attrs = ::std::vector<Attribute>()) : PathPattern(::std::move(path_segments)), - has_opening_scope_resolution(has_opening_scope_resolution) {} + PathExpr(::std::move(outer_attrs)), + has_opening_scope_resolution(has_opening_scope_resolution), locus(locus) {} // Creates an error state path in expression. static PathInExpression create_error() { @@ -243,11 +276,26 @@ namespace Rust { return convert_to_simple_path(has_opening_scope_resolution); } + location_t get_locus() const { + return locus; + } + + location_t get_locus_slow() const OVERRIDE { + return get_locus(); + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual PathInExpression* clone_pattern_impl() const OVERRIDE { return new PathInExpression(*this); } + + // Use covariance to implement clone function as returning this object rather than base + virtual PathInExpression* clone_expr_without_block_impl() const OVERRIDE { + return new PathInExpression(*this); + } }; // Base class for segments used in type paths - not abstract (represents an ident-only @@ -259,6 +307,8 @@ namespace Rust { * so could disallow that in constructor, which won't give that much size overhead. */ PathIdentSegment ident_segment; + location_t locus; + protected: // This is protected because it is only really used by derived classes, not the base. bool has_separating_scope_resolution; @@ -276,13 +326,15 @@ namespace Rust { return ::std::unique_ptr<TypePathSegment>(clone_type_path_segment_impl()); } - TypePathSegment(PathIdentSegment ident_segment, bool has_separating_scope_resolution) : + TypePathSegment(PathIdentSegment ident_segment, bool has_separating_scope_resolution, + location_t locus) : ident_segment(::std::move(ident_segment)), - has_separating_scope_resolution(has_separating_scope_resolution) {} + locus(locus), has_separating_scope_resolution(has_separating_scope_resolution) {} - TypePathSegment(::std::string segment_name, bool has_separating_scope_resolution) : + TypePathSegment( + ::std::string segment_name, bool has_separating_scope_resolution, location_t locus) : ident_segment(PathIdentSegment(::std::move(segment_name))), - has_separating_scope_resolution(has_separating_scope_resolution) {} + locus(locus), has_separating_scope_resolution(has_separating_scope_resolution) {} virtual ::std::string as_string() const { return ident_segment.as_string(); @@ -293,11 +345,18 @@ namespace Rust { return ident_segment.is_error(); } - /* Returns whether segment is identifier only (as opposed to generic args or function). + /* Returns whether segment is identifier only (as opposed to generic args or function). Overriden in derived classes with other segments. */ virtual bool is_ident_only() const { return true; } + + inline bool get_locus() const { + return locus; + } + + // not pure virtual as class not abstract + virtual void accept_vis(ASTVisitor& vis); }; // Segment used in type path with generic args @@ -315,21 +374,23 @@ namespace Rust { // Constructor with PathIdentSegment and GenericArgs TypePathSegmentGeneric(PathIdentSegment ident_segment, - bool has_separating_scope_resolution, GenericArgs generic_args) : - TypePathSegment(::std::move(ident_segment), has_separating_scope_resolution), + bool has_separating_scope_resolution, GenericArgs generic_args, location_t locus) : + TypePathSegment(::std::move(ident_segment), has_separating_scope_resolution, locus), generic_args(::std::move(generic_args)) {} // Constructor from segment name and all args TypePathSegmentGeneric(::std::string segment_name, bool has_separating_scope_resolution, ::std::vector<Lifetime> lifetime_args, ::std::vector< ::std::unique_ptr<Type> > type_args, - ::std::vector<GenericArgsBinding> binding_args) : - TypePathSegment(::std::move(segment_name), has_separating_scope_resolution), + ::std::vector<GenericArgsBinding> binding_args, location_t locus) : + TypePathSegment(::std::move(segment_name), has_separating_scope_resolution, locus), generic_args(GenericArgs( ::std::move(lifetime_args), ::std::move(type_args), ::std::move(binding_args))) {} ::std::string as_string() const; + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to override base class method virtual TypePathSegmentGeneric* clone_type_path_segment_impl() const OVERRIDE { @@ -353,6 +414,8 @@ namespace Rust { // FIXME: think of better way to mark as invalid than taking up storage bool is_invalid; + // TODO: should this have location info? + protected: // Constructor only used to create invalid type path functions. TypePathFunction(bool is_invalid) : is_invalid(is_invalid) {} @@ -381,6 +444,13 @@ namespace Rust { // Constructor TypePathFunction(::std::vector< ::std::unique_ptr<Type> > inputs, Type* type = NULL) : inputs(::std::move(inputs)), return_type(type), is_invalid(false) {} + // FIXME: deprecated + + // Constructor + TypePathFunction( + ::std::vector< ::std::unique_ptr<Type> > inputs, ::std::unique_ptr<Type> type = NULL) : + inputs(::std::move(inputs)), + return_type(::std::move(type)), is_invalid(false) {} // Copy constructor with clone TypePathFunction(TypePathFunction const& other) : @@ -415,6 +485,8 @@ namespace Rust { // move constructors TypePathFunction(TypePathFunction&& other) = default; TypePathFunction& operator=(TypePathFunction&& other) = default; + + ::std::string as_string() const; }; // Segment used in type path with a function argument @@ -424,14 +496,15 @@ namespace Rust { public: // Constructor with PathIdentSegment and TypePathFn TypePathSegmentFunction(PathIdentSegment ident_segment, - bool has_separating_scope_resolution, TypePathFunction function_path) : - TypePathSegment(::std::move(ident_segment), has_separating_scope_resolution), + bool has_separating_scope_resolution, TypePathFunction function_path, + location_t locus) : + TypePathSegment(::std::move(ident_segment), has_separating_scope_resolution, locus), function_path(::std::move(function_path)) {} // Constructor with segment name and TypePathFn TypePathSegmentFunction(::std::string segment_name, bool has_separating_scope_resolution, - TypePathFunction function_path) : - TypePathSegment(::std::move(segment_name), has_separating_scope_resolution), + TypePathFunction function_path, location_t locus) : + TypePathSegment(::std::move(segment_name), has_separating_scope_resolution, locus), function_path(::std::move(function_path)) {} ::std::string as_string() const; @@ -440,6 +513,8 @@ namespace Rust { return false; } + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to override base class method virtual TypePathSegmentFunction* clone_type_path_segment_impl() const OVERRIDE { @@ -452,6 +527,8 @@ namespace Rust { bool has_opening_scope_resolution; ::std::vector< ::std::unique_ptr<TypePathSegment> > segments; + location_t locus; + protected: // Use covariance to implement clone function as returning this object rather than base virtual TypePath* clone_type_impl() const OVERRIDE { @@ -482,13 +559,13 @@ namespace Rust { // Constructor TypePath(::std::vector< ::std::unique_ptr<TypePathSegment> > segments, - bool has_opening_scope_resolution = false) : + location_t locus = UNKNOWN_LOCATION, bool has_opening_scope_resolution = false) : has_opening_scope_resolution(has_opening_scope_resolution), - segments(::std::move(segments)) {} + segments(::std::move(segments)), locus(locus) {} // Copy constructor with vector clone TypePath(TypePath const& other) : - has_opening_scope_resolution(other.has_opening_scope_resolution) { + has_opening_scope_resolution(other.has_opening_scope_resolution), locus(other.locus) { // crappy vector unique pointer clone - TODO is there a better way of doing this? segments.reserve(other.segments.size()); @@ -500,6 +577,7 @@ namespace Rust { // Overloaded assignment operator with clone TypePath& operator=(TypePath const& other) { has_opening_scope_resolution = other.has_opening_scope_resolution; + locus = other.locus; // crappy vector unique pointer clone - TODO is there a better way of doing this? segments.reserve(other.segments.size()); @@ -521,8 +599,14 @@ namespace Rust { * Otherwise returns an empty SimplePath. */ SimplePath as_simple_path() const; - // Creates a trait bound with a clone of this type path as its only element. + // Creates a trait bound with a clone of this type path as its only element. virtual TraitBound* to_trait_bound(bool in_parens) const OVERRIDE; + + location_t get_locus() const { + return locus; + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; }; struct QualifiedPathType { @@ -533,15 +617,19 @@ namespace Rust { // bool has_as_clause; TypePath trait_path; + location_t locus; + public: // Constructor - QualifiedPathType(Type* invoke_on_type, TypePath trait_path = TypePath::create_error()) : - type_to_invoke_on(invoke_on_type), trait_path(::std::move(trait_path)) {} + QualifiedPathType(::std::unique_ptr<Type> invoke_on_type, + location_t locus = UNKNOWN_LOCATION, TypePath trait_path = TypePath::create_error()) : + type_to_invoke_on(::std::move(invoke_on_type)), + trait_path(::std::move(trait_path)), locus(locus) {} // Copy constructor uses custom deep copy for Type to preserve polymorphism QualifiedPathType(QualifiedPathType const& other) : - type_to_invoke_on(other.type_to_invoke_on->clone_type()), trait_path(other.trait_path) { - } + type_to_invoke_on(other.type_to_invoke_on->clone_type()), trait_path(other.trait_path), + locus(other.locus) {} // default destructor ~QualifiedPathType() = default; @@ -550,6 +638,7 @@ namespace Rust { QualifiedPathType& operator=(QualifiedPathType const& other) { type_to_invoke_on = other.type_to_invoke_on->clone_type(); trait_path = other.trait_path; + locus = other.locus; return *this; } @@ -571,19 +660,32 @@ namespace Rust { static QualifiedPathType create_error() { return QualifiedPathType(NULL); } + + ::std::string as_string() const; + + inline location_t get_locus() const { + return locus; + } }; /* AST node representing a qualified path-in-expression pattern (path that allows specifying * trait functions) */ - class QualifiedPathInExpression : public PathPattern { + class QualifiedPathInExpression + : public PathPattern + , public PathExpr { QualifiedPathType path_type; + location_t locus; + public: ::std::string as_string() const; - QualifiedPathInExpression( - QualifiedPathType qual_path_type, ::std::vector<PathExprSegment> path_segments) : - PathPattern(::std::move(path_segments)), path_type(::std::move(qual_path_type)) {} + QualifiedPathInExpression(QualifiedPathType qual_path_type, + ::std::vector<PathExprSegment> path_segments, location_t locus = UNKNOWN_LOCATION, + ::std::vector<Attribute> outer_attrs = ::std::vector<Attribute>()) : + PathPattern(::std::move(path_segments)), + PathExpr(::std::move(outer_attrs)), path_type(::std::move(qual_path_type)), + locus(locus) {} // TODO: maybe make a shortcut constructor that has QualifiedPathType elements as params @@ -600,11 +702,26 @@ namespace Rust { QualifiedPathType::create_error(), ::std::vector<PathExprSegment>()); } + location_t get_locus() const { + return locus; + } + + location_t get_locus_slow() const OVERRIDE { + return get_locus(); + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual QualifiedPathInExpression* clone_pattern_impl() const OVERRIDE { return new QualifiedPathInExpression(*this); } + + // Use covariance to implement clone function as returning this object rather than base + virtual QualifiedPathInExpression* clone_expr_without_block_impl() const OVERRIDE { + return new QualifiedPathInExpression(*this); + } }; // Represents a qualified path in a type; used for disambiguating trait function calls @@ -613,6 +730,8 @@ namespace Rust { // ::std::vector<TypePathSegment> segments; ::std::vector< ::std::unique_ptr<TypePathSegment> > segments; + location_t locus; + protected: // Use covariance to implement clone function as returning this object rather than base virtual QualifiedPathInType* clone_type_impl() const OVERRIDE { @@ -626,14 +745,16 @@ namespace Rust { public: QualifiedPathInType(QualifiedPathType qual_path_type, - ::std::vector< ::std::unique_ptr<TypePathSegment> > path_segments) : + ::std::vector< ::std::unique_ptr<TypePathSegment> > path_segments, + location_t locus = UNKNOWN_LOCATION) : path_type(::std::move(qual_path_type)), - segments(::std::move(path_segments)) {} + segments(::std::move(path_segments)), locus(locus) {} // TODO: maybe make a shortcut constructor that has QualifiedPathType elements as params // Copy constructor with vector clone - QualifiedPathInType(QualifiedPathInType const& other) : path_type(other.path_type) { + QualifiedPathInType(QualifiedPathInType const& other) : + path_type(other.path_type), locus(other.locus) { // crappy vector unique pointer clone - TODO is there a better way of doing this? segments.reserve(other.segments.size()); @@ -645,6 +766,7 @@ namespace Rust { // Overloaded assignment operator with vector clone QualifiedPathInType& operator=(QualifiedPathInType const& other) { path_type = other.path_type; + locus = other.locus; // crappy vector unique pointer clone - TODO is there a better way of doing this? segments.reserve(other.segments.size()); @@ -672,6 +794,8 @@ namespace Rust { } ::std::string as_string() const; + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; }; } } diff --git a/gcc/rust/test3/ast/rust-pattern.h b/gcc/rust/test3/ast/rust-pattern.h index fae7a57..f0cabee 100644 --- a/gcc/rust/test3/ast/rust-pattern.h +++ b/gcc/rust/test3/ast/rust-pattern.h @@ -15,15 +15,25 @@ namespace Rust { bool has_minus; // Actually, this might be a good place to use a template. + location_t locus; + public: ::std::string as_string() const; // Constructor for a literal pattern - LiteralPattern(Literal lit, bool has_minus = false) : - lit(::std::move(lit)), has_minus(has_minus) {} + LiteralPattern(Literal lit, location_t locus, bool has_minus = false) : + lit(::std::move(lit)), has_minus(has_minus), locus(locus) {} + + LiteralPattern( + ::std::string val, Literal::LitType type, location_t locus, bool has_minus = false) : + lit(Literal(::std::move(val), type)), + has_minus(has_minus), locus(locus) {} + + location_t get_locus() const { + return locus; + } - LiteralPattern(::std::string val, Literal::LitType type, bool has_minus = false) : - lit(Literal(::std::move(val), type)), has_minus(has_minus) {} + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; protected: // Use covariance to implement clone function as returning this object rather than base @@ -42,6 +52,8 @@ namespace Rust { // Pattern* to_bind; ::std::unique_ptr<Pattern> to_bind; + location_t locus; + public: /*~IdentifierPattern() { delete to_bind; @@ -55,15 +67,20 @@ namespace Rust { } // Constructor - IdentifierPattern( - Identifier ident, bool is_ref = false, bool is_mut = false, Pattern* to_bind = NULL) : + IdentifierPattern(Identifier ident, location_t locus, bool is_ref = false, + bool is_mut = false, ::std::unique_ptr<Pattern> to_bind = NULL) : variable_ident(::std::move(ident)), - is_ref(is_ref), is_mut(is_mut), to_bind(to_bind) {} + is_ref(is_ref), is_mut(is_mut), to_bind(::std::move(to_bind)), locus(locus) {} // Copy constructor with clone IdentifierPattern(IdentifierPattern const& other) : variable_ident(other.variable_ident), is_ref(other.is_ref), is_mut(other.is_mut), - to_bind(other.to_bind->clone_pattern()) {} + locus(other.locus) { + // fix to get prevent null pointer dereference + if (other.to_bind != NULL) { + to_bind = other.to_bind->clone_pattern(); + } + } // Destructor - define here if required @@ -72,7 +89,11 @@ namespace Rust { variable_ident = other.variable_ident; is_ref = other.is_ref; is_mut = other.is_mut; - to_bind = other.to_bind->clone_pattern(); + locus = other.locus; + // fix to get prevent null pointer dereference + if (other.to_bind != NULL) { + to_bind = other.to_bind->clone_pattern(); + } return *this; } @@ -81,6 +102,12 @@ namespace Rust { IdentifierPattern(IdentifierPattern&& other) = default; IdentifierPattern& operator=(IdentifierPattern&& other) = default; + location_t get_locus() const { + return locus; + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual IdentifierPattern* clone_pattern_impl() const OVERRIDE { @@ -90,12 +117,20 @@ namespace Rust { // AST node for using the '_' wildcard "match any value" pattern class WildcardPattern : public Pattern { + location_t locus; + public: ::std::string as_string() const { return ::std::string(1, '_'); } - WildcardPattern() {} + WildcardPattern(location_t locus) : locus(locus) {} + + location_t get_locus() const { + return locus; + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; protected: // Use covariance to implement clone function as returning this object rather than base @@ -122,6 +157,10 @@ namespace Rust { return ::std::unique_ptr<RangePatternBound>(clone_range_pattern_bound_impl()); } + virtual ::std::string as_string() const = 0; + + virtual void accept_vis(ASTVisitor& vis) = 0; + protected: // pure virtual as RangePatternBound is abstract virtual RangePatternBound* clone_range_pattern_bound_impl() const = 0; @@ -135,10 +174,20 @@ namespace Rust { // Minus prefixed to literal (if integer or floating-point) bool has_minus; + location_t locus; + public: // Constructor - RangePatternBoundLiteral(Literal literal, bool has_minus = false) : - literal(literal), has_minus(has_minus) {} + RangePatternBoundLiteral(Literal literal, location_t locus, bool has_minus = false) : + literal(literal), has_minus(has_minus), locus(locus) {} + + ::std::string as_string() const; + + location_t get_locus() const { + return locus; + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; protected: // Use covariance to implement clone function as returning this object rather than base @@ -151,9 +200,22 @@ namespace Rust { class RangePatternBoundPath : public RangePatternBound { PathInExpression path; + // TODO: should this be refactored so that PathInExpression is a subclass of + // RangePatternBound? + public: RangePatternBoundPath(PathInExpression path) : path(::std::move(path)) {} + ::std::string as_string() const { + return path.as_string(); + } + + location_t get_locus() const { + return path.get_locus(); + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual RangePatternBoundPath* clone_range_pattern_bound_impl() const OVERRIDE { @@ -165,9 +227,22 @@ namespace Rust { class RangePatternBoundQualPath : public RangePatternBound { QualifiedPathInExpression path; + /* TODO: should this be refactored so that QualifiedPathInExpression is a subclass of + * RangePatternBound? */ + public: RangePatternBoundQualPath(QualifiedPathInExpression path) : path(::std::move(path)) {} + ::std::string as_string() const { + return path.as_string(); + } + + location_t get_locus() const { + return path.get_locus(); + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual RangePatternBoundQualPath* clone_range_pattern_bound_impl() const OVERRIDE { @@ -184,20 +259,25 @@ namespace Rust { bool has_ellipsis_syntax; + // location only stored to avoid a dereference - lower pattern should give correct + // location so maybe change in future + location_t locus; + public: ::std::string as_string() const; // Constructor - RangePattern( - RangePatternBound* lower, RangePatternBound* upper, bool has_ellipsis_syntax = false) : - lower(lower), - upper(upper), has_ellipsis_syntax(has_ellipsis_syntax) {} + RangePattern(::std::unique_ptr<RangePatternBound> lower, + ::std::unique_ptr<RangePatternBound> upper, location_t locus, + bool has_ellipsis_syntax = false) : + lower(::std::move(lower)), + upper(::std::move(upper)), has_ellipsis_syntax(has_ellipsis_syntax), locus(locus) {} // Copy constructor with clone RangePattern(RangePattern const& other) : lower(other.lower->clone_range_pattern_bound()), upper(other.upper->clone_range_pattern_bound()), - has_ellipsis_syntax(other.has_ellipsis_syntax) {} + has_ellipsis_syntax(other.has_ellipsis_syntax), locus(other.locus) {} // Destructor - define here if required @@ -206,6 +286,7 @@ namespace Rust { lower = other.lower->clone_range_pattern_bound(); upper = other.upper->clone_range_pattern_bound(); has_ellipsis_syntax = other.has_ellipsis_syntax; + locus = other.locus; return *this; } @@ -214,6 +295,12 @@ namespace Rust { RangePattern(RangePattern&& other) = default; RangePattern& operator=(RangePattern&& other) = default; + location_t get_locus() const { + return locus; + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual RangePattern* clone_pattern_impl() const OVERRIDE { @@ -228,6 +315,8 @@ namespace Rust { // Pattern* pattern; ::std::unique_ptr<Pattern> pattern; + location_t locus; + public: /*~ReferencePattern() { delete pattern; @@ -235,13 +324,15 @@ namespace Rust { ::std::string as_string() const; - ReferencePattern(Pattern* pattern, bool is_mut_reference, bool ref_has_two_amps) : - has_two_amps(ref_has_two_amps), is_mut(is_mut_reference), pattern(pattern) {} + ReferencePattern(::std::unique_ptr<Pattern> pattern, bool is_mut_reference, + bool ref_has_two_amps, location_t locus) : + has_two_amps(ref_has_two_amps), + is_mut(is_mut_reference), pattern(::std::move(pattern)), locus(locus) {} // Copy constructor requires clone ReferencePattern(ReferencePattern const& other) : has_two_amps(other.has_two_amps), is_mut(other.is_mut), - pattern(other.pattern->clone_pattern()) {} + pattern(other.pattern->clone_pattern()), locus(other.locus) {} // Destructor - define here if required @@ -250,6 +341,7 @@ namespace Rust { pattern = other.pattern->clone_pattern(); is_mut = other.is_mut; has_two_amps = other.has_two_amps; + locus = other.locus; return *this; } @@ -258,6 +350,8 @@ namespace Rust { ReferencePattern(ReferencePattern&& other) = default; ReferencePattern& operator=(ReferencePattern&& other) = default; + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual ReferencePattern* clone_pattern_impl() const OVERRIDE { @@ -270,6 +364,8 @@ namespace Rust { private: ::std::vector<Attribute> outer_attrs; + // should this store location data? + public: StructPatternEtc(::std::vector<Attribute> outer_attribs) : outer_attrs(::std::move(outer_attribs)) {} @@ -299,6 +395,8 @@ namespace Rust { } ident; } pattern;*/ + location_t locus; + public: virtual ~StructPatternField() {} @@ -307,9 +405,17 @@ namespace Rust { return ::std::unique_ptr<StructPatternField>(clone_struct_pattern_field_impl()); } + virtual ::std::string as_string() const; + + location_t get_locus() const { + return locus; + } + + virtual void accept_vis(ASTVisitor& vis) = 0; + protected: - StructPatternField(::std::vector<Attribute> outer_attribs) : - outer_attrs(::std::move(outer_attribs)) {} + StructPatternField(::std::vector<Attribute> outer_attribs, location_t locus) : + outer_attrs(::std::move(outer_attribs)), locus(locus) {} // Clone function implementation as pure virtual method virtual StructPatternField* clone_struct_pattern_field_impl() const = 0; @@ -326,10 +432,10 @@ namespace Rust { delete tuple_pattern; }*/ - StructPatternFieldTuplePat( - TupleIndex index, Pattern* tuple_pattern, ::std::vector<Attribute> outer_attribs) : - StructPatternField(::std::move(outer_attribs)), - index(index), tuple_pattern(tuple_pattern) {} + StructPatternFieldTuplePat(TupleIndex index, ::std::unique_ptr<Pattern> tuple_pattern, + ::std::vector<Attribute> outer_attribs, location_t locus) : + StructPatternField(::std::move(outer_attribs), locus), + index(index), tuple_pattern(::std::move(tuple_pattern)) {} // Copy constructor requires clone StructPatternFieldTuplePat(StructPatternFieldTuplePat const& other) : @@ -352,6 +458,10 @@ namespace Rust { StructPatternFieldTuplePat(StructPatternFieldTuplePat&& other) = default; StructPatternFieldTuplePat& operator=(StructPatternFieldTuplePat&& other) = default; + ::std::string as_string() const; + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual StructPatternFieldTuplePat* clone_struct_pattern_field_impl() const OVERRIDE { @@ -370,10 +480,10 @@ namespace Rust { delete ident_pattern; }*/ - StructPatternFieldIdentPat( - Identifier ident, Pattern* ident_pattern, ::std::vector<Attribute> outer_attrs) : - StructPatternField(::std::move(outer_attrs)), - ident(::std::move(ident)), ident_pattern(ident_pattern) {} + StructPatternFieldIdentPat(Identifier ident, ::std::unique_ptr<Pattern> ident_pattern, + ::std::vector<Attribute> outer_attrs, location_t locus) : + StructPatternField(::std::move(outer_attrs), locus), + ident(::std::move(ident)), ident_pattern(::std::move(ident_pattern)) {} // Copy constructor requires clone StructPatternFieldIdentPat(StructPatternFieldIdentPat const& other) : @@ -396,6 +506,10 @@ namespace Rust { StructPatternFieldIdentPat(StructPatternFieldIdentPat&& other) = default; StructPatternFieldIdentPat& operator=(StructPatternFieldIdentPat&& other) = default; + ::std::string as_string() const; + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual StructPatternFieldIdentPat* clone_struct_pattern_field_impl() const OVERRIDE { @@ -411,11 +525,15 @@ namespace Rust { Identifier ident; public: - StructPatternFieldIdent( - Identifier ident, bool is_ref, bool is_mut, ::std::vector<Attribute> outer_attrs) : - StructPatternField(::std::move(outer_attrs)), + StructPatternFieldIdent(Identifier ident, bool is_ref, bool is_mut, + ::std::vector<Attribute> outer_attrs, location_t locus) : + StructPatternField(::std::move(outer_attrs), locus), has_ref(is_ref), has_mut(is_mut), ident(::std::move(ident)) {} + ::std::string as_string() const; + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual StructPatternFieldIdent* clone_struct_pattern_field_impl() const OVERRIDE { @@ -435,12 +553,19 @@ namespace Rust { // must have at least one of the two and maybe both + // should this store location data? + public: // Returns whether there are any struct pattern fields inline bool has_struct_pattern_fields() const { return !fields.empty(); } + // Returns whether the struct pattern elements is entirely empty (no fields, no etc). + inline bool is_empty() const { + return !has_struct_pattern_fields() && !has_struct_pattern_etc; + } + // Constructor for StructPatternElements with both (potentially) StructPatternElements( ::std::vector< ::std::unique_ptr<StructPatternField> > fields, StructPatternEtc etc) : @@ -487,15 +612,19 @@ namespace Rust { return StructPatternElements( ::std::vector< ::std::unique_ptr<StructPatternField> >()); } + + ::std::string as_string() const; }; // Struct pattern AST node representation class StructPattern : public Pattern { PathInExpression path; - bool has_struct_pattern_elements; + // bool has_struct_pattern_elements; StructPatternElements elems; + // TODO: should this store location data? Accessor uses path location data. + public: ::std::string as_string() const; @@ -503,10 +632,21 @@ namespace Rust { StructPattern(PathInExpression struct_path, StructPatternElements elems = StructPatternElements::create_empty()) : path(::std::move(struct_path)), - has_struct_pattern_elements(true), elems(::std::move(elems)) {} + elems(::std::move(elems)) {} // TODO: constructor to construct via elements included in StructPatternElements + // Returns whether struct pattern has any struct pattern elements (if not, it is empty). + inline bool has_struct_pattern_elems() const { + return !elems.is_empty(); + } + + location_t get_locus() const { + return path.get_locus(); + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual StructPattern* clone_pattern_impl() const OVERRIDE { @@ -519,11 +659,17 @@ namespace Rust { public: virtual ~TupleStructItems() {} + // TODO: should this store location data? + // Unique pointer custom clone function ::std::unique_ptr<TupleStructItems> clone_tuple_struct_items() const { return ::std::unique_ptr<TupleStructItems>(clone_tuple_struct_items_impl()); } + virtual ::std::string as_string() const = 0; + + virtual void accept_vis(ASTVisitor& vis) = 0; + protected: // pure virtual clone implementation virtual TupleStructItems* clone_tuple_struct_items_impl() const = 0; @@ -564,6 +710,10 @@ namespace Rust { TupleStructItemsNoRange(TupleStructItemsNoRange&& other) = default; TupleStructItemsNoRange& operator=(TupleStructItemsNoRange&& other) = default; + ::std::string as_string() const; + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual TupleStructItemsNoRange* clone_tuple_struct_items_impl() const OVERRIDE { @@ -624,6 +774,10 @@ namespace Rust { TupleStructItemsRange(TupleStructItemsRange&& other) = default; TupleStructItemsRange& operator=(TupleStructItemsRange&& other) = default; + ::std::string as_string() const; + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual TupleStructItemsRange* clone_tuple_struct_items_impl() const OVERRIDE { @@ -637,11 +791,15 @@ namespace Rust { // TupleStructItems items; ::std::unique_ptr<TupleStructItems> items; + // TOOD: should this store location data? current accessor uses path location data + public: ::std::string as_string() const; - TupleStructPattern(PathInExpression tuple_struct_path, TupleStructItems* items) : - path(::std::move(tuple_struct_path)), items(items) {} + TupleStructPattern( + PathInExpression tuple_struct_path, ::std::unique_ptr<TupleStructItems> items) : + path(::std::move(tuple_struct_path)), + items(::std::move(items)) {} // Copy constructor required to clone TupleStructPattern(TupleStructPattern const& other) : @@ -661,6 +819,12 @@ namespace Rust { TupleStructPattern(TupleStructPattern&& other) = default; TupleStructPattern& operator=(TupleStructPattern&& other) = default; + location_t get_locus() const { + return path.get_locus(); + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual TupleStructPattern* clone_pattern_impl() const OVERRIDE { @@ -673,11 +837,17 @@ namespace Rust { public: virtual ~TuplePatternItems() {} + // TODO: should this store location data? + // Unique pointer custom clone function ::std::unique_ptr<TuplePatternItems> clone_tuple_pattern_items() const { return ::std::unique_ptr<TuplePatternItems>(clone_tuple_pattern_items_impl()); } + virtual ::std::string as_string() const = 0; + + virtual void accept_vis(ASTVisitor& vis) = 0; + protected: // pure virtual clone implementation virtual TuplePatternItems* clone_tuple_pattern_items_impl() const = 0; @@ -751,6 +921,10 @@ namespace Rust { TuplePatternItemsMultiple(TuplePatternItemsMultiple&& other) = default; TuplePatternItemsMultiple& operator=(TuplePatternItemsMultiple&& other) = default; + ::std::string as_string() const; + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual TuplePatternItemsMultiple* clone_tuple_pattern_items_impl() const OVERRIDE { @@ -811,6 +985,10 @@ namespace Rust { TuplePatternItemsRanged(TuplePatternItemsRanged&& other) = default; TuplePatternItemsRanged& operator=(TuplePatternItemsRanged&& other) = default; + ::std::string as_string() const; + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual TuplePatternItemsRanged* clone_tuple_pattern_items_impl() const OVERRIDE { @@ -824,6 +1002,8 @@ namespace Rust { // TuplePatternItems items; ::std::unique_ptr<TuplePatternItems> items; + location_t locus; + public: ::std::string as_string() const; @@ -832,21 +1012,29 @@ namespace Rust { return items != NULL; } - TuplePattern(TuplePatternItems* items) : items(items) {} + TuplePattern(::std::unique_ptr<TuplePatternItems> items, location_t locus) : + items(::std::move(items)), locus(locus) {} // Copy constructor requires clone TuplePattern(TuplePattern const& other) : - items(other.items->clone_tuple_pattern_items()) {} + items(other.items->clone_tuple_pattern_items()), locus(other.locus) {} // Destructor - define here if required // Overload assignment operator to clone TuplePattern& operator=(TuplePattern const& other) { items = other.items->clone_tuple_pattern_items(); + locus = other.locus; return *this; } + location_t get_locus() const { + return locus; + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual TuplePattern* clone_pattern_impl() const OVERRIDE { @@ -859,22 +1047,26 @@ namespace Rust { // Pattern pattern_in_parens; ::std::unique_ptr<Pattern> pattern_in_parens; + location_t locus; + public: ::std::string as_string() const { return "(" + pattern_in_parens->as_string() + ")"; } - GroupedPattern(Pattern* pattern_in_parens) : pattern_in_parens(pattern_in_parens) {} + GroupedPattern(::std::unique_ptr<Pattern> pattern_in_parens, location_t locus) : + pattern_in_parens(::std::move(pattern_in_parens)), locus(locus) {} // Copy constructor uses clone GroupedPattern(GroupedPattern const& other) : - pattern_in_parens(other.pattern_in_parens->clone_pattern()) {} + pattern_in_parens(other.pattern_in_parens->clone_pattern()), locus(other.locus) {} // Destructor - define here if required // Overload assignment operator to clone GroupedPattern& operator=(GroupedPattern const& other) { pattern_in_parens = other.pattern_in_parens->clone_pattern(); + locus = other.locus; return *this; } @@ -883,6 +1075,12 @@ namespace Rust { GroupedPattern(GroupedPattern&& other) = default; GroupedPattern& operator=(GroupedPattern&& other) = default; + location_t get_locus() const { + return locus; + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual GroupedPattern* clone_pattern_impl() const OVERRIDE { @@ -895,14 +1093,16 @@ namespace Rust { //::std::vector<Pattern> items; ::std::vector< ::std::unique_ptr<Pattern> > items; + location_t locus; + public: ::std::string as_string() const; - SlicePattern(::std::vector< ::std::unique_ptr<Pattern> > items) : - items(::std::move(items)) {} + SlicePattern(::std::vector< ::std::unique_ptr<Pattern> > items, location_t locus) : + items(::std::move(items)), locus(locus) {} // Copy constructor with vector clone - SlicePattern(SlicePattern const& other) { + SlicePattern(SlicePattern const& other) : locus(other.locus) { // crappy vector unique pointer clone - TODO is there a better way of doing this? items.reserve(other.items.size()); @@ -913,6 +1113,7 @@ namespace Rust { // Overloaded assignment operator to vector clone SlicePattern& operator=(SlicePattern const& other) { + locus = other.locus; // crappy vector unique pointer clone - TODO is there a better way of doing this? items.reserve(other.items.size()); @@ -927,6 +1128,12 @@ namespace Rust { SlicePattern(SlicePattern&& other) = default; SlicePattern& operator=(SlicePattern&& other) = default; + location_t get_locus() const { + return locus; + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual SlicePattern* clone_pattern_impl() const OVERRIDE { diff --git a/gcc/rust/test3/ast/rust-stmt.h b/gcc/rust/test3/ast/rust-stmt.h index 296be00..ece0801 100644 --- a/gcc/rust/test3/ast/rust-stmt.h +++ b/gcc/rust/test3/ast/rust-stmt.h @@ -9,12 +9,20 @@ namespace Rust { namespace AST { // Just a semi-colon, which apparently is a statement. class EmptyStmt : public Stmt { + location_t locus; + public: ::std::string as_string() const { return ::std::string(1, ';'); } - EmptyStmt() {} + EmptyStmt(location_t locus) : locus(locus) {} + + location_t get_locus() const { + return locus; + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; protected: // Use covariance to implement clone function as returning this object rather than base @@ -51,6 +59,8 @@ namespace Rust { // Expr* init_expr; ::std::unique_ptr<Expr> init_expr; + location_t locus; + public: // Returns whether let statement has outer attributes. inline bool has_outer_attrs() const { @@ -75,16 +85,18 @@ namespace Rust { ::std::string as_string() const; - LetStmt(Pattern* variables_pattern, Expr* init_expr, Type* type, - ::std::vector<Attribute> outer_attrs) : + LetStmt(::std::unique_ptr<Pattern> variables_pattern, ::std::unique_ptr<Expr> init_expr, + ::std::unique_ptr<Type> type, ::std::vector<Attribute> outer_attrs, location_t locus) : outer_attrs(::std::move(outer_attrs)), - variables_pattern(variables_pattern), type(type), init_expr(init_expr) {} + variables_pattern(::std::move(variables_pattern)), type(::std::move(type)), + init_expr(::std::move(init_expr)), locus(locus) {} // Copy constructor with clone LetStmt(LetStmt const& other) : outer_attrs(other.outer_attrs), variables_pattern(other.variables_pattern->clone_pattern()), - type(other.type->clone_type()), init_expr(other.init_expr->clone_expr()) {} + type(other.type->clone_type()), init_expr(other.init_expr->clone_expr()), + locus(other.locus) {} // Destructor - define here if required @@ -94,6 +106,7 @@ namespace Rust { init_expr = other.init_expr->clone_expr(); type = other.type->clone_type(); outer_attrs = other.outer_attrs; + locus = other.locus; return *this; } @@ -102,6 +115,12 @@ namespace Rust { LetStmt(LetStmt&& other) = default; LetStmt& operator=(LetStmt&& other) = default; + location_t get_locus() const { + return locus; + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual LetStmt* clone_stmt_impl() const OVERRIDE { @@ -112,6 +131,16 @@ namespace Rust { // Abstract base class for expression statements (statements containing an expression) class ExprStmt : public Stmt { // TODO: add any useful virtual functions + + location_t locus; + + public: + location_t get_locus() const { + return locus; + } + + protected: + ExprStmt(location_t locus) : locus(locus) {} }; /* Statement containing an expression without a block (or, due to technical difficulties, can @@ -130,17 +159,20 @@ namespace Rust { ::std::string as_string() const; - // ExprStmtWithoutBlock(ExprWithoutBlock* expr) : expr(expr) {} - ExprStmtWithoutBlock(Expr* expr) : expr(expr) {} + // ExprStmtWithoutBlock(::std::unique_ptr<ExprWithoutBlock> expr) : + // expr(::std::move(expr)) {} + ExprStmtWithoutBlock(::std::unique_ptr<Expr> expr, location_t locus) : + ExprStmt(locus), expr(::std::move(expr)) {} // Copy constructor with clone ExprStmtWithoutBlock(ExprStmtWithoutBlock const& other) : - expr(other.expr->clone_expr /*_without_block*/ ()) {} + ExprStmt(other), expr(other.expr->clone_expr /*_without_block*/ ()) {} // Destructor - define here if required // Overloaded assignment operator to clone ExprStmtWithoutBlock& operator=(ExprStmtWithoutBlock const& other) { + ExprStmt::operator=(other); expr = other.expr->clone_expr /*_without_block*/ (); return *this; @@ -150,6 +182,8 @@ namespace Rust { ExprStmtWithoutBlock(ExprStmtWithoutBlock&& other) = default; ExprStmtWithoutBlock& operator=(ExprStmtWithoutBlock&& other) = default; + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual ExprStmtWithoutBlock* clone_stmt_impl() const OVERRIDE { @@ -169,16 +203,18 @@ namespace Rust { ::std::string as_string() const; - ExprStmtWithBlock(ExprWithBlock* expr) : expr(expr) {} + ExprStmtWithBlock(::std::unique_ptr<ExprWithBlock> expr, location_t locus) : + ExprStmt(locus), expr(::std::move(expr)) {} // Copy constructor with clone ExprStmtWithBlock(ExprStmtWithBlock const& other) : - expr(other.expr->clone_expr_with_block()) {} + ExprStmt(other), expr(other.expr->clone_expr_with_block()) {} // Destructor - define here if required // Overloaded assignment operator to clone ExprStmtWithBlock& operator=(ExprStmtWithBlock const& other) { + ExprStmt::operator=(other); expr = other.expr->clone_expr_with_block(); return *this; @@ -188,6 +224,8 @@ namespace Rust { ExprStmtWithBlock(ExprStmtWithBlock&& other) = default; ExprStmtWithBlock& operator=(ExprStmtWithBlock&& other) = default; + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual ExprStmtWithBlock* clone_stmt_impl() const OVERRIDE { diff --git a/gcc/rust/test3/ast/rust-type.h b/gcc/rust/test3/ast/rust-type.h index c9b963d..4ca408d 100644 --- a/gcc/rust/test3/ast/rust-type.h +++ b/gcc/rust/test3/ast/rust-type.h @@ -21,20 +21,29 @@ namespace Rust { TypePath type_path; + location_t locus; + public: // Returns whether trait bound has "for" lifetimes inline bool has_for_lifetimes() const { return !for_lifetimes.empty(); } - TraitBound(TypePath type_path, bool in_parens = false, bool opening_question_mark = false, + TraitBound(TypePath type_path, location_t locus, bool in_parens = false, + bool opening_question_mark = false, ::std::vector<LifetimeParam> for_lifetimes = ::std::vector<LifetimeParam>()) : in_parens(in_parens), opening_question_mark(opening_question_mark), for_lifetimes(::std::move(for_lifetimes)), - type_path(::std::move(type_path)) {} + type_path(::std::move(type_path)), locus(locus) {} ::std::string as_string() const; + location_t get_locus() const { + return locus; + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Clone function implementation as (not pure) virtual method virtual TraitBound* clone_type_param_bound_impl() const { @@ -50,6 +59,8 @@ namespace Rust { // TypeParamBounds type_param_bounds; ::std::vector< ::std::unique_ptr<TypeParamBound> > type_param_bounds; // inlined form + location_t locus; + protected: // Use covariance to implement clone function as returning this object rather than base virtual ImplTraitType* clone_type_impl() const OVERRIDE { @@ -57,11 +68,13 @@ namespace Rust { } public: - ImplTraitType(::std::vector< ::std::unique_ptr<TypeParamBound> > type_param_bounds) : - type_param_bounds(::std::move(type_param_bounds)) {} + ImplTraitType(::std::vector< ::std::unique_ptr<TypeParamBound> > type_param_bounds, + location_t locus) : + type_param_bounds(::std::move(type_param_bounds)), + locus(locus) {} // copy constructor with vector clone - ImplTraitType(ImplTraitType const& other) { + ImplTraitType(ImplTraitType const& other) : locus(other.locus) { // crappy vector unique pointer clone - TODO is there a better way of doing this? type_param_bounds.reserve(other.type_param_bounds.size()); @@ -72,6 +85,7 @@ namespace Rust { // overloaded assignment operator to clone ImplTraitType& operator=(ImplTraitType const& other) { + locus = other.locus; // crappy vector unique pointer clone - TODO is there a better way of doing this? type_param_bounds.reserve(other.type_param_bounds.size()); @@ -87,6 +101,12 @@ namespace Rust { ImplTraitType& operator=(ImplTraitType&& other) = default; ::std::string as_string() const; + + location_t get_locus() const { + return locus; + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; }; // An opaque value of another type that implements a set of traits @@ -95,6 +115,8 @@ namespace Rust { // TypeParamBounds type_param_bounds; ::std::vector< ::std::unique_ptr<TypeParamBound> > type_param_bounds; // inlined form + location_t locus; + protected: // Use covariance to implement clone function as returning this object rather than base virtual TraitObjectType* clone_type_impl() const OVERRIDE { @@ -103,12 +125,13 @@ namespace Rust { public: TraitObjectType(::std::vector< ::std::unique_ptr<TypeParamBound> > type_param_bounds, - bool is_dyn_dispatch = false) : + location_t locus, bool is_dyn_dispatch = false) : has_dyn(is_dyn_dispatch), - type_param_bounds(::std::move(type_param_bounds)) {} + type_param_bounds(::std::move(type_param_bounds)), locus(locus) {} // copy constructor with vector clone - TraitObjectType(TraitObjectType const& other) : has_dyn(other.has_dyn) { + TraitObjectType(TraitObjectType const& other) : + has_dyn(other.has_dyn), locus(other.locus) { // crappy vector unique pointer clone - TODO is there a better way of doing this? type_param_bounds.reserve(other.type_param_bounds.size()); @@ -120,6 +143,7 @@ namespace Rust { // overloaded assignment operator to clone TraitObjectType& operator=(TraitObjectType const& other) { has_dyn = other.has_dyn; + locus = other.locus; // crappy vector unique pointer clone - TODO is there a better way of doing this? type_param_bounds.reserve(other.type_param_bounds.size()); @@ -135,6 +159,12 @@ namespace Rust { TraitObjectType& operator=(TraitObjectType&& other) = default; ::std::string as_string() const; + + location_t get_locus() const { + return locus; + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; }; // A type with parentheses around it, used to avoid ambiguity. @@ -142,6 +172,8 @@ namespace Rust { // Type type_in_parens; ::std::unique_ptr<Type> type_in_parens; + location_t locus; + protected: // Use covariance to implement clone function as returning this object rather than base virtual ParenthesisedType* clone_type_impl() const OVERRIDE { @@ -155,17 +187,19 @@ namespace Rust { public: // Constructor uses Type pointer for polymorphism - ParenthesisedType(Type* type_inside_parens) : type_in_parens(type_inside_parens) {} + ParenthesisedType(::std::unique_ptr<Type> type_inside_parens, location_t locus) : + type_in_parens(::std::move(type_inside_parens)), locus(locus) {} // Copy constructor uses custom deep copy method for type to preserve polymorphism ParenthesisedType(ParenthesisedType const& other) : - type_in_parens(other.type_in_parens->clone_type()) {} + type_in_parens(other.type_in_parens->clone_type()), locus(other.locus) {} // define destructor here if required // overload assignment operator to use custom clone method ParenthesisedType& operator=(ParenthesisedType const& other) { type_in_parens = other.type_in_parens->clone_type(); + locus = other.locus; return *this; } @@ -177,19 +211,27 @@ namespace Rust { return "(" + type_in_parens->as_string() + ")"; } - // Creates a trait bound (clone of this one's trait bound) - HACK - virtual TraitBound* to_trait_bound(bool in_parens) const OVERRIDE { - /* NOTE: obviously it is unknown whether the internal type is a trait bound due to + // Creates a trait bound (clone of this one's trait bound) - HACK + virtual TraitBound* to_trait_bound(bool in_parens ATTRIBUTE_UNUSED) const OVERRIDE { + /* NOTE: obviously it is unknown whether the internal type is a trait bound due to * polymorphism, so just let the internal type handle it. As parenthesised type, it * must be in parentheses. */ return type_in_parens->to_trait_bound(true); } + + location_t get_locus() const { + return locus; + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; }; // Impl trait with a single bound? Poor reference material here. class ImplTraitTypeOneBound : public TypeNoBounds { TraitBound trait_bound; + location_t locus; + protected: // Use covariance to implement clone function as returning this object rather than base virtual ImplTraitTypeOneBound* clone_type_impl() const OVERRIDE { @@ -202,17 +244,26 @@ namespace Rust { } public: - ImplTraitTypeOneBound(TraitBound trait_bound) : trait_bound(::std::move(trait_bound)) {} + ImplTraitTypeOneBound(TraitBound trait_bound, location_t locus) : + trait_bound(::std::move(trait_bound)), locus(locus) {} ::std::string as_string() const; + + location_t get_locus() const { + return locus; + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; }; - /* A trait object with a single trait bound. The "trait bound" is really just the trait. + /* A trait object with a single trait bound. The "trait bound" is really just the trait. * Basically like using an interface as a type in an OOP language. */ class TraitObjectTypeOneBound : public TypeNoBounds { bool has_dyn; TraitBound trait_bound; + location_t locus; + protected: // Use covariance to implement clone function as returning this object rather than base virtual TraitObjectTypeOneBound* clone_type_impl() const OVERRIDE { @@ -225,17 +276,25 @@ namespace Rust { } public: - TraitObjectTypeOneBound(TraitBound trait_bound, bool is_dyn_dispatch = false) : - has_dyn(is_dyn_dispatch), trait_bound(::std::move(trait_bound)) {} + TraitObjectTypeOneBound( + TraitBound trait_bound, location_t locus, bool is_dyn_dispatch = false) : + has_dyn(is_dyn_dispatch), + trait_bound(::std::move(trait_bound)), locus(locus) {} ::std::string as_string() const; - // Creates a trait bound (clone of this one's trait bound) - HACK - virtual TraitBound* to_trait_bound(bool in_parens) const OVERRIDE { - /* NOTE: this assumes there is no dynamic dispatch specified- if there was, this + // Creates a trait bound (clone of this one's trait bound) - HACK + virtual TraitBound* to_trait_bound(bool in_parens ATTRIBUTE_UNUSED) const OVERRIDE { + /* NOTE: this assumes there is no dynamic dispatch specified- if there was, this * cloning would not be required as parsing is unambiguous. */ return new AST::TraitBound(trait_bound); } + + location_t get_locus() const { + return locus; + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; }; class TypePath; // definition moved to "rust-path.h" @@ -245,16 +304,19 @@ namespace Rust { //::std::vector<Type> elems; ::std::vector< ::std::unique_ptr<Type> > elems; + location_t locus; + public: // Returns whether the tuple type is the unit type, i.e. has no elements. inline bool is_unit_type() const { return elems.empty(); } - TupleType(::std::vector< ::std::unique_ptr<Type> > elems) : elems(::std::move(elems)) {} + TupleType(::std::vector< ::std::unique_ptr<Type> > elems, location_t locus) : + elems(::std::move(elems)), locus(locus) {} // copy constructor with vector clone - TupleType(TupleType const& other) { + TupleType(TupleType const& other) : locus(other.locus) { // crappy vector unique pointer clone - TODO is there a better way of doing this? elems.reserve(other.elems.size()); @@ -265,6 +327,7 @@ namespace Rust { // overloaded assignment operator to clone TupleType& operator=(TupleType const& other) { + locus = other.locus; // crappy vector unique pointer clone - TODO is there a better way of doing this? elems.reserve(other.elems.size()); @@ -281,6 +344,12 @@ namespace Rust { ::std::string as_string() const; + location_t get_locus() const { + return locus; + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual TupleType* clone_type_impl() const OVERRIDE { @@ -296,6 +365,8 @@ namespace Rust { /* A type with no values, representing the result of computations that never complete. * Expressions of NeverType can be coerced into any other types. Represented as "!". */ class NeverType : public TypeNoBounds { + location_t locus; + protected: // Use covariance to implement clone function as returning this object rather than base virtual NeverType* clone_type_impl() const OVERRIDE { @@ -308,11 +379,17 @@ namespace Rust { } public: - NeverType() {} + NeverType(location_t locus) : locus(locus) {} ::std::string as_string() const { return "! (never type)"; } + + location_t get_locus() const { + return locus; + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; }; // A type consisting of a pointer without safety or liveness guarantees @@ -326,6 +403,8 @@ namespace Rust { // TypeNoBounds type; ::std::unique_ptr<TypeNoBounds> type; + location_t locus; + public: // Returns whether the pointer is mutable or constant. inline PointerType get_pointer_type() const { @@ -333,20 +412,23 @@ namespace Rust { } // Constructor requires pointer for polymorphism reasons - RawPointerType(PointerType pointer_type, TypeNoBounds* type_no_bounds) : - pointer_type(pointer_type), type(type_no_bounds) {} + RawPointerType(PointerType pointer_type, ::std::unique_ptr<TypeNoBounds> type_no_bounds, + location_t locus) : + pointer_type(pointer_type), + type(::std::move(type_no_bounds)), locus(locus) {} // Copy constructor calls custom polymorphic clone function RawPointerType(RawPointerType const& other) : - pointer_type(other.pointer_type), type(other.type->clone_type_no_bounds()) {} + pointer_type(other.pointer_type), type(other.type->clone_type_no_bounds()), + locus(other.locus) {} - // default destructor - ~RawPointerType() = default; + // no destructor required? // overload assignment operator to use custom clone method RawPointerType& operator=(RawPointerType const& other) { pointer_type = other.pointer_type; type = other.type->clone_type_no_bounds(); + locus = other.locus; return *this; } @@ -356,6 +438,12 @@ namespace Rust { ::std::string as_string() const; + location_t get_locus() const { + return locus; + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual RawPointerType* clone_type_impl() const OVERRIDE { @@ -378,6 +466,8 @@ namespace Rust { // TypeNoBounds type; ::std::unique_ptr<TypeNoBounds> type; + location_t locus; + public: // Returns whether the reference is mutable or immutable. inline bool is_mut() const { @@ -390,24 +480,24 @@ namespace Rust { } // Constructor - ReferenceType( - bool is_mut, TypeNoBounds* type_no_bounds, Lifetime lifetime = Lifetime::error()) : + ReferenceType(bool is_mut, ::std::unique_ptr<TypeNoBounds> type_no_bounds, + location_t locus, Lifetime lifetime = Lifetime::error()) : lifetime(::std::move(lifetime)), - has_mut(is_mut), type(type_no_bounds) {} + has_mut(is_mut), type(::std::move(type_no_bounds)), locus(locus) {} // Copy constructor with custom clone method ReferenceType(ReferenceType const& other) : lifetime(other.lifetime), has_mut(other.has_mut), - type(other.type->clone_type_no_bounds()) {} + type(other.type->clone_type_no_bounds()), locus(other.locus) {} - // Default destructor - ~ReferenceType() = default; + // Destructor not required? // Operator overload assignment operator to custom clone the unique pointer ReferenceType& operator=(ReferenceType const& other) { lifetime = other.lifetime; has_mut = other.has_mut; type = other.type->clone_type_no_bounds(); + locus = other.locus; return *this; } @@ -418,6 +508,12 @@ namespace Rust { ::std::string as_string() const; + location_t get_locus() const { + return locus; + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual ReferenceType* clone_type_impl() const OVERRIDE { @@ -437,21 +533,27 @@ namespace Rust { // Expr* size; ::std::unique_ptr<Expr> size; + location_t locus; + public: // Constructor requires pointers for polymorphism - ArrayType(Type* type, Expr* array_size) : elem_type(type), size(array_size) {} + ArrayType( + ::std::unique_ptr<Type> type, ::std::unique_ptr<Expr> array_size, location_t locus) : + elem_type(::std::move(type)), + size(::std::move(array_size)), locus(locus) {} // Copy constructor requires deep copies of both unique pointers ArrayType(ArrayType const& other) : - elem_type(other.elem_type->clone_type()), size(other.size->clone_expr()) {} + elem_type(other.elem_type->clone_type()), size(other.size->clone_expr()), + locus(other.locus) {} - // default destructor - ~ArrayType() = default; + // destructor not required? // Overload assignment operator to deep copy pointers ArrayType& operator=(ArrayType const& other) { elem_type = other.elem_type->clone_type(); size = other.size->clone_expr(); + locus = other.locus; return *this; } @@ -461,6 +563,12 @@ namespace Rust { ::std::string as_string() const; + location_t get_locus() const { + return locus; + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + /*~ArrayType() { delete size; }*/ @@ -481,19 +589,23 @@ namespace Rust { // Type elem_type; ::std::unique_ptr<Type> elem_type; + location_t locus; + public: // Constructor requires pointer for polymorphism - SliceType(Type* type) : elem_type(type) {} + SliceType(::std::unique_ptr<Type> type, location_t locus) : + elem_type(::std::move(type)), locus(locus) {} // Copy constructor requires deep copy of Type smart pointer - SliceType(SliceType const& other) : elem_type(other.elem_type->clone_type()) {} + SliceType(SliceType const& other) : + elem_type(other.elem_type->clone_type()), locus(other.locus) {} - // default destructor - ~SliceType() = default; + // destructor not required? // Overload assignment operator to deep copy SliceType& operator=(SliceType const& other) { elem_type = other.elem_type->clone_type(); + locus = other.locus; return *this; } @@ -504,6 +616,12 @@ namespace Rust { ::std::string as_string() const; + location_t get_locus() const { + return locus; + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual SliceType* clone_type_impl() const OVERRIDE { @@ -518,6 +636,8 @@ namespace Rust { // Type used in generic arguments to explicitly request type inference (wildcard pattern) class InferredType : public TypeNoBounds { + location_t locus; + // e.g. Vec<_> = whatever protected: // Use covariance to implement clone function as returning this object rather than base @@ -531,9 +651,15 @@ namespace Rust { } public: - InferredType() {} + InferredType(location_t locus) : locus(locus) {} ::std::string as_string() const; + + location_t get_locus() const { + return locus; + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; }; class QualifiedPathInType; // definition moved to "rust-path.h" @@ -550,14 +676,18 @@ namespace Rust { ParamKind param_kind; Identifier name; // technically, can be an identifier or '_' + location_t locus; + public: - MaybeNamedParam(Identifier name, ParamKind param_kind, Type* param_type) : - param_type(param_type), param_kind(param_kind), name(::std::move(name)) {} + MaybeNamedParam(Identifier name, ParamKind param_kind, ::std::unique_ptr<Type> param_type, + location_t locus) : + param_type(::std::move(param_type)), + param_kind(param_kind), name(::std::move(name)), locus(locus) {} // Copy constructor with clone MaybeNamedParam(MaybeNamedParam const& other) : param_type(other.param_type->clone_type()), param_kind(other.param_kind), - name(other.name) {} + name(other.name), locus(other.locus) {} ~MaybeNamedParam() = default; @@ -566,6 +696,7 @@ namespace Rust { name = other.name; param_kind = other.param_kind; param_type = other.param_type->clone_type(); + locus = other.locus; return *this; } @@ -583,7 +714,11 @@ namespace Rust { // Creates an error state param. static MaybeNamedParam create_error() { - return MaybeNamedParam("", UNNAMED, NULL); + return MaybeNamedParam("", UNNAMED, NULL, UNKNOWN_LOCATION); + } + + location_t get_locus() const { + return locus; } }; @@ -602,6 +737,8 @@ namespace Rust { // BareFunctionReturnType return_type; ::std::unique_ptr<TypeNoBounds> return_type; // inlined version + location_t locus; + public: // Whether a return type is defined with the function. inline bool has_return_type() const { @@ -615,19 +752,18 @@ namespace Rust { BareFunctionType(::std::vector<LifetimeParam> lifetime_params, FunctionQualifiers qualifiers, ::std::vector<MaybeNamedParam> named_params, - bool is_variadic, TypeNoBounds* type) : + bool is_variadic, ::std::unique_ptr<TypeNoBounds> type, location_t locus) : for_lifetimes(::std::move(lifetime_params)), function_qualifiers(::std::move(qualifiers)), params(::std::move(named_params)), - is_variadic(is_variadic), return_type(type) {} + is_variadic(is_variadic), return_type(::std::move(type)), locus(locus) {} // Copy constructor with clone BareFunctionType(BareFunctionType const& other) : for_lifetimes(other.for_lifetimes), function_qualifiers(other.function_qualifiers), params(other.params), is_variadic(other.is_variadic), - return_type(other.return_type->clone_type_no_bounds()) {} + return_type(other.return_type->clone_type_no_bounds()), locus(other.locus) {} - // default destructor - ~BareFunctionType() = default; + // destructor - define here if required // Overload assignment operator to deep copy BareFunctionType& operator=(BareFunctionType const& other) { @@ -636,6 +772,7 @@ namespace Rust { params = other.params; is_variadic = other.is_variadic; return_type = other.return_type->clone_type_no_bounds(); + locus = other.locus; return *this; } @@ -646,6 +783,12 @@ namespace Rust { ::std::string as_string() const; + location_t get_locus() const { + return locus; + } + + virtual void accept_vis(ASTVisitor& vis) OVERRIDE; + protected: // Use covariance to implement clone function as returning this object rather than base virtual BareFunctionType* clone_type_impl() const OVERRIDE { @@ -673,7 +816,7 @@ namespace Rust { * C-like union type? * function item type? * closure expression types? - * primitive types (bool, int, float, char, str (the slice)) + * primitive types (bool, int, float, char, str (the slice)) * Although supposedly TypePaths are used to reference these types (including primitives) */ /* FIXME: Incomplete spec references: diff --git a/gcc/rust/test3/config-lang.in b/gcc/rust/test3/config-lang.in index 823f626..5591340 100644 --- a/gcc/rust/test3/config-lang.in +++ b/gcc/rust/test3/config-lang.in @@ -40,7 +40,7 @@ lang_requires_boot_languages=c++ # Lists (space-separated) targets in the top level Makefile to build the runtime libraries # for this language, such as target-libobjc. -target_libs="" +target_libs="target-libbacktrace" # Space-separated list of files that should be scanned by gengtype.c to generate the garbage # collection tables and routines for this language. This excludes the files that are common to all diff --git a/gcc/rust/test3/expand/rust-macro-expand.cc b/gcc/rust/test3/expand/rust-macro-expand.cc new file mode 100644 index 0000000..613d94f --- /dev/null +++ b/gcc/rust/test3/expand/rust-macro-expand.cc @@ -0,0 +1,69 @@ +#include "rust-macro-expand.h" +#include "rust-ast-full.h" +// is full really required? + +namespace Rust { + void MacroExpander::expand_invoc(::std::unique_ptr<AST::MacroInvocation>& invoc) { + // if current expansion depth > recursion limit, create an error (maybe fatal error) and return + + /* switch on type of macro: + - '!' syntax macro (inner switch) + - procedural macro - "A token-based function-like macro" + - 'macro_rules' (by example/pattern-match) macro? or not? "an AST-based function-like macro" + - else is unreachable + - attribute syntax macro (inner switch) + - procedural macro attribute syntax - "A token-based attribute macro" + - legacy macro attribute syntax? - "an AST-based attribute macro" + - non-macro attribute: mark known + - else is unreachable + - derive macro (inner switch) + - derive or legacy derive - "token-based" vs "AST-based" + - else is unreachable + - derive container macro - unreachable*/ + + } + + // Determines whether cfg predicate is true and item with attribute should not be stripped. + bool check_cfg_predicate() {} + + // Determines whether cfg predicate is true and item with attribute should not be stripped. + bool check_cfg(AST::Attribute& attr) { + + } + + // Expands cfg_attr attributes. + void expand_attrs_cfgattr(::std::vector<AST::Attribute>& attrs) { + for (auto it = attrs.begin(); it != attrs.end(); ) { + auto& attr = *it; + if (attr.get_path() == "cfg_attr") { + if (check_cfg(attr)) {} + + /* do something - if feature (first token in tree) is in fact enabled, make tokens listed + * afterwards into attributes. + * i.e.: for [cfg_attr(feature = "wow", wow1, wow2)], if "wow" is true, then add attributes + * [wow1] and [wow2] to attribute list. + * This can also be recursive, so check for expanded attributes being recursive and + * possibly recursively call the expand_attrs? */ + } else { + ++it; + } + } + } + + void MacroExpander::expand_crate(AST::Crate& crate) { + // fill macro/decorator map from init list? not sure where init list comes from? + + // expand crate attributes + expand_attrs_cfgattr(crate.inner_attrs); + + // expand module attributes? + + // expand module tree recursively + + // post-process + + // extract exported macros? + + + } +}
\ No newline at end of file diff --git a/gcc/rust/test3/expand/rust-macro-expand.h b/gcc/rust/test3/expand/rust-macro-expand.h new file mode 100644 index 0000000..a252a41 --- /dev/null +++ b/gcc/rust/test3/expand/rust-macro-expand.h @@ -0,0 +1,47 @@ +#ifndef RUST_MACRO_EXPAND_H +#define RUST_MACRO_EXPAND_H + +#include "rust-ast.h" + +// Provides objects and method prototypes for macro expansion + +namespace Rust { + // forward decls for AST + namespace AST { + class MacroInvocation; + } + + // Object used to store configuration data for macro expansion. + struct ExpansionCfg { + // features? + unsigned int recursion_limit; // TODO: determine default recursion limit + // trace macros? + // should test? + // more default stuff? + }; + + // Object used to store shared data (between functions) for macro expansion. + struct MacroExpander { + ExpansionCfg cfg; + unsigned int expansion_depth = 0; + + MacroExpander(AST::Crate& crate, ExpansionCfg cfg) : cfg(cfg), crate(crate) {} + + ~MacroExpander() = default; + + // Expands all macros in the crate passed in. + void expand_crate(AST::Crate& crate); + + /* Expands a macro invocation (not macro invocation semi) - possibly make both have similar + * duck-typed interface and use templates?*/ + // should this be public or private? + void expand_invoc(::std::unique_ptr<AST::MacroInvocation>& invoc); + + // TODO: make it extend ASTVisitor so that individual items can be accessed properly? + + private: + AST::Crate& crate; + }; +} + +#endif
\ No newline at end of file diff --git a/gcc/rust/test3/lang.opt b/gcc/rust/test3/lang.opt new file mode 100644 index 0000000..4757dfb --- /dev/null +++ b/gcc/rust/test3/lang.opt @@ -0,0 +1,46 @@ +; Options for the Rust front end. +; Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 +; Free Software Foundation, Inc. +; +; This file is part of GCC. +; +; GCC 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 3, or (at your option) any later +; version. +; +; GCC 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 GCC; see the file COPYING3. If not see +; <http://www.gnu.org/licenses/>. + +; See the GCC internals manual for a description of this file's format. + +; Please try to keep this file in ASCII collating order. + +; Describes command-line options used by this frontend + +Language +Rust + +I +Rust Joined Separate +; Documented in c.opt + +L +Rust Joined Separate +; Not documented + +frust-dump- +Rust Joined RejectNegative +-frust-dump-<type> Dump Rust frontend internal information. + +o +Rust Joined Separate +; Documented in common.opt + +; This comment is to ensure we retain the blank line above. diff --git a/gcc/rust/test3/lex/rust-lex.cc b/gcc/rust/test3/lex/rust-lex.cc index a8a6877..5a7b0cb 100644 --- a/gcc/rust/test3/lex/rust-lex.cc +++ b/gcc/rust/test3/lex/rust-lex.cc @@ -134,6 +134,10 @@ namespace Rust { skip_token(0); } + void Lexer::replace_current_token(TokenPtr replacement) { + token_queue.replace_current_value(replacement); + } + /* shitty anonymous namespace that can only be accessed inside the compilation unit - used for * classify_keyword * Binary search in sorted array of keywords created with x-macros. */ diff --git a/gcc/rust/test3/lex/rust-lex.h b/gcc/rust/test3/lex/rust-lex.h index c051cd1..b16cfeb 100644 --- a/gcc/rust/test3/lex/rust-lex.h +++ b/gcc/rust/test3/lex/rust-lex.h @@ -60,6 +60,9 @@ namespace Rust { // Skips the current token. void skip_token(); + // Replaces the current token with a specified token. + void replace_current_token(TokenPtr replacement); + private: // File for use as input. FILE* input; diff --git a/gcc/rust/test3/parse/rust-parse.cc b/gcc/rust/test3/parse/rust-parse.cc index 6d058f1..1eac8a1 100644 --- a/gcc/rust/test3/parse/rust-parse.cc +++ b/gcc/rust/test3/parse/rust-parse.cc @@ -5,26 +5,6 @@ #include <algorithm> // for std::find -/* parsing notes: - * kinds of "syntactic units" used: - * - statement: expresses an action to be carried out (executed), e.g.: - * function calls - * goto - * return - * (maybe) variable definition - * blocks (apparently) - as in {} - * control structures - if, while, do-while, switch - * cannot return a result and are executed only for side effects - * distinction may not exist in rust entirely due to functional influence of lots of things being - * expressions - * - * - expression: stuff that evaluates to a value, e.g.: - * 2 + 3 - * y * 6 - * - * - variable definition (maybe - if not a statement), e.g.: - * y = x + 2 */ - namespace Rust { // Left binding powers of operations. enum binding_powers { @@ -96,10 +76,10 @@ namespace Rust { LBP_L_SHIFT_ASSIG = LBP_ASSIG, LBP_R_SHIFT_ASSIG = LBP_ASSIG, - // return, break, and closures as lowest priority? - // LBP_RETURN = 5, - // LBP_BREAK = LBP_RETURN, - // LBP_CLOSURE = LBP_RETURN, + // return, break, and closures as lowest priority? + LBP_RETURN = 5, + LBP_BREAK = LBP_RETURN, + LBP_CLOSURE = LBP_RETURN, // unary prefix operators #if 0 // rust precedences @@ -140,37 +120,136 @@ namespace Rust { return type.get_tree_code() == RECORD_TYPE; } + // Returns whether the token can start a type (i.e. there is a valid type beginning with the + // token). + bool can_tok_start_type(TokenId id) { + switch (id) { + case EXCLAM: + case LEFT_SQUARE: + case LEFT_ANGLE: + case UNDERSCORE: + case ASTERISK: + case AMP: + case LIFETIME: + case IDENTIFIER: + case SUPER: + case SELF: + case SELF_ALIAS: + case CRATE: + case DOLLAR_SIGN: + case SCOPE_RESOLUTION: + case LEFT_PAREN: + case FOR: + case ASYNC: + case CONST: + case UNSAFE: + case EXTERN_TOK: + case FN_TOK: + case IMPL: + case DYN: + case QUESTION_MARK: + return true; + default: + return false; + } + } + + /* Returns whether the token id is (or is likely to be) a right angle bracket. i.e. '>', '>>', + * '>=' and '>>=' tokens. */ + bool is_right_angle_tok(TokenId id) { + switch (id) { + case RIGHT_ANGLE: + case RIGHT_SHIFT: + case GREATER_OR_EQUAL: + case RIGHT_SHIFT_EQ: + return true; + default: + return false; + } + } + + // HACK-y special handling for skipping a right angle token at the end of generic arguments. + bool Parser::skip_generics_right_angle() { + // HACK: special handling for right shift '>>', greater or equal '>=', and right shift assig + // '>>=' + const_TokenPtr tok = lexer.peek_token(); + switch (tok->get_id()) { + case RIGHT_ANGLE: + // this is good - skip token + lexer.skip_token(); + return true; + case RIGHT_SHIFT: { + /* shit. preferred HACK would be to replace this token in stream with '>', but may not + * be possible at this point. */ + // FIXME: ensure locations aren't messed up + TokenPtr right_angle = Token::make(RIGHT_ANGLE, tok->get_locus() + 1); + lexer.replace_current_token(right_angle); + return true; + } + case GREATER_OR_EQUAL: { + // another HACK - replace with equal (as assignment intended, probably) + /* FIXME: is this even required? how many people wouldn't leave a space? - apparently + * rustc has this feature */ + // FIXME: ensure locations aren't messed up + TokenPtr equal = Token::make(EQUAL, tok->get_locus() + 1); + lexer.replace_current_token(equal); + return true; + } + case RIGHT_SHIFT_EQ: { + // another HACK - replace with greater or equal + // FIXME: again, is this really required? rustc has the feature, though + // FIXME: ensure locations aren't messed up + TokenPtr greater_equal = Token::make(GREATER_OR_EQUAL, tok->get_locus() + 1); + lexer.replace_current_token(greater_equal); + return true; + } + default: + error_at(tok->get_locus(), "expected '>' at end of generic argument - found '%s'", + tok->get_token_description()); + return false; + } + } + /* Gets left binding power for specified token. * Not suitable for use at the moment or possibly ever because binding power cannot be purely * determined from operator token with Rust grammar - e.g. method call and field access have * different left binding powers but the same operator token. */ int Parser::left_binding_power(const_TokenPtr token) { + // HACK: called with "peek_token()", so lookahead is "peek_token(1)" switch (token->get_id()) { - /* TODO: issue here - distinguish between method calls and field access somehow? - Also would have to distinguish between paths and function calls (:: operator), - maybe more stuff. */ - /* Current plan for tackling LBP - don't do it based on token, use lookahead. - * Or alternatively, only use Pratt parsing for OperatorExpr and handle other expressions - * without it. - * rustc only considers arithmetic, logical/relational, 'as', '?=', ranges, colons, and - * assignment to have operator precedence and associativity rules applicable. It then has - * a separate "ExprPrecedence" that also includes binary operators. */ - - // TODO: handle operator overloading - have a function replace the operator? - - /*case DOT: - return LBP_DOT;*/ - - /* TODO: BIG ISSUE - scope resolution can be for "path" or "function call", which have - * different precedences (and also relative precedences - method and field are between)*/ + /* TODO: issue here - distinguish between method calls and field access somehow? + Also would have to distinguish between paths and function calls (:: operator), + maybe more stuff. */ + /* Current plan for tackling LBP - don't do it based on token, use lookahead. + * Or alternatively, only use Pratt parsing for OperatorExpr and handle other + * expressions without it. rustc only considers arithmetic, logical/relational, 'as', + * '?=', ranges, colons, and assignment to have operator precedence and associativity + * rules applicable. It then has + * a separate "ExprPrecedence" that also includes binary operators. */ + + // TODO: handle operator overloading - have a function replace the operator? + + /*case DOT: + return LBP_DOT;*/ + case SCOPE_RESOLUTION: + fprintf(stderr, "possible error - looked up LBP of scope resolution operator. should " + "be handled elsewhere. \n"); return LBP_PATH; - /* TODO: BIG ISSUE - dot can be for "method call" or "field access", which have - * different precedences (though at least they have none between) */ + /* Resolved by lookahead HACK that should work with current code. If next token is + * identifier and token after that isn't parenthesised expression list, it is a field + * reference. */ case DOT: + if (lexer.peek_token(1)->get_id() == IDENTIFIER + && lexer.peek_token(2)->get_id() != LEFT_PAREN) { + return LBP_FIELD_EXPR; + } return LBP_METHOD_CALL; + case LEFT_PAREN: + return LBP_FUNCTION_CALL; + case LEFT_SQUARE: return LBP_ARRAY_REF; @@ -256,6 +335,11 @@ namespace Rust { case RIGHT_SHIFT_EQ: return LBP_R_SHIFT_ASSIG; + // HACK: float literal due to lexer misidentifying a dot then an integer as a float + case FLOAT_LITERAL: + return LBP_FIELD_EXPR; + // field expr is same as tuple expr in precedence, i imagine + // anything that can't appear in an infix position is given lowest priority default: return LBP_LOWEST; @@ -269,12 +353,12 @@ namespace Rust { // Parse statements until done (EOF) and append to current stmt list. void Parser::parse_statement_seq(bool (Parser::*done)()) { // Parse statements until done and append to the current stmt list - while (!(this->*done)()) { + /*while (!(this->*done)()) { // get stmt tree for parsed statement Tree stmt = parse_statement(); // append each stmt tree to current stmt list get_current_stmt_list().append(stmt); - } + }*/ } // Parse "items" until done (EOF) and append to current something list. Seems to be method taken @@ -365,7 +449,21 @@ namespace Rust { ::std::vector<AST::Attribute> inner_attrs = parse_inner_attributes(); // parse items - ::std::vector< ::std::unique_ptr<AST::Item> > items = parse_items(); + ::std::vector< ::std::unique_ptr<AST::Item> > items; + + const_TokenPtr t = lexer.peek_token(); + while (t->get_id() != END_OF_FILE) { + ::std::unique_ptr<AST::Item> item = parse_item(false); + if (item == NULL) { + error_at(lexer.peek_token()->get_locus(), "failed to parse item in crate"); + items = ::std::vector< ::std::unique_ptr<AST::Item> >(); + break; + } + + items.push_back(::std::move(item)); + + t = lexer.peek_token(); + } return AST::Crate(::std::move(items), ::std::move(inner_attrs), has_utf8bom, has_shebang); } @@ -419,6 +517,8 @@ namespace Rust { // Parses the body of an attribute (inner or outer). AST::Attribute Parser::parse_attribute_body() { + location_t locus = lexer.peek_token()->get_locus(); + AST::SimplePath attr_path = parse_simple_path(); // ensure path is valid to parse attribute input if (attr_path.is_empty()) { @@ -429,25 +529,34 @@ namespace Rust { return AST::Attribute::create_empty(); } - AST::AttrInput* attr_input = parse_attr_input(); + ::std::unique_ptr<AST::AttrInput> attr_input = parse_attr_input(); // AttrInput is allowed to be null, so no checks here - return AST::Attribute(::std::move(attr_path), attr_input); + return AST::Attribute(::std::move(attr_path), ::std::move(attr_input), locus); } // Parses a SimplePath AST node AST::SimplePath Parser::parse_simple_path() { bool has_opening_scope_resolution = false; + location_t locus = UNKNOWN_LOCATION; // Checks for opening scope resolution (i.e. global scope fully-qualified path) if (lexer.peek_token()->get_id() == SCOPE_RESOLUTION) { has_opening_scope_resolution = true; + + locus = lexer.peek_token()->get_locus(); + lexer.skip_token(); } // Parse single required simple path segment AST::SimplePathSegment segment = parse_simple_path_segment(); + // get location if not gotten already + if (locus == UNKNOWN_LOCATION) { + locus = segment.get_locus(); + } + ::std::vector<AST::SimplePathSegment> segments; // Return empty vector if first, actually required segment is an error @@ -481,7 +590,7 @@ namespace Rust { } } - return AST::SimplePath(::std::move(segments), has_opening_scope_resolution); + return AST::SimplePath(::std::move(segments), has_opening_scope_resolution, locus); } // Parses a single SimplePathSegment (does not handle the scope resolution operators) @@ -491,24 +600,24 @@ namespace Rust { case IDENTIFIER: lexer.skip_token(); - return AST::SimplePathSegment(t->get_str()); + return AST::SimplePathSegment(t->get_str(), t->get_locus()); case SUPER: lexer.skip_token(); - return AST::SimplePathSegment(::std::string("super")); + return AST::SimplePathSegment(::std::string("super"), t->get_locus()); case SELF: lexer.skip_token(); - return AST::SimplePathSegment(::std::string("self")); + return AST::SimplePathSegment(::std::string("self"), t->get_locus()); case CRATE: lexer.skip_token(); - return AST::SimplePathSegment(::std::string("crate")); + return AST::SimplePathSegment(::std::string("crate"), t->get_locus()); case DOLLAR_SIGN: if (lexer.peek_token(1)->get_id() == CRATE) { lexer.skip_token(1); - return AST::SimplePathSegment(::std::string("$crate")); + return AST::SimplePathSegment(::std::string("$crate"), t->get_locus()); } gcc_fallthrough(); default: @@ -570,14 +679,15 @@ namespace Rust { } // Parses an AttrInput AST node (polymorphic, as AttrInput is abstract) - AST::AttrInput* Parser::parse_attr_input() { + ::std::unique_ptr<AST::AttrInput> Parser::parse_attr_input() { const_TokenPtr t = lexer.peek_token(); switch (t->get_id()) { case LEFT_PAREN: case LEFT_SQUARE: case LEFT_CURLY: { // must be a delimited token tree, so parse that - AST::DelimTokenTree* input_tree = new AST::DelimTokenTree(parse_delim_token_tree()); + ::std::unique_ptr<AST::DelimTokenTree> input_tree( + new AST::DelimTokenTree(parse_delim_token_tree())); // TODO: potential checks on DelimTokenTree before returning @@ -623,12 +733,15 @@ namespace Rust { } // create actual LiteralExpr - AST::LiteralExpr lit_expr(t->get_str(), lit_type); + AST::LiteralExpr lit_expr(t->get_str(), lit_type, t->get_locus()); - AST::AttrInputLiteral* attr_input_lit = new AST::AttrInputLiteral(lit_expr); + ::std::unique_ptr<AST::AttrInputLiteral> attr_input_lit( + new AST::AttrInputLiteral(::std::move(lit_expr))); // do checks or whatever? none required, really + // FIXME: shouldn't a skip token be required here? + return attr_input_lit; } break; case RIGHT_SQUARE: @@ -673,8 +786,12 @@ namespace Rust { // Parses a delimited token tree AST::DelimTokenTree Parser::parse_delim_token_tree() { + // DEBUG + fprintf(stderr, "new delim token tree parsing begun\n"); + const_TokenPtr t = lexer.peek_token(); lexer.skip_token(); + location_t initial_loc = t->get_locus(); // save delim type to ensure it is reused later AST::DelimType delim_type = AST::PARENS; @@ -697,14 +814,13 @@ namespace Rust { return AST::DelimTokenTree::create_empty(); } - t = lexer.peek_token(); - // parse actual token tree vector - 0 or more ::std::vector< ::std::unique_ptr<AST::TokenTree> > token_trees_in_tree; // repeat loop until finding the matching delimiter + t = lexer.peek_token(); while (!token_id_matches_delims(t->get_id(), delim_type)) { - AST::TokenTree* tok_tree = parse_token_tree(); + ::std::unique_ptr<AST::TokenTree> tok_tree = parse_token_tree(); if (tok_tree == NULL) { // TODO: is this error handling appropriate? @@ -714,15 +830,13 @@ namespace Rust { return AST::DelimTokenTree::create_empty(); } - // may need attention in C++11 move - token_trees_in_tree.push_back(::std::unique_ptr<AST::TokenTree>(tok_tree)); + token_trees_in_tree.push_back(::std::move(tok_tree)); // lexer.skip_token(); t = lexer.peek_token(); } - // TODO: put in std::move for vector in constructor or here? - AST::DelimTokenTree token_tree(delim_type, ::std::move(token_trees_in_tree)); + AST::DelimTokenTree token_tree(delim_type, ::std::move(token_trees_in_tree), initial_loc); // parse end delimiters t = lexer.peek_token(); @@ -731,6 +845,11 @@ namespace Rust { // tokens match opening delimiter, so skip. lexer.skip_token(); + // DEBUG + fprintf(stderr, + "finished parsing new delim token tree - peeked token is now '%s' while t is '%s'\n", + lexer.peek_token()->get_token_description(), t->get_token_description()); + return token_tree; } else { // tokens don't match opening delimiters, so produce error @@ -747,7 +866,7 @@ namespace Rust { /* Parses a TokenTree syntactical production. This is either a delimited token tree or a * non-delimiter token. */ - AST::TokenTree* Parser::parse_token_tree() { + ::std::unique_ptr<AST::TokenTree> Parser::parse_token_tree() { const_TokenPtr t = lexer.peek_token(); switch (t->get_id()) { @@ -756,7 +875,8 @@ namespace Rust { case LEFT_CURLY: // Parse delimited token tree // TODO: use move rather than copy constructor - return new AST::DelimTokenTree(parse_delim_token_tree()); + return ::std::unique_ptr<AST::DelimTokenTree>( + new AST::DelimTokenTree(parse_delim_token_tree())); case RIGHT_PAREN: case RIGHT_SQUARE: case RIGHT_CURLY: @@ -771,21 +891,23 @@ namespace Rust { // parse token itself as TokenTree lexer.skip_token(); // TODO: fix that token constructor, possibly with c++11 features - return new AST::Token(t); + return ::std::unique_ptr<AST::Token>(new AST::Token(t)); } } - // Parses a sequence of items within a module or the implicit top-level module in a crate. + /* Parses a sequence of items within a module or the implicit top-level module in a crate. Note: + * this is not currently used as parsing an item sequence individually is pretty simple and allows + * for better error diagnostics and detection. */ ::std::vector< ::std::unique_ptr<AST::Item> > Parser::parse_items() { ::std::vector< ::std::unique_ptr<AST::Item> > items; // TODO: replace with do-while loop? // infinite loop to save on comparisons (may be a tight loop) - breaks when next item is null while (true) { - AST::Item* item = parse_item(false); + ::std::unique_ptr<AST::Item> item = parse_item(false); if (item != NULL) { - items.push_back(::std::unique_ptr<AST::Item>(item)); + items.push_back(::std::move(item)); } else { break; } @@ -795,7 +917,7 @@ namespace Rust { } // Parses a single item - AST::Item* Parser::parse_item(bool called_from_statement) { + ::std::unique_ptr<AST::Item> Parser::parse_item(bool called_from_statement) { // has a "called_from_statement" parameter for better error message handling // parse outer attributes for item @@ -920,7 +1042,8 @@ namespace Rust { } // Parses a VisItem (item that can have non-default visibility). - AST::VisItem* Parser::parse_vis_item(::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::VisItem> Parser::parse_vis_item( + ::std::vector<AST::Attribute> outer_attrs) { // parse visibility, which may or may not exist AST::Visibility vis = parse_visibility(); @@ -1038,7 +1161,8 @@ namespace Rust { } // Parses a MacroItem (either a MacroInvocationSemi or MacroRulesDefinition). - AST::MacroItem* Parser::parse_macro_item(::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::MacroItem> Parser::parse_macro_item( + ::std::vector<AST::Attribute> outer_attrs) { const_TokenPtr t = lexer.peek_token(); /* dodgy way of detecting macro due to weird context-dependence thing. probably can be @@ -1048,13 +1172,13 @@ namespace Rust { return parse_macro_rules_def(::std::move(outer_attrs)); } else { // DEBUG: TODO: remove - error_at(t->get_locus(), "DEBUG - parse_macro_item called and token is not macro_rules"); + fprintf(stderr, "DEBUG - parse_macro_item called and token is not macro_rules"); if (t->get_id() == IDENTIFIER) { - error_at(t->get_locus(), + fprintf(stderr, "just add to last error: token is not macro_rules and is instead '%s'", t->get_str().c_str()); } else { - error_at(t->get_locus(), + fprintf(stderr, "just add to last error: token is not macro_rules and is not an identifier either " "- it is '%s'", t->get_token_description()); @@ -1065,7 +1189,7 @@ namespace Rust { } // Parses a macro rules definition syntax extension whatever thing. - AST::MacroRulesDefinition* Parser::parse_macro_rules_def( + ::std::unique_ptr<AST::MacroRulesDefinition> Parser::parse_macro_rules_def( ::std::vector<AST::Attribute> outer_attrs) { // ensure that first token is identifier saying "macro_rules" const_TokenPtr t = lexer.peek_token(); @@ -1075,6 +1199,7 @@ namespace Rust { return NULL; } lexer.skip_token(); + location_t macro_locus = t->get_locus(); if (!skip_token(EXCLAM)) { // skip after somewhere? @@ -1083,8 +1208,14 @@ namespace Rust { // parse macro name const_TokenPtr ident_tok = expect_token(IDENTIFIER); + if (ident_tok == NULL) { + return NULL; + } Identifier rule_name = ident_tok->get_str(); + // DEBUG + fprintf(stderr, "in macro rules def, about to parse parens.\n"); + // save delim type to ensure it is reused later AST::DelimType delim_type = AST::PARENS; @@ -1106,6 +1237,7 @@ namespace Rust { t->get_token_description()); return NULL; } + lexer.skip_token(); // parse actual macro rules ::std::vector<AST::MacroRule> macro_rules; @@ -1118,7 +1250,10 @@ namespace Rust { // skip after somewhere? return NULL; } - macro_rules.push_back(initial_rule); + macro_rules.push_back(::std::move(initial_rule)); + + // DEBUG + fprintf(stderr, "successfully pushed back initial macro rule\n"); t = lexer.peek_token(); // parse macro rules @@ -1126,14 +1261,26 @@ namespace Rust { // skip semicolon lexer.skip_token(); + // don't parse if end of macro rules + if (token_id_matches_delims(lexer.peek_token()->get_id(), delim_type)) { + // DEBUG + fprintf(stderr, "broke out of parsing macro rules loop due to finding delim\n"); + + break; + } + // try to parse next rule AST::MacroRule rule = parse_macro_rule(); if (rule.is_error()) { - // not necessarily an error - could be trailing semicolon - break; + error_at(lexer.peek_token()->get_locus(), + "failed to parse macro rule in macro rules definition"); + return NULL; } - macro_rules.push_back(rule); + macro_rules.push_back(::std::move(rule)); + + // DEBUG + fprintf(stderr, "successfully pushed back another macro rule\n"); t = lexer.peek_token(); } @@ -1148,13 +1295,15 @@ namespace Rust { // skip semicolon at end of non-curly macro definitions if (!skip_token(SEMICOLON)) { // as this is the end, allow recovery (probably) - may change - return new AST::MacroRulesDefinition(::std::move(rule_name), delim_type, - ::std::move(macro_rules), ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::MacroRulesDefinition>( + new AST::MacroRulesDefinition(::std::move(rule_name), delim_type, + ::std::move(macro_rules), ::std::move(outer_attrs), macro_locus)); } } - return new AST::MacroRulesDefinition( - ::std::move(rule_name), delim_type, ::std::move(macro_rules), ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::MacroRulesDefinition>( + new AST::MacroRulesDefinition(::std::move(rule_name), delim_type, + ::std::move(macro_rules), ::std::move(outer_attrs), macro_locus)); } else { // tokens don't match opening delimiters, so produce error error_at(t->get_locus(), @@ -1170,8 +1319,9 @@ namespace Rust { } // Parses a semi-coloned (except for full block) macro invocation item. - AST::MacroInvocationSemi* Parser::parse_macro_invocation_semi( + ::std::unique_ptr<AST::MacroInvocationSemi> Parser::parse_macro_invocation_semi( ::std::vector<AST::Attribute> outer_attrs) { + location_t macro_locus = lexer.peek_token()->get_locus(); AST::SimplePath path = parse_simple_path(); if (!skip_token(EXCLAM)) { @@ -1200,6 +1350,7 @@ namespace Rust { t->get_token_description()); return NULL; } + lexer.skip_token(); // parse actual token trees ::std::vector< ::std::unique_ptr<AST::TokenTree> > token_trees; @@ -1207,7 +1358,7 @@ namespace Rust { t = lexer.peek_token(); // parse token trees until the initial delimiter token is found again while (!token_id_matches_delims(t->get_id(), delim_type)) { - AST::TokenTree* tree = parse_token_tree(); + ::std::unique_ptr<AST::TokenTree> tree = parse_token_tree(); if (tree == NULL) { error_at(t->get_locus(), @@ -1216,7 +1367,7 @@ namespace Rust { return NULL; } - token_trees.push_back(::std::unique_ptr<AST::TokenTree>(tree)); + token_trees.push_back(::std::move(tree)); t = lexer.peek_token(); } @@ -1231,13 +1382,19 @@ namespace Rust { // skip semicolon at end of non-curly macro invocation semis if (!skip_token(SEMICOLON)) { // as this is the end, allow recovery (probably) - may change - return new AST::MacroInvocationSemi(::std::move(path), delim_type, - ::std::move(token_trees), ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::MacroInvocationSemi>( + new AST::MacroInvocationSemi(::std::move(path), delim_type, + ::std::move(token_trees), ::std::move(outer_attrs), macro_locus)); } } - return new AST::MacroInvocationSemi( - ::std::move(path), delim_type, ::std::move(token_trees), ::std::move(outer_attrs)); + // DEBUG: + fprintf(stderr, "skipped token is '%s', next token (current peek) is '%s'\n", + t->get_token_description(), lexer.peek_token()->get_token_description()); + + return ::std::unique_ptr<AST::MacroInvocationSemi>( + new AST::MacroInvocationSemi(::std::move(path), delim_type, ::std::move(token_trees), + ::std::move(outer_attrs), macro_locus)); } else { // tokens don't match opening delimiters, so produce error error_at(t->get_locus(), @@ -1253,7 +1410,8 @@ namespace Rust { } // Parses a non-semicoloned macro invocation (i.e. as pattern or expression). - AST::MacroInvocation* Parser::parse_macro_invocation(::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::MacroInvocation> Parser::parse_macro_invocation( + ::std::vector<AST::Attribute> outer_attrs) { // parse macro path AST::SimplePath macro_path = parse_simple_path(); if (macro_path.is_empty()) { @@ -1270,27 +1428,50 @@ namespace Rust { // parse internal delim token tree AST::DelimTokenTree delim_tok_tree = parse_delim_token_tree(); - return new AST::MacroInvocation( - ::std::move(macro_path), ::std::move(delim_tok_tree), ::std::move(outer_attrs)); + location_t macro_locus = macro_path.get_locus(); + + return ::std::unique_ptr<AST::MacroInvocation>( + new AST::MacroInvocation(::std::move(macro_path), ::std::move(delim_tok_tree), + ::std::move(outer_attrs), macro_locus)); } // Parses a macro rule definition - does not parse semicolons. AST::MacroRule Parser::parse_macro_rule() { + // DEBUG + fprintf(stderr, "begun parsing macro rule\n"); + // parse macro matcher AST::MacroMatcher matcher = parse_macro_matcher(); + + // DEBUG + fprintf(stderr, "managed to get past parsing macro matcher\n"); + if (matcher.is_error()) { return AST::MacroRule::create_error(); } + // DEBUG + fprintf(stderr, "successfully parsed macro matcher\n"); + if (!skip_token(MATCH_ARROW)) { // skip after somewhere? return AST::MacroRule::create_error(); } + // DEBUG + fprintf(stderr, "successfully skipped match arrow\n"); + // parse transcriber (this is just a delim token tree) AST::DelimTokenTree transcribe_tree = parse_delim_token_tree(); + + // DEBUG + fprintf(stderr, "successfully parsed transcribe tree\n"); + AST::MacroTranscriber transcriber(::std::move(transcribe_tree)); + // DEBUG + fprintf(stderr, "successfully parsed macro transcriber - returning macro rule\n"); + return AST::MacroRule(::std::move(matcher), ::std::move(transcriber)); } @@ -1299,6 +1480,9 @@ namespace Rust { // save delim type to ensure it is reused later AST::DelimType delim_type = AST::PARENS; + // DEBUG + fprintf(stderr, "begun parsing macro matcher\n"); + // Map tokens to DelimType const_TokenPtr t = lexer.peek_token(); switch (t->get_id()) { @@ -1317,6 +1501,7 @@ namespace Rust { t->get_token_description()); return AST::MacroMatcher::create_error(); } + lexer.skip_token(); // parse actual macro matches ::std::vector< ::std::unique_ptr<AST::MacroMatch> > matches; @@ -1324,7 +1509,7 @@ namespace Rust { t = lexer.peek_token(); // parse token trees until the initial delimiter token is found again while (!token_id_matches_delims(t->get_id(), delim_type)) { - AST::MacroMatch* match = parse_macro_match(); + ::std::unique_ptr<AST::MacroMatch> match = parse_macro_match(); if (match == NULL) { error_at(t->get_locus(), "failed to parse macro match for macro matcher - found '%s'", @@ -1332,7 +1517,10 @@ namespace Rust { return AST::MacroMatcher::create_error(); } - matches.push_back(::std::unique_ptr<AST::MacroMatch>(match)); + matches.push_back(::std::move(match)); + + // DEBUG + fprintf(stderr, "pushed back a match in macro matcher\n"); t = lexer.peek_token(); } @@ -1358,15 +1546,23 @@ namespace Rust { } // Parses a macro match (syntax match inside a matcher in a macro rule). - AST::MacroMatch* Parser::parse_macro_match() { + ::std::unique_ptr<AST::MacroMatch> Parser::parse_macro_match() { // branch based on token available const_TokenPtr t = lexer.peek_token(); switch (t->get_id()) { case LEFT_PAREN: case LEFT_SQUARE: - case LEFT_CURLY: + case LEFT_CURLY: { // must be macro matcher as delimited - return new AST::MacroMatcher(parse_macro_matcher()); + AST::MacroMatcher matcher = parse_macro_matcher(); + if (matcher.is_error()) { + error_at(lexer.peek_token()->get_locus(), + "failed to parse macro matcher in macro match"); + return NULL; + } + return ::std::unique_ptr<AST::MacroMatcher>( + new AST::MacroMatcher(::std::move(matcher))); + } case DOLLAR_SIGN: { // have to do more lookahead to determine if fragment or repetition const_TokenPtr t2 = lexer.peek_token(1); @@ -1398,12 +1594,13 @@ namespace Rust { return NULL; default: // just the token - return new AST::Token(t); + lexer.skip_token(); + return ::std::unique_ptr<AST::Token>(new AST::Token(t)); } } // Parses a fragment macro match. - AST::MacroMatchFragment* Parser::parse_macro_match_fragment() { + ::std::unique_ptr<AST::MacroMatchFragment> Parser::parse_macro_match_fragment() { skip_token(DOLLAR_SIGN); const_TokenPtr ident_tok = expect_token(IDENTIFIER); @@ -1427,36 +1624,39 @@ namespace Rust { return NULL; } - return new AST::MacroMatchFragment(::std::move(ident), frag); + return ::std::unique_ptr<AST::MacroMatchFragment>( + new AST::MacroMatchFragment(::std::move(ident), frag)); } // Parses a repetition macro match. - AST::MacroMatchRepetition* Parser::parse_macro_match_repetition() { + ::std::unique_ptr<AST::MacroMatchRepetition> Parser::parse_macro_match_repetition() { skip_token(DOLLAR_SIGN); skip_token(LEFT_PAREN); ::std::vector< ::std::unique_ptr<AST::MacroMatch> > matches; // parse required first macro match - AST::MacroMatch* initial_match = parse_macro_match(); + ::std::unique_ptr<AST::MacroMatch> initial_match = parse_macro_match(); if (initial_match == NULL) { error_at(lexer.peek_token()->get_locus(), "could not parse required first macro match in macro match repetition"); // skip after somewhere? return NULL; } - matches.push_back(::std::unique_ptr<AST::MacroMatch>(initial_match)); + matches.push_back(::std::move(initial_match)); // parse optional later macro matches const_TokenPtr t = lexer.peek_token(); while (t->get_id() != RIGHT_PAREN) { - AST::MacroMatch* match = parse_macro_match(); + ::std::unique_ptr<AST::MacroMatch> match = parse_macro_match(); if (match == NULL) { - break; + error_at(lexer.peek_token()->get_locus(), + "failed to parse macro match in macro match repetition"); + return NULL; } - matches.push_back(::std::unique_ptr<AST::MacroMatch>(match)); + matches.push_back(::std::move(match)); t = lexer.peek_token(); } @@ -1468,7 +1668,7 @@ namespace Rust { t = lexer.peek_token(); // see if separator token exists - AST::Token* separator = NULL; + ::std::unique_ptr<AST::Token> separator = NULL; switch (t->get_id()) { // repetition operators case ASTERISK: @@ -1481,12 +1681,11 @@ namespace Rust { case RIGHT_PAREN: case RIGHT_CURLY: case RIGHT_SQUARE: - // separator does not exist, so still null - lexer.skip_token(); + // separator does not exist, so still null and don't skip token break; default: // separator does exist - separator = new AST::Token(t); + separator = ::std::unique_ptr<AST::Token>(new AST::Token(t)); lexer.skip_token(); break; } @@ -1515,7 +1714,8 @@ namespace Rust { return NULL; } - return new AST::MacroMatchRepetition(::std::move(matches), op, separator); + return ::std::unique_ptr<AST::MacroMatchRepetition>( + new AST::MacroMatchRepetition(::std::move(matches), op, ::std::move(separator))); } // Parses a visibility syntactical production (i.e. creating a non-default visibility) @@ -1573,19 +1773,24 @@ namespace Rust { return AST::Visibility::create_in_path(::std::move(path)); } default: - unexpected_token(t); + error_at( + t->get_locus(), "unexpected token '%s' in visibility", t->get_token_description()); lexer.skip_token(); return AST::Visibility::create_error(); } } // Parses a module - either a bodied module or a module defined in another file. - AST::Module* Parser::parse_module( + ::std::unique_ptr<AST::Module> Parser::parse_module( AST::Visibility vis, ::std::vector<AST::Attribute> outer_attrs) { + location_t locus = lexer.peek_token()->get_locus(); skip_token(MOD); const_TokenPtr module_name = expect_token(IDENTIFIER); - // TODO: come back when module name has been implemented + if (module_name == NULL) { + return NULL; + } + Identifier name = module_name->get_str(); const_TokenPtr t = lexer.peek_token(); @@ -1593,8 +1798,8 @@ namespace Rust { case SEMICOLON: lexer.skip_token(); - return new AST::ModuleNoBody( - ::std::move(vis), ::std::move(outer_attrs)); // module name? + return ::std::unique_ptr<AST::ModuleNoBody>(new AST::ModuleNoBody(::std::move(name), + ::std::move(vis), ::std::move(outer_attrs), locus)); // module name? case LEFT_CURLY: { lexer.skip_token(); @@ -1602,23 +1807,42 @@ namespace Rust { ::std::vector<AST::Attribute> inner_attrs = parse_inner_attributes(); // parse items - ::std::vector< ::std::unique_ptr<AST::Item> > items = parse_items(); + ::std::vector< ::std::unique_ptr<AST::Item> > items; + const_TokenPtr tok = lexer.peek_token(); + while (tok->get_id() != RIGHT_CURLY) { + ::std::unique_ptr<AST::Item> item = parse_item(false); + if (item == NULL) { + error_at(tok->get_locus(), "failed to parse item in module"); + return NULL; + } + + items.push_back(::std::move(item)); - skip_token(RIGHT_CURLY); + tok = lexer.peek_token(); + } - return new AST::ModuleBodied(::std::move(items), ::std::move(vis), - ::std::move(inner_attrs), ::std::move(outer_attrs)); // module name? + if (!skip_token(RIGHT_CURLY)) { + // skip somewhere? + return NULL; + } + + return ::std::unique_ptr<AST::ModuleBodied>(new AST::ModuleBodied(::std::move(name), + locus, ::std::move(items), ::std::move(vis), ::std::move(inner_attrs), + ::std::move(outer_attrs))); // module name? } default: - unexpected_token(t); + error_at(t->get_locus(), + "unexpected token '%s' in module declaration/definition item", + t->get_token_description()); lexer.skip_token(); return NULL; } } // Parses an extern crate declaration (dependency on external crate) - AST::ExternCrate* Parser::parse_extern_crate( + ::std::unique_ptr<AST::ExternCrate> Parser::parse_extern_crate( AST::Visibility vis, ::std::vector<AST::Attribute> outer_attrs) { + location_t locus = lexer.peek_token()->get_locus(); if (!skip_token(EXTERN_TOK)) { skip_after_semicolon(); return NULL; @@ -1655,7 +1879,8 @@ namespace Rust { if (lexer.peek_token()->get_id() == SEMICOLON) { lexer.skip_token(); - return new AST::ExternCrate(crate_name, vis, outer_attrs); + return ::std::unique_ptr<AST::ExternCrate>(new AST::ExternCrate( + ::std::move(crate_name), ::std::move(vis), ::std::move(outer_attrs), locus)); } /* parse as clause - this also has its own syntactical rule in reference and also seems to @@ -1690,20 +1915,21 @@ namespace Rust { return NULL; } - return new AST::ExternCrate( - ::std::move(crate_name), ::std::move(vis), ::std::move(outer_attrs), ::std::move(as_name)); + return ::std::unique_ptr<AST::ExternCrate>(new AST::ExternCrate(::std::move(crate_name), + ::std::move(vis), ::std::move(outer_attrs), locus, ::std::move(as_name))); } // Parses a use declaration. - AST::UseDeclaration* Parser::parse_use_decl( + ::std::unique_ptr<AST::UseDeclaration> Parser::parse_use_decl( AST::Visibility vis, ::std::vector<AST::Attribute> outer_attrs) { + location_t locus = lexer.peek_token()->get_locus(); if (!skip_token(USE)) { skip_after_semicolon(); return NULL; } // parse use tree, which is required - AST::UseTree* use_tree = parse_use_tree(); + ::std::unique_ptr<AST::UseTree> use_tree = parse_use_tree(); if (use_tree == NULL) { error_at(lexer.peek_token()->get_locus(), "could not parse use tree in use declaration"); skip_after_semicolon(); @@ -1715,11 +1941,12 @@ namespace Rust { return NULL; } - return new AST::UseDeclaration(use_tree, ::std::move(vis), ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::UseDeclaration>(new AST::UseDeclaration( + ::std::move(use_tree), ::std::move(vis), ::std::move(outer_attrs), locus)); } // Parses a use tree (which can be recursive and is actually a base class). - AST::UseTree* Parser::parse_use_tree() { + ::std::unique_ptr<AST::UseTree> Parser::parse_use_tree() { /* potential syntax definitions in attempt to get algorithm: * Glob: * <- SimplePath :: * @@ -1744,6 +1971,8 @@ namespace Rust { // TODO: I think this function is too complex, probably should split it + location_t locus = lexer.peek_token()->get_locus(); + // bool has_path = false; AST::SimplePath path = parse_simple_path(); @@ -1767,8 +1996,8 @@ namespace Rust { lexer.skip_token(); // TODO: find way to determine whether GLOBAL or NO_PATH path type - placeholder - return new AST::UseTreeGlob( - AST::UseTreeGlob::NO_PATH, AST::SimplePath::create_empty()); + return ::std::unique_ptr<AST::UseTreeGlob>(new AST::UseTreeGlob( + AST::UseTreeGlob::NO_PATH, AST::SimplePath::create_empty(), locus)); case LEFT_CURLY: { // nested tree UseTree type lexer.skip_token(); @@ -1777,12 +2006,12 @@ namespace Rust { const_TokenPtr t = lexer.peek_token(); while (t->get_id() != RIGHT_CURLY) { - AST::UseTree* use_tree = parse_use_tree(); + ::std::unique_ptr<AST::UseTree> use_tree = parse_use_tree(); if (use_tree == NULL) { break; } - use_trees.push_back(::std::unique_ptr<AST::UseTree>(use_tree)); + use_trees.push_back(::std::move(use_tree)); if (lexer.peek_token()->get_id() != COMMA) { break; @@ -1799,8 +2028,9 @@ namespace Rust { } // TODO: find way to determine whether GLOBAL or NO_PATH path type - placeholder - return new AST::UseTreeList(AST::UseTreeList::NO_PATH, - AST::SimplePath::create_empty(), ::std::move(use_trees)); + return ::std::unique_ptr<AST::UseTreeList>( + new AST::UseTreeList(AST::UseTreeList::NO_PATH, AST::SimplePath::create_empty(), + ::std::move(use_trees), locus)); } case AS: // this is not allowed @@ -1809,7 +2039,10 @@ namespace Rust { skip_after_semicolon(); return NULL; default: - unexpected_token(t); + error_at(t->get_locus(), + "unexpected token '%s' in use tree with no valid simple path (i.e. list or " + "glob use tree)", + t->get_token_description()); skip_after_semicolon(); return NULL; } @@ -1823,7 +2056,8 @@ namespace Rust { // glob UseTree type lexer.skip_token(); - return new AST::UseTreeGlob(AST::UseTreeGlob::PATH_PREFIXED, ::std::move(path)); + return ::std::unique_ptr<AST::UseTreeGlob>(new AST::UseTreeGlob( + AST::UseTreeGlob::PATH_PREFIXED, ::std::move(path), locus)); case LEFT_CURLY: { // nested tree UseTree type lexer.skip_token(); @@ -1833,12 +2067,12 @@ namespace Rust { // TODO: think of better control structure const_TokenPtr t = lexer.peek_token(); while (t->get_id() != RIGHT_CURLY) { - AST::UseTree* use_tree = parse_use_tree(); + ::std::unique_ptr<AST::UseTree> use_tree = parse_use_tree(); if (use_tree == NULL) { break; } - use_trees.push_back(::std::unique_ptr<AST::UseTree>(use_tree)); + use_trees.push_back(::std::move(use_tree)); if (lexer.peek_token()->get_id() != COMMA) { break; @@ -1854,8 +2088,9 @@ namespace Rust { return NULL; } - return new AST::UseTreeList( - AST::UseTreeList::PATH_PREFIXED, ::std::move(path), std::move(use_trees)); + return ::std::unique_ptr<AST::UseTreeList>( + new AST::UseTreeList(AST::UseTreeList::PATH_PREFIXED, ::std::move(path), + std::move(use_trees), locus)); } case AS: { // rebind UseTree type @@ -1867,16 +2102,21 @@ namespace Rust { // skip lexer token lexer.skip_token(); - return new AST::UseTreeRebind( - AST::UseTreeRebind::IDENTIFIER, ::std::move(path), t->get_str()); + return ::std::unique_ptr<AST::UseTreeRebind>( + new AST::UseTreeRebind(AST::UseTreeRebind::IDENTIFIER, + ::std::move(path), locus, t->get_str())); case UNDERSCORE: // skip lexer token lexer.skip_token(); - return new AST::UseTreeRebind( - AST::UseTreeRebind::WILDCARD, ::std::move(path), ::std::string("_")); + return ::std::unique_ptr<AST::UseTreeRebind>( + new AST::UseTreeRebind(AST::UseTreeRebind::WILDCARD, ::std::move(path), + locus, ::std::string("_"))); default: - unexpected_token(t); + error_at(t->get_locus(), + "unexpected token '%s' in use tree with as clause - expected " + "identifier or '_'", + t->get_token_description()); skip_after_semicolon(); return NULL; } @@ -1887,13 +2127,16 @@ namespace Rust { // don't skip semicolon - handled in parse_use_tree // lexer.skip_token(); - return new AST::UseTreeRebind(AST::UseTreeRebind::NONE, ::std::move(path)); + return ::std::unique_ptr<AST::UseTreeRebind>( + new AST::UseTreeRebind(AST::UseTreeRebind::NONE, ::std::move(path), locus)); case COMMA: case RIGHT_CURLY: // this may occur in recursive calls - assume it is ok and ignore it - return new AST::UseTreeRebind(AST::UseTreeRebind::NONE, ::std::move(path)); + return ::std::unique_ptr<AST::UseTreeRebind>( + new AST::UseTreeRebind(AST::UseTreeRebind::NONE, ::std::move(path), locus)); default: - unexpected_token(t); + error_at(t->get_locus(), "unexpected token '%s' in use tree with valid path", + t->get_token_description()); // skip_after_semicolon(); return NULL; } @@ -1901,8 +2144,9 @@ namespace Rust { } // Parses a function (not a method). - AST::Function* Parser::parse_function( + ::std::unique_ptr<AST::Function> Parser::parse_function( AST::Visibility vis, ::std::vector<AST::Attribute> outer_attrs) { + location_t locus = lexer.peek_token()->get_locus(); // Get qualifiers for function if they exist AST::FunctionQualifiers qualifiers = parse_function_qualifiers(); @@ -1911,7 +2155,7 @@ namespace Rust { // Save function name token const_TokenPtr function_name_tok = expect_token(IDENTIFIER); if (function_name_tok == NULL) { - skip_after_end_block(); + skip_after_next_block(); return NULL; } Identifier function_name = function_name_tok->get_str(); @@ -1923,7 +2167,7 @@ namespace Rust { if (!skip_token(LEFT_PAREN)) { error_at(lexer.peek_token()->get_locus(), "function declaration missing opening parentheses before parameter list"); - skip_after_end_block(); + skip_after_next_block(); return NULL; } @@ -1936,22 +2180,23 @@ namespace Rust { if (!skip_token(RIGHT_PAREN)) { error_at(lexer.peek_token()->get_locus(), "function declaration missing closing parentheses after parameter list"); - skip_after_end_block(); + skip_after_next_block(); return NULL; } // parse function return type - if exists - AST::Type* return_type = parse_function_return_type(); + ::std::unique_ptr<AST::Type> return_type = parse_function_return_type(); // parse where clause - if exists AST::WhereClause where_clause = parse_where_clause(); // parse block expression - AST::BlockExpr* block_expr = parse_block_expr(); + ::std::unique_ptr<AST::BlockExpr> block_expr = parse_block_expr(); - return new AST::Function(::std::move(function_name), ::std::move(qualifiers), - ::std::move(generic_params), ::std::move(function_params), return_type, - ::std::move(where_clause), block_expr, ::std::move(vis), ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::Function>(new AST::Function(::std::move(function_name), + ::std::move(qualifiers), ::std::move(generic_params), ::std::move(function_params), + ::std::move(return_type), ::std::move(where_clause), ::std::move(block_expr), + ::std::move(vis), ::std::move(outer_attrs), locus)); } // Parses function or method qualifiers (i.e. const, unsafe, and extern). @@ -2006,9 +2251,18 @@ namespace Rust { } lexer.skip_token(); + // DEBUG: + fprintf(stderr, "skipped left angle in generic param\n"); + ::std::vector< ::std::unique_ptr<AST::GenericParam> > generic_params = parse_generic_params(); - if (!skip_token(RIGHT_ANGLE)) { + // DEBUG: + fprintf(stderr, "finished parsing actual generic params (i.e. inside angles)\n"); + + if (!skip_generics_right_angle()) { + // DEBUG + fprintf(stderr, "failed to skip generics right angle - returning empty generic params\n"); + return ::std::vector< ::std::unique_ptr<AST::GenericParam> >(); } @@ -2020,6 +2274,138 @@ namespace Rust { ::std::vector< ::std::unique_ptr<AST::GenericParam> > Parser::parse_generic_params() { ::std::vector< ::std::unique_ptr<AST::GenericParam> > generic_params; + // can't parse lifetime and type params separately due to lookahead issues + // thus, parse them all here + + // DEBUG + fprintf(stderr, "starting to parse generic params (inside angle brackets)\n"); + + // HACK: used to retain attribute data if a lifetime param is tentatively parsed but it turns + // out to be type param + AST::Attribute parsed_outer_attr = AST::Attribute::create_empty(); + + // HACK: generic params always in angle brackets with current syntax, so have that as end char + const_TokenPtr t = lexer.peek_token(); + // parse lifetime params + while (!is_right_angle_tok(t->get_id())) { + // HACK: reimpl of lifetime param parsing + AST::Attribute outer_attr = parse_outer_attribute(); + + // move attribute outward if type param + if (lexer.peek_token()->get_id() != LIFETIME) { + parsed_outer_attr = ::std::move(outer_attr); + + // DEBUG + fprintf(stderr, "broke from parsing lifetime params as next token isn't lifetime - " + "saved attribute\n"); + + break; + } + + location_t locus = lexer.peek_token()->get_locus(); + AST::Lifetime lifetime = parse_lifetime(); + + // DEBUG + fprintf(stderr, "parsed lifetime in lifetime params\n"); + + // parse optional bounds + ::std::vector<AST::Lifetime> lifetime_bounds; + if (lexer.peek_token()->get_id() == COLON) { + lexer.skip_token(); + // parse required bounds + lifetime_bounds = parse_lifetime_bounds(); + } + + ::std::unique_ptr<AST::LifetimeParam> param(new AST::LifetimeParam( + ::std::move(lifetime), locus, ::std::move(lifetime_bounds), ::std::move(outer_attr))); + generic_params.push_back(::std::move(param)); + + if (lexer.peek_token()->get_id() != COMMA) { + break; + } + lexer.skip_token(); + + t = lexer.peek_token(); + } + + // parse type params (reimpl required for first one but not others) + if (!is_right_angle_tok(lexer.peek_token()->get_id()) && !parsed_outer_attr.is_empty()) { + // DEBUG + fprintf(stderr, "as parsed outer attr isn't empty, started parsing type param reimpl\n"); + + // reimpl as type param definitely exists + const_TokenPtr ident_tok = expect_token(IDENTIFIER); + if (ident_tok == NULL) { + error_at(lexer.peek_token()->get_locus(), + "failed to parse identifier in type param in generic params"); + return ::std::vector< ::std::unique_ptr<AST::GenericParam> >(); + } + Identifier ident = ident_tok->get_str(); + + // parse optional bounds + ::std::vector< ::std::unique_ptr<AST::TypeParamBound> > type_param_bounds; + if (lexer.peek_token()->get_id() == COLON) { + lexer.skip_token(); + + // parse optional type param bounds + type_param_bounds = parse_type_param_bounds(); + } + + // parse optional type + ::std::unique_ptr<AST::Type> type = NULL; + if (lexer.peek_token()->get_id() == EQUAL) { + lexer.skip_token(); + + // parse required type + type = parse_type(); + if (type == NULL) { + error_at(lexer.peek_token()->get_id(), + "failed to parse type in type param in generic params"); + return ::std::vector< ::std::unique_ptr<AST::GenericParam> >(); + } + } + + ::std::unique_ptr<AST::TypeParam> param( + new AST::TypeParam(::std::move(ident), ident_tok->get_locus(), + ::std::move(type_param_bounds), ::std::move(type), ::std::move(parsed_outer_attr))); + generic_params.push_back(::std::move(param)); + + // handle comma + if (lexer.peek_token()->get_id() == COMMA) { + lexer.skip_token(); + } + } + + // DEBUG + fprintf(stderr, "about to start parsing normally-parsed type params in generic params\n"); + + // parse rest of type params - reimpl due to right angle tokens + t = lexer.peek_token(); + while (!is_right_angle_tok(t->get_id())) { + ::std::unique_ptr<AST::TypeParam> type_param = parse_type_param(); + + if (type_param == NULL) { + error_at( + lexer.peek_token()->get_locus(), "failed to parse type param in generic params"); + return ::std::vector< ::std::unique_ptr<AST::GenericParam> >(); + } + + // DEBUG + fprintf(stderr, "successfully parsed type param\n"); + + generic_params.push_back(::std::move(type_param)); + + if (lexer.peek_token()->get_id() != COMMA) { + break; + } + // skip commas, including trailing commas + lexer.skip_token(); + + t = lexer.peek_token(); + } + + // old code + /* // parse lifetime params (optional), allowed to end with a trailing comma ::std::vector< ::std::unique_ptr<AST::LifetimeParam> > lifetime_params = parse_lifetime_params(); @@ -2028,10 +2414,6 @@ namespace Rust { generic_params.insert(generic_params.end(), ::std::make_move_iterator(lifetime_params.begin()), ::std::make_move_iterator(lifetime_params.end())); - - // placeholder code - /*generic_params.insert( - generic_params.end(), lifetime_params.begin(), lifetime_params.end());*/ } // parse type params (optional) @@ -2041,10 +2423,7 @@ namespace Rust { generic_params.insert(generic_params.end(), ::std::make_move_iterator(type_params.begin()), ::std::make_move_iterator(type_params.end())); - - // placeholder code - // generic_params.insert(generic_params.end(), type_params.begin(), type_params.end()); - } + }*/ return generic_params; } @@ -2113,7 +2492,8 @@ namespace Rust { return AST::LifetimeParam::create_error(); } // TODO: does this always create a named lifetime? or can a different type be made? - AST::Lifetime lifetime(AST::Lifetime::NAMED, lifetime_tok->get_str()); + AST::Lifetime lifetime( + AST::Lifetime::NAMED, lifetime_tok->get_str(), lifetime_tok->get_locus()); // parse lifetime bounds, if it exists ::std::vector<AST::Lifetime> lifetime_bounds; @@ -2122,8 +2502,8 @@ namespace Rust { lifetime_bounds = parse_lifetime_bounds(); } - return AST::LifetimeParam( - ::std::move(lifetime), ::std::move(lifetime_bounds), ::std::move(outer_attr)); + return AST::LifetimeParam(::std::move(lifetime), lifetime_tok->get_locus(), + ::std::move(lifetime_bounds), ::std::move(outer_attr)); } // Parses type generic parameters. Will also consume any trailing comma. @@ -2132,14 +2512,14 @@ namespace Rust { // TODO: think of better control structure than infinite loop with break on failure? while (true) { - AST::TypeParam* type_param = parse_type_param(); + ::std::unique_ptr<AST::TypeParam> type_param = parse_type_param(); if (type_param == NULL) { // break if fails to parse break; } - type_params.push_back(::std::unique_ptr<AST::TypeParam>(type_param)); + type_params.push_back(::std::move(type_param)); if (lexer.peek_token()->get_id() != COMMA) { break; @@ -2153,7 +2533,7 @@ namespace Rust { } // Parses a single type (generic) parameter, not including commas. May change to return value. - AST::TypeParam* Parser::parse_type_param() { + ::std::unique_ptr<AST::TypeParam> Parser::parse_type_param() { // parse outer attribute, which is optional and may not exist AST::Attribute outer_attr = parse_outer_attribute(); @@ -2164,45 +2544,44 @@ namespace Rust { } // TODO: create identifier from identifier token Identifier ident = identifier_tok->get_str(); + lexer.skip_token(); - // branch to type param bounds or type or none based on next token - const_TokenPtr t = lexer.peek_token(); - switch (t->get_id()) { - case COLON: { - lexer.skip_token(); - - // parse type param bounds, which may or may not exist - ::std::vector< ::std::unique_ptr<AST::TypeParamBound> > type_param_bounds - = parse_type_param_bounds(); + // parse type param bounds (if they exist) + ::std::vector< ::std::unique_ptr<AST::TypeParamBound> > type_param_bounds; + if (lexer.peek_token()->get_id() == COLON) { + lexer.skip_token(); - // TODO: is move required here? - return new AST::TypeParam( - ::std::move(ident), ::std::move(type_param_bounds), NULL, ::std::move(outer_attr)); - } - case EQUAL: { - lexer.skip_token(); + // parse type param bounds, which may or may not exist + type_param_bounds = parse_type_param_bounds(); + } - // parse type - AST::Type* type = parse_type(); + // parse type (if it exists) + ::std::unique_ptr<AST::Type> type = NULL; + if (lexer.peek_token()->get_id() == EQUAL) { + lexer.skip_token(); - return new AST::TypeParam(::std::move(ident), - ::std::vector< ::std::unique_ptr<AST::TypeParamBound> >(), type, - ::std::move(outer_attr)); + // parse type (now required) + type = parse_type(); + if (type == NULL) { + error_at(lexer.peek_token()->get_locus(), "failed to parse type in type param"); + return NULL; } - default: - // Best assumption is that this is the end of the type param - return new AST::TypeParam(::std::move(ident), - ::std::vector< ::std::unique_ptr<AST::TypeParamBound> >(), NULL, - ::std::move(outer_attr)); } - // Stop the "control passes without return" error. - gcc_unreachable(); + + return ::std::unique_ptr<AST::TypeParam>( + new AST::TypeParam(::std::move(ident), identifier_tok->get_locus(), + ::std::move(type_param_bounds), ::std::move(type), ::std::move(outer_attr))); } // Parses regular (i.e. non-generic) parameters in functions or methods. ::std::vector<AST::FunctionParam> Parser::parse_function_params() { ::std::vector<AST::FunctionParam> params; + // HACK: return early if RIGHT_PAREN is found + if (lexer.peek_token()->get_id() == RIGHT_PAREN) { + return params; + } + AST::FunctionParam initial_param = parse_function_param(); // Return empty parameter list if no parameter there @@ -2210,26 +2589,33 @@ namespace Rust { return params; } - params.push_back(initial_param); + params.push_back(::std::move(initial_param)); // maybe think of a better control structure here - do-while with an initial error state? // basically, loop through parameter list until can't find any more params - while (true) { - if (lexer.peek_token()->get_id() != COMMA) { - break; - } - + const_TokenPtr t = lexer.peek_token(); + while (t->get_id() == COMMA) { // skip comma if applies lexer.skip_token(); - AST::FunctionParam param = parse_function_param(); - - if (!param.is_error()) { - params.push_back(param); - } else { - // this would occur with a trailing comma, which is allowed + /* HACK: break if next token is a right (closing) paren - this is not strictly true via + * grammar rule but seems to be true in practice (i.e. with trailing comma). */ + if (lexer.peek_token()->get_id() == RIGHT_PAREN) { break; } + + // now, as right paren would break, function param is required + AST::FunctionParam param = parse_function_param(); + if (param.is_error()) { + error_at(lexer.peek_token()->get_locus(), + "failed to parse function param (in function params)"); + // skip somewhere? + return ::std::vector<AST::FunctionParam>(); + } + + params.push_back(::std::move(param)); + + t = lexer.peek_token(); } return params; @@ -2238,7 +2624,8 @@ namespace Rust { /* Parses a single regular (i.e. non-generic) parameter in a function or method, i.e. the * "name: type" bit. Also handles it not existing. */ AST::FunctionParam Parser::parse_function_param() { - AST::Pattern* param_pattern = parse_pattern(); + location_t locus = lexer.peek_token()->get_locus(); + ::std::unique_ptr<AST::Pattern> param_pattern = parse_pattern(); // create error function param if it doesn't exist if (param_pattern == NULL) { @@ -2251,25 +2638,25 @@ namespace Rust { return AST::FunctionParam::create_error(); } - AST::Type* param_type = parse_type(); + ::std::unique_ptr<AST::Type> param_type = parse_type(); if (param_type == NULL) { // skip? return AST::FunctionParam::create_error(); } - return AST::FunctionParam(param_pattern, param_type); + return AST::FunctionParam(::std::move(param_pattern), ::std::move(param_type), locus); } /* Parses a function or method return type syntactical construction. Also handles a function * return type not existing. */ - AST::Type* Parser::parse_function_return_type() { + ::std::unique_ptr<AST::Type> Parser::parse_function_return_type() { if (lexer.peek_token()->get_id() != RETURN_TYPE) { return NULL; } // skip return type, as it now obviously exists lexer.skip_token(); - AST::Type* type = parse_type(); + ::std::unique_ptr<AST::Type> type = parse_type(); return type; } @@ -2289,29 +2676,32 @@ namespace Rust { // parse where clause items - this is not a separate rule in the reference so won't be here ::std::vector< ::std::unique_ptr<AST::WhereClauseItem> > where_clause_items; - // TODO: think of better control structure - do-while loop? - while (true) { - AST::WhereClauseItem* where_clause_item = parse_where_clause_item(); + // HACK: where clauses end with a right curly or semicolon or equals in all uses currently + const_TokenPtr t = lexer.peek_token(); + while (t->get_id() != LEFT_CURLY && t->get_id() != SEMICOLON && t->get_id() != EQUAL) { + ::std::unique_ptr<AST::WhereClauseItem> where_clause_item = parse_where_clause_item(); if (where_clause_item == NULL) { - // exit if parse failed - break; + error_at(t->get_locus(), "failed to parse where clause item"); + return AST::WhereClause::create_empty(); } - where_clause_items.push_back(::std::unique_ptr<AST::WhereClauseItem>(where_clause_item)); + where_clause_items.push_back(::std::move(where_clause_item)); // also skip comma if it exists - if (lexer.peek_token()->get_id() == COMMA) { - lexer.skip_token(); + if (lexer.peek_token()->get_id() != COMMA) { + break; } + lexer.skip_token(); + + t = lexer.peek_token(); } - // TODO: is move required here? return AST::WhereClause(::std::move(where_clause_items)); } // Parses a where clause item (lifetime or type bound). Does not parse any commas. - AST::WhereClauseItem* Parser::parse_where_clause_item() { + ::std::unique_ptr<AST::WhereClauseItem> Parser::parse_where_clause_item() { // shitty cheat way of determining lifetime or type bound - test for lifetime const_TokenPtr t = lexer.peek_token(); @@ -2323,7 +2713,7 @@ namespace Rust { } // Parses a lifetime where clause item. - AST::LifetimeWhereClauseItem* Parser::parse_lifetime_where_clause_item() { + ::std::unique_ptr<AST::LifetimeWhereClauseItem> Parser::parse_lifetime_where_clause_item() { AST::Lifetime lifetime = parse_lifetime(); if (lifetime.is_error()) { // TODO: error here? @@ -2337,15 +2727,19 @@ namespace Rust { ::std::vector<AST::Lifetime> lifetime_bounds = parse_lifetime_bounds(); - return new AST::LifetimeWhereClauseItem(::std::move(lifetime), ::std::move(lifetime_bounds)); + return ::std::unique_ptr<AST::LifetimeWhereClauseItem>( + new AST::LifetimeWhereClauseItem(::std::move(lifetime), ::std::move(lifetime_bounds))); } // Parses a type bound where clause item. - AST::TypeBoundWhereClauseItem* Parser::parse_type_bound_where_clause_item() { - // parse for lifetimes, if it exists (although empty for lifetimes is ok to handle this) - ::std::vector<AST::LifetimeParam> for_lifetimes = parse_for_lifetimes(); + ::std::unique_ptr<AST::TypeBoundWhereClauseItem> Parser::parse_type_bound_where_clause_item() { + // parse for lifetimes, if it exists + ::std::vector<AST::LifetimeParam> for_lifetimes; + if (lexer.peek_token()->get_id() == FOR) { + for_lifetimes = parse_for_lifetimes(); + } - AST::Type* type = parse_type(); + ::std::unique_ptr<AST::Type> type = parse_type(); if (type == NULL) { return NULL; } @@ -2359,8 +2753,8 @@ namespace Rust { ::std::vector< ::std::unique_ptr<AST::TypeParamBound> > type_param_bounds = parse_type_param_bounds(); - return new AST::TypeBoundWhereClauseItem( - ::std::move(for_lifetimes), type, ::std::move(type_param_bounds)); + return ::std::unique_ptr<AST::TypeBoundWhereClauseItem>(new AST::TypeBoundWhereClauseItem( + ::std::move(for_lifetimes), ::std::move(type), ::std::move(type_param_bounds))); } // Parses a for lifetimes clause, including the for keyword and angle brackets. @@ -2379,7 +2773,7 @@ namespace Rust { params = parse_lifetime_params_objs(); - if (!skip_token(RIGHT_ANGLE)) { + if (!skip_generics_right_angle()) { // skip after somewhere? return params; } @@ -2391,7 +2785,7 @@ namespace Rust { ::std::vector< ::std::unique_ptr<AST::TypeParamBound> > Parser::parse_type_param_bounds() { ::std::vector< ::std::unique_ptr<AST::TypeParamBound> > type_param_bounds; - AST::TypeParamBound* initial_bound = parse_type_param_bound(); + ::std::unique_ptr<AST::TypeParamBound> initial_bound = parse_type_param_bound(); // quick exit if null if (initial_bound == NULL) { @@ -2399,7 +2793,7 @@ namespace Rust { return type_param_bounds; } - type_param_bounds.push_back(::std::unique_ptr<AST::TypeParamBound>(initial_bound)); + type_param_bounds.push_back(::std::move(initial_bound)); // TODO think of better control structure than infinite loop while (true) { @@ -2409,13 +2803,13 @@ namespace Rust { } lexer.skip_token(); - AST::TypeParamBound* bound = parse_type_param_bound(); + ::std::unique_ptr<AST::TypeParamBound> bound = parse_type_param_bound(); if (bound == NULL) { // not an error: bound is allowed to be null as trailing plus is allowed return type_param_bounds; } - type_param_bounds.push_back(::std::unique_ptr<AST::TypeParamBound>(bound)); + type_param_bounds.push_back(::std::move(bound)); } return type_param_bounds; @@ -2423,12 +2817,12 @@ namespace Rust { /* Parses a single type parameter bound in a where clause or generic argument. Does not parse * the '+' between arguments. */ - AST::TypeParamBound* Parser::parse_type_param_bound() { + ::std::unique_ptr<AST::TypeParamBound> Parser::parse_type_param_bound() { // shitty cheat way of determining lifetime or trait bound - test for lifetime const_TokenPtr t = lexer.peek_token(); switch (t->get_id()) { case LIFETIME: - return new AST::Lifetime(parse_lifetime()); + return ::std::unique_ptr<AST::Lifetime>(new AST::Lifetime(parse_lifetime())); case LEFT_PAREN: case QUESTION_MARK: case FOR: @@ -2446,10 +2840,12 @@ namespace Rust { } // Parses a trait bound type param bound. - AST::TraitBound* Parser::parse_trait_bound() { + ::std::unique_ptr<AST::TraitBound> Parser::parse_trait_bound() { bool has_parens = false; bool has_question_mark = false; + location_t locus = lexer.peek_token()->get_locus(); + // handle trait bound being in parentheses if (lexer.peek_token()->get_id() == LEFT_PAREN) { has_parens = true; @@ -2478,8 +2874,8 @@ namespace Rust { } } - return new AST::TraitBound( - ::std::move(type_path), has_parens, has_question_mark, ::std::move(for_lifetimes)); + return ::std::unique_ptr<AST::TraitBound>(new AST::TraitBound( + ::std::move(type_path), locus, has_parens, has_question_mark, ::std::move(for_lifetimes))); } // Parses lifetime bounds. @@ -2495,7 +2891,7 @@ namespace Rust { return lifetime_bounds; } - lifetime_bounds.push_back(lifetime); + lifetime_bounds.push_back(::std::move(lifetime)); // plus is maybe required - spec defines it poorly, so assuming not required if (lexer.peek_token()->get_id() != PLUS) { @@ -2508,28 +2904,31 @@ namespace Rust { return lifetime_bounds; } - // Parses a lifetime token (named, 'static, or '_). + // Parses a lifetime token (named, 'static, or '_). Also handles lifetime not existing. AST::Lifetime Parser::parse_lifetime() { - const_TokenPtr lifetime_tok = expect_token(LIFETIME); + const_TokenPtr lifetime_tok = lexer.peek_token(); + location_t locus = lifetime_tok->get_locus(); // create error lifetime if doesn't exist - if (lifetime_tok == NULL) { + if (lifetime_tok->get_id() != LIFETIME) { return AST::Lifetime::error(); } + lexer.skip_token(); ::std::string lifetime_ident = lifetime_tok->get_str(); if (lifetime_ident == "'static") { - return AST::Lifetime(AST::Lifetime::STATIC); + return AST::Lifetime(AST::Lifetime::STATIC, "", locus); } else if (lifetime_ident == "'_") { - return AST::Lifetime(AST::Lifetime::WILDCARD); + return AST::Lifetime(AST::Lifetime::WILDCARD, "", locus); } else { - return AST::Lifetime(AST::Lifetime::NAMED, ::std::move(lifetime_ident)); + return AST::Lifetime(AST::Lifetime::NAMED, ::std::move(lifetime_ident), locus); } } // Parses a "type alias" (typedef) item. - AST::TypeAlias* Parser::parse_type_alias( + ::std::unique_ptr<AST::TypeAlias> Parser::parse_type_alias( AST::Visibility vis, ::std::vector<AST::Attribute> outer_attrs) { + location_t locus = lexer.peek_token()->get_locus(); skip_token(TYPE); // TODO: use this token for identifier when finished that @@ -2553,19 +2952,20 @@ namespace Rust { return NULL; } - AST::Type* type_to_alias = parse_type(); + ::std::unique_ptr<AST::Type> type_to_alias = parse_type(); if (!skip_token(SEMICOLON)) { // should be skipping past this, not the next line return NULL; } - return new AST::TypeAlias(::std::move(alias_name), ::std::move(generic_params), - ::std::move(where_clause), type_to_alias, ::std::move(vis), ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::TypeAlias>(new AST::TypeAlias(::std::move(alias_name), + ::std::move(generic_params), ::std::move(where_clause), ::std::move(type_to_alias), + ::std::move(vis), ::std::move(outer_attrs), locus)); } // Parse a struct item AST node. - AST::Struct* Parser::parse_struct( + ::std::unique_ptr<AST::Struct> Parser::parse_struct( AST::Visibility vis, ::std::vector<AST::Attribute> outer_attrs) { /* TODO: determine best way to parse the proper struct vs tuple struct - share most of * initial constructs so lookahead might be impossible, and if not probably too expensive. @@ -2577,7 +2977,7 @@ namespace Rust { * | ';' ) */ /* Tuple struct <- 'struct' IDENTIFIER generic_params? '(' tuple_fields? ')' * where_clause? ';' */ - + location_t locus = lexer.peek_token()->get_locus(); skip_token(STRUCT_TOK); // parse struct name @@ -2618,9 +3018,9 @@ namespace Rust { return NULL; } - return new AST::TupleStruct(::std::move(tuple_fields), ::std::move(struct_name), - ::std::move(generic_params), ::std::move(where_clause), ::std::move(vis), - ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::TupleStruct>(new AST::TupleStruct(::std::move(tuple_fields), + ::std::move(struct_name), ::std::move(generic_params), ::std::move(where_clause), + ::std::move(vis), ::std::move(outer_attrs), locus)); } // assume it is a proper struct being parsed and continue outside of switch - label only here @@ -2646,17 +3046,19 @@ namespace Rust { return NULL; } - return new AST::StructStruct(::std::move(struct_fields), ::std::move(struct_name), - ::std::move(generic_params), ::std::move(where_clause), false, ::std::move(vis), - ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::StructStruct>( + new AST::StructStruct(::std::move(struct_fields), ::std::move(struct_name), + ::std::move(generic_params), ::std::move(where_clause), false, ::std::move(vis), + ::std::move(outer_attrs), locus)); } case SEMICOLON: // unit struct declaration lexer.skip_token(); - return new AST::StructStruct(::std::move(struct_name), ::std::move(generic_params), - ::std::move(where_clause), ::std::move(vis), ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::StructStruct>( + new AST::StructStruct(::std::move(struct_name), ::std::move(generic_params), + ::std::move(where_clause), ::std::move(vis), ::std::move(outer_attrs), locus)); default: error_at(t->get_locus(), "unexpected token '%s' in struct declaration", t->get_token_description()); @@ -2676,7 +3078,7 @@ namespace Rust { return fields; } - fields.push_back(initial_field); + fields.push_back(::std::move(initial_field)); // maybe think of a better control structure here - do-while with an initial error state? // basically, loop through field list until can't find any more params @@ -2691,7 +3093,7 @@ namespace Rust { AST::StructField field = parse_struct_field(); if (!field.is_error()) { - fields.push_back(field); + fields.push_back(::std::move(field)); } else { // this would occur with a trailing comma, which is allowed break; @@ -2726,7 +3128,7 @@ namespace Rust { } // parse field type - this is required - AST::Type* field_type = parse_type(); + ::std::unique_ptr<AST::Type> field_type = parse_type(); if (field_type == NULL) { error_at( lexer.peek_token()->get_locus(), "could not parse type in struct field definition"); @@ -2734,8 +3136,8 @@ namespace Rust { return AST::StructField::create_error(); } - return AST::StructField( - ::std::move(field_name), field_type, ::std::move(vis), ::std::move(outer_attrs)); + return AST::StructField(::std::move(field_name), ::std::move(field_type), ::std::move(vis), + ::std::move(outer_attrs)); } // Parses tuple fields in tuple/tuple struct declarations. @@ -2749,26 +3151,31 @@ namespace Rust { return fields; } - fields.push_back(initial_field); + fields.push_back(::std::move(initial_field)); // maybe think of a better control structure here - do-while with an initial error state? // basically, loop through field list until can't find any more params - while (true) { - if (lexer.peek_token()->get_id() != COMMA) { + // HACK: all current syntax uses of tuple fields have them ending with a right paren token + const_TokenPtr t = lexer.peek_token(); + while (t->get_id() == COMMA) { + // skip comma if applies - e.g. trailing comma + lexer.skip_token(); + + // break out due to right paren if it exists + if (lexer.peek_token()->get_id() == RIGHT_PAREN) { break; } - // skip comma if applies - lexer.skip_token(); - AST::TupleField field = parse_tuple_field(); - - if (!field.is_error()) { - fields.push_back(field); - } else { - // this would occur with a trailing comma, which is allowed - break; + if (field.is_error()) { + error_at( + lexer.peek_token()->get_locus(), "failed to parse tuple field in tuple fields"); + return ::std::vector<AST::TupleField>(); } + + fields.push_back(::std::move(field)); + + t = lexer.peek_token(); } return fields; @@ -2785,7 +3192,7 @@ namespace Rust { AST::Visibility vis = parse_visibility(); // parse type, which is required - AST::Type* field_type = parse_type(); + ::std::unique_ptr<AST::Type> field_type = parse_type(); if (field_type == NULL) { // error if null error_at(lexer.peek_token()->get_locus(), "could not parse type in tuple struct field"); @@ -2793,11 +3200,13 @@ namespace Rust { return AST::TupleField::create_error(); } - return AST::TupleField(field_type, ::std::move(vis), ::std::move(outer_attrs)); + return AST::TupleField(::std::move(field_type), ::std::move(vis), ::std::move(outer_attrs)); } // Parses a Rust "enum" tagged union item definition. - AST::Enum* Parser::parse_enum(AST::Visibility vis, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::Enum> Parser::parse_enum( + AST::Visibility vis, ::std::vector<AST::Attribute> outer_attrs) { + location_t locus = lexer.peek_token()->get_locus(); skip_token(ENUM_TOK); // parse enum name @@ -2824,22 +3233,23 @@ namespace Rust { return NULL; } - return new AST::Enum(::std::move(enum_name), ::std::move(vis), ::std::move(generic_params), - ::std::move(where_clause), ::std::move(enum_items), ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::Enum>( + new AST::Enum(::std::move(enum_name), ::std::move(vis), ::std::move(generic_params), + ::std::move(where_clause), ::std::move(enum_items), ::std::move(outer_attrs), locus)); } // Parses the enum variants inside an enum definiton. ::std::vector< ::std::unique_ptr<AST::EnumItem> > Parser::parse_enum_items() { ::std::vector< ::std::unique_ptr<AST::EnumItem> > items; - AST::EnumItem* initial_item = parse_enum_item(); + ::std::unique_ptr<AST::EnumItem> initial_item = parse_enum_item(); // Return empty item list if no field there if (initial_item == NULL) { return items; } - items.push_back(::std::unique_ptr<AST::EnumItem>(initial_item)); + items.push_back(::std::move(initial_item)); // maybe think of a better control structure here - do-while with an initial error state? // basically, loop through item list until can't find any more params @@ -2851,10 +3261,10 @@ namespace Rust { // skip comma if applies lexer.skip_token(); - AST::EnumItem* item = parse_enum_item(); + ::std::unique_ptr<AST::EnumItem> item = parse_enum_item(); if (item != NULL) { - items.push_back(::std::unique_ptr<AST::EnumItem>(item)); + items.push_back(::std::move(item)); } else { // this would occur with a trailing comma, which is allowed break; @@ -2868,7 +3278,7 @@ namespace Rust { } // Parses a single enum variant item in an enum definition. Does not parse commas. - AST::EnumItem* Parser::parse_enum_item() { + ::std::unique_ptr<AST::EnumItem> Parser::parse_enum_item() { // parse outer attributes if they exist ::std::vector<AST::Attribute> outer_attrs = parse_outer_attributes(); @@ -2895,8 +3305,9 @@ namespace Rust { return NULL; } - return new AST::EnumItemTuple( - ::std::move(item_name), ::std::move(tuple_fields), ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::EnumItemTuple>( + new AST::EnumItemTuple(::std::move(item_name), ::std::move(tuple_fields), + ::std::move(outer_attrs), item_name_tok->get_locus())); } case LEFT_CURLY: { // struct enum item @@ -2909,34 +3320,39 @@ namespace Rust { return NULL; } - return new AST::EnumItemStruct( - ::std::move(item_name), ::std::move(struct_fields), ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::EnumItemStruct>( + new AST::EnumItemStruct(::std::move(item_name), ::std::move(struct_fields), + ::std::move(outer_attrs), item_name_tok->get_locus())); } case EQUAL: { // discriminant enum item lexer.skip_token(); - AST::Expr* discriminant_expr = parse_expr(); + ::std::unique_ptr<AST::Expr> discriminant_expr = parse_expr(); - return new AST::EnumItemDiscriminant( - ::std::move(item_name), discriminant_expr, ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::EnumItemDiscriminant>(new AST::EnumItemDiscriminant( + ::std::move(item_name), ::std::move(discriminant_expr), ::std::move(outer_attrs), + item_name_tok->get_locus())); } default: // regular enum with just an identifier - return new AST::EnumItem(::std::move(item_name), ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::EnumItem>(new AST::EnumItem( + ::std::move(item_name), ::std::move(outer_attrs), item_name_tok->get_locus())); } } // Parses a C-style (and C-compat) untagged union declaration. - AST::Union* Parser::parse_union(AST::Visibility vis, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::Union> Parser::parse_union( + AST::Visibility vis, ::std::vector<AST::Attribute> outer_attrs) { // hack - "weak keyword" by finding identifier called "union" (lookahead in item switch) + location_t locus = lexer.peek_token()->get_locus(); // skip union "identifier" skip_token(IDENTIFIER); // parse actual union name const_TokenPtr union_name_tok = expect_token(IDENTIFIER); if (union_name_tok == NULL) { - skip_after_end_block(); + skip_after_next_block(); return NULL; } Identifier union_name = union_name_tok->get_str(); @@ -2961,13 +3377,15 @@ namespace Rust { return NULL; } - return new AST::Union(::std::move(union_name), ::std::move(vis), ::std::move(generic_params), - ::std::move(where_clause), ::std::move(union_fields), ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::Union>( + new AST::Union(::std::move(union_name), ::std::move(vis), ::std::move(generic_params), + ::std::move(where_clause), ::std::move(union_fields), ::std::move(outer_attrs), locus)); } // Parses a "constant item" (compile-time constant to maybe "inline" throughout the program). - AST::ConstantItem* Parser::parse_const_item( + ::std::unique_ptr<AST::ConstantItem> Parser::parse_const_item( AST::Visibility vis, ::std::vector<AST::Attribute> outer_attrs) { + location_t locus = lexer.peek_token()->get_locus(); skip_token(CONST); // get constant identifier - this is either a proper identifier or the _ wildcard @@ -2977,9 +3395,11 @@ namespace Rust { switch (ident_tok->get_id()) { case IDENTIFIER: ident = ident_tok->get_str(); + lexer.skip_token(); break; case UNDERSCORE: // do nothing - identifier is already "_" + lexer.skip_token(); break; default: error_at(ident_tok->get_locus(), @@ -2995,7 +3415,7 @@ namespace Rust { } // parse constant type (required) - AST::Type* type = parse_type(); + ::std::unique_ptr<AST::Type> type = parse_type(); if (!skip_token(EQUAL)) { skip_after_semicolon(); @@ -3003,20 +3423,21 @@ namespace Rust { } // parse constant expression (required) - AST::Expr* expr = parse_expr(); + ::std::unique_ptr<AST::Expr> expr = parse_expr(); if (!skip_token(SEMICOLON)) { // skip somewhere? return NULL; } - return new AST::ConstantItem( - ::std::move(ident), ::std::move(vis), type, expr, ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::ConstantItem>(new AST::ConstantItem(::std::move(ident), + ::std::move(vis), ::std::move(type), ::std::move(expr), ::std::move(outer_attrs), locus)); } // Parses a "static item" (static storage item, with 'static lifetime). - AST::StaticItem* Parser::parse_static_item( + ::std::unique_ptr<AST::StaticItem> Parser::parse_static_item( AST::Visibility vis, ::std::vector<AST::Attribute> outer_attrs) { + location_t locus = lexer.peek_token()->get_locus(); skip_token(STATIC_TOK); // determine whether static item is mutable @@ -3035,7 +3456,7 @@ namespace Rust { } // parse static item type (required) - AST::Type* type = parse_type(); + ::std::unique_ptr<AST::Type> type = parse_type(); if (!skip_token(EQUAL)) { skip_after_semicolon(); @@ -3043,19 +3464,21 @@ namespace Rust { } // parse static item expression (required) - AST::Expr* expr = parse_expr(); + ::std::unique_ptr<AST::Expr> expr = parse_expr(); if (!skip_token(SEMICOLON)) { // skip after somewhere return NULL; } - return new AST::StaticItem( - ::std::move(ident), is_mut, type, expr, ::std::move(vis), ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::StaticItem>(new AST::StaticItem(::std::move(ident), is_mut, + ::std::move(type), ::std::move(expr), ::std::move(vis), ::std::move(outer_attrs), locus)); } // Parses a trait definition item, including unsafe ones. - AST::Trait* Parser::parse_trait(AST::Visibility vis, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::Trait> Parser::parse_trait( + AST::Visibility vis, ::std::vector<AST::Attribute> outer_attrs) { + location_t locus = lexer.peek_token()->get_locus(); bool is_unsafe = false; if (lexer.peek_token()->get_id() == UNSAFE) { is_unsafe = true; @@ -3096,14 +3519,14 @@ namespace Rust { const_TokenPtr t = lexer.peek_token(); while (t->get_id() != RIGHT_CURLY) { - AST::TraitItem* trait_item = parse_trait_item(); + ::std::unique_ptr<AST::TraitItem> trait_item = parse_trait_item(); if (trait_item == NULL) { // TODO: this is probably an error as next character should equal RIGHT_CURLY break; } - trait_items.push_back(::std::unique_ptr<AST::TraitItem>(trait_item)); + trait_items.push_back(::std::move(trait_item)); t = lexer.peek_token(); } @@ -3113,18 +3536,19 @@ namespace Rust { return NULL; } - return new AST::Trait(::std::move(ident), is_unsafe, ::std::move(generic_params), - ::std::move(type_param_bounds), ::std::move(where_clause), ::std::move(trait_items), - ::std::move(vis), ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::Trait>(new AST::Trait(::std::move(ident), is_unsafe, + ::std::move(generic_params), ::std::move(type_param_bounds), ::std::move(where_clause), + ::std::move(trait_items), ::std::move(vis), ::std::move(outer_attrs), locus)); } // Parses a trait item used inside traits (not trait, the Item). - AST::TraitItem* Parser::parse_trait_item() { + ::std::unique_ptr<AST::TraitItem> Parser::parse_trait_item() { // parse outer attributes (if they exist) ::std::vector<AST::Attribute> outer_attrs = parse_outer_attributes(); // lookahead to determine what type of trait item to parse - switch (lexer.peek_token()->get_id()) { + const_TokenPtr tok = lexer.peek_token(); + switch (tok->get_id()) { case TYPE: return parse_trait_type(::std::move(outer_attrs)); case CONST: @@ -3183,14 +3607,14 @@ namespace Rust { } // parse return type (optional) - AST::Type* return_type = parse_function_return_type(); + ::std::unique_ptr<AST::Type> return_type = parse_function_return_type(); // parse where clause (optional) AST::WhereClause where_clause = parse_where_clause(); // parse semicolon or function definition (in block) const_TokenPtr t = lexer.peek_token(); - AST::BlockExpr* definition = NULL; + ::std::unique_ptr<AST::BlockExpr> definition = NULL; switch (t->get_id()) { case SEMICOLON: lexer.skip_token(); @@ -3213,23 +3637,27 @@ namespace Rust { if (is_method) { AST::TraitMethodDecl method_decl(::std::move(ident), ::std::move(qualifiers), ::std::move(generic_params), ::std::move(self_param), - ::std::move(function_params), return_type, ::std::move(where_clause)); + ::std::move(function_params), ::std::move(return_type), + ::std::move(where_clause)); // TODO: does this (method_decl) need move? - return new AST::TraitItemMethod( - ::std::move(method_decl), definition, ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::TraitItemMethod>( + new AST::TraitItemMethod(::std::move(method_decl), ::std::move(definition), + ::std::move(outer_attrs), tok->get_locus())); } else { AST::TraitFunctionDecl function_decl(::std::move(ident), ::std::move(qualifiers), - ::std::move(generic_params), ::std::move(function_params), return_type, - ::std::move(where_clause)); + ::std::move(generic_params), ::std::move(function_params), + ::std::move(return_type), ::std::move(where_clause)); - return new AST::TraitItemFunc( - ::std::move(function_decl), definition, ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::TraitItemFunc>( + new AST::TraitItemFunc(::std::move(function_decl), ::std::move(definition), + ::std::move(outer_attrs), tok->get_locus())); } } default: { // TODO: try and parse macro invocation semi - if fails, maybe error. - AST::MacroInvocationSemi* macro_invoc = parse_macro_invocation_semi(outer_attrs); + ::std::unique_ptr<AST::MacroInvocationSemi> macro_invoc + = parse_macro_invocation_semi(outer_attrs); if (macro_invoc == NULL) { // TODO: error? @@ -3237,12 +3665,16 @@ namespace Rust { } else { return macro_invoc; } + // FIXME: macro invocations can only start with certain tokens. be more picky with + // these? } } } // Parse a typedef trait item. - AST::TraitItemType* Parser::parse_trait_type(::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::TraitItemType> Parser::parse_trait_type( + ::std::vector<AST::Attribute> outer_attrs) { + location_t locus = lexer.peek_token()->get_locus(); skip_token(TYPE); const_TokenPtr ident_tok = expect_token(IDENTIFIER); @@ -3265,12 +3697,14 @@ namespace Rust { return NULL; } - return new AST::TraitItemType( - ::std::move(ident), ::std::move(bounds), ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::TraitItemType>(new AST::TraitItemType( + ::std::move(ident), ::std::move(bounds), ::std::move(outer_attrs), locus)); } // Parses a constant trait item. - AST::TraitItemConst* Parser::parse_trait_const(::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::TraitItemConst> Parser::parse_trait_const( + ::std::vector<AST::Attribute> outer_attrs) { + location_t locus = lexer.peek_token()->get_locus(); skip_token(CONST); // parse constant item name @@ -3283,10 +3717,10 @@ namespace Rust { } // parse constant trait item type - AST::Type* type = parse_type(); + ::std::unique_ptr<AST::Type> type = parse_type(); // parse constant trait body expression, if it exists - AST::Expr* const_body = NULL; + ::std::unique_ptr<AST::Expr> const_body = NULL; if (lexer.peek_token()->get_id() == EQUAL) { lexer.skip_token(); @@ -3299,14 +3733,16 @@ namespace Rust { return NULL; } - return new AST::TraitItemConst( - ::std::move(ident), type, const_body, ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::TraitItemConst>(new AST::TraitItemConst(::std::move(ident), + ::std::move(type), ::std::move(const_body), ::std::move(outer_attrs), locus)); } // Parses a struct "impl" item (both inherent impl and trait impl can be parsed here), - AST::Impl* Parser::parse_impl(AST::Visibility vis, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::Impl> Parser::parse_impl( + AST::Visibility vis, ::std::vector<AST::Attribute> outer_attrs) { /* Note that only trait impls are allowed to be unsafe. So if unsafe, it must be a trait * impl. However, this isn't enough for full disambiguation, so don't branch here. */ + location_t locus = lexer.peek_token()->get_locus(); bool is_unsafe = false; if (lexer.peek_token()->get_id() == UNSAFE) { lexer.skip_token(); @@ -3314,7 +3750,7 @@ namespace Rust { } if (!skip_token(IMPL)) { - skip_after_end_block(); + skip_after_next_block(); return NULL; } @@ -3336,17 +3772,17 @@ namespace Rust { // cannot parse type path (or not for token next, at least), so must be inherent impl // hacky conversion of TypePath stack object to Type pointer - AST::Type* type = NULL; + ::std::unique_ptr<AST::Type> type = NULL; if (!type_path.is_error()) { // TODO: would move work here? - type = new AST::TypePath(type_path); + type = ::std::unique_ptr<AST::TypePath>(new AST::TypePath(type_path)); } else { type = parse_type(); } // Type is required, so error if null if (type == NULL) { error_at(lexer.peek_token()->get_locus(), "could not parse type in inherent impl"); - skip_after_end_block(); + skip_after_next_block(); return NULL; } @@ -3367,14 +3803,16 @@ namespace Rust { const_TokenPtr t = lexer.peek_token(); while (t->get_id() != RIGHT_CURLY) { - AST::InherentImplItem* impl_item = parse_inherent_impl_item(); + ::std::unique_ptr<AST::InherentImplItem> impl_item = parse_inherent_impl_item(); if (impl_item == NULL) { // TODO: this is probably an error as next character should equal RIGHT_CURLY + fprintf(stderr, + "impl item is null and next char wasn't RIGHT_CURLY - probably an error"); break; } - impl_items.push_back(::std::unique_ptr<AST::InherentImplItem>(impl_item)); + impl_items.push_back(::std::move(impl_item)); t = lexer.peek_token(); } @@ -3384,22 +3822,25 @@ namespace Rust { return NULL; } - return new AST::InherentImpl(::std::move(impl_items), ::std::move(generic_params), type, - ::std::move(where_clause), ::std::move(vis), ::std::move(inner_attrs), - ::std::move(outer_attrs)); + // DEBUG + fprintf(stderr, "successfully parsed inherent impl\n"); + + return ::std::unique_ptr<AST::InherentImpl>(new AST::InherentImpl(::std::move(impl_items), + ::std::move(generic_params), ::std::move(type), ::std::move(where_clause), + ::std::move(vis), ::std::move(inner_attrs), ::std::move(outer_attrs), locus)); } else { // type path must both be valid and next token is for, so trait impl if (!skip_token(FOR)) { - skip_after_end_block(); + skip_after_next_block(); return NULL; } // parse type - AST::Type* type = parse_type(); + ::std::unique_ptr<AST::Type> type = parse_type(); // ensure type is included as it is required if (type == NULL) { error_at(lexer.peek_token()->get_locus(), "could not parse type in trait impl"); - skip_after_end_block(); + skip_after_next_block(); return NULL; } @@ -3420,31 +3861,44 @@ namespace Rust { const_TokenPtr t = lexer.peek_token(); while (t->get_id() != RIGHT_CURLY) { - AST::TraitImplItem* impl_item = parse_trait_impl_item(); + ::std::unique_ptr<AST::TraitImplItem> impl_item = parse_trait_impl_item(); if (impl_item == NULL) { + // DEBUG + fprintf( + stderr, "break out of parsing trait impl items (due to parse giving null)\n"); + // TODO: this is probably an error as next character should equal RIGHT_CURLY break; } - impl_items.push_back(::std::unique_ptr<AST::TraitImplItem>(impl_item)); + impl_items.push_back(::std::move(impl_item)); t = lexer.peek_token(); + + // DEBUG + fprintf(stderr, "successfully parsed a trait impl item\n"); } + // DEBUG + fprintf(stderr, "successfully finished trait impl items\n"); if (!skip_token(RIGHT_CURLY)) { // skip somewhere return NULL; } - return new AST::TraitImpl(::std::move(type_path), is_unsafe, has_exclam, - ::std::move(impl_items), ::std::move(generic_params), type, ::std::move(where_clause), - ::std::move(vis), ::std::move(inner_attrs), ::std::move(outer_attrs)); + // DEBUG + fprintf(stderr, "successfully parsed trait impl\n"); + + return ::std::unique_ptr<AST::TraitImpl>(new AST::TraitImpl(::std::move(type_path), + is_unsafe, has_exclam, ::std::move(impl_items), ::std::move(generic_params), + ::std::move(type), ::std::move(where_clause), ::std::move(vis), + ::std::move(inner_attrs), ::std::move(outer_attrs), locus)); } } // Parses a single inherent impl item (item inside an inherent impl block). - AST::InherentImplItem* Parser::parse_inherent_impl_item() { + ::std::unique_ptr<AST::InherentImplItem> Parser::parse_inherent_impl_item() { // parse outer attributes (if they exist) ::std::vector<AST::Attribute> outer_attrs = parse_outer_attributes(); @@ -3457,22 +3911,9 @@ namespace Rust { case SUPER: case SELF: case CRATE: - case DOLLAR_SIGN: { + case DOLLAR_SIGN: // these seem to be SimplePath tokens, so this is a macro invocation semi - AST::MacroInvocationSemi* macro_invoc = parse_macro_invocation_semi(outer_attrs); - if (macro_invoc == NULL) { - error_at(t->get_locus(), "could not parse macro inherent impl item"); - skip_after_semicolon(); - return NULL; - } - // TODO: keep ahead of possible hierachy changes - // have to do this then delete macro pointer because of taking param by value - AST::InherentImplItemMacro* return_val - = new AST::InherentImplItemMacro(*macro_invoc, outer_attrs); - delete macro_invoc; - // FIXME: ensure this doesn't cause double free - return return_val; - } + return parse_macro_invocation_semi(::std::move(outer_attrs)); case PUB: { // visibility, so not a macro invocation semi - must be constant, function, or method AST::Visibility vis = parse_visibility(); @@ -3483,28 +3924,21 @@ namespace Rust { case UNSAFE: case FN_TOK: // function or method - return parse_inherent_impl_function_or_method(vis, outer_attrs); + return parse_inherent_impl_function_or_method( + ::std::move(vis), ::std::move(outer_attrs)); case CONST: // lookahead to resolve production - could be function/method or const item t = lexer.peek_token(1); switch (t->get_id()) { case IDENTIFIER: - case UNDERSCORE: { - AST::ConstantItem* const_item = parse_const_item(vis, outer_attrs); - - // have to do this then delete const item ptr because of taking param - // by value - AST::InherentImplItemConstant* return_val - = new AST::InherentImplItemConstant(*const_item, outer_attrs); - delete const_item; - // FIXME: ensure this doesn't cause double free - return return_val; - } + case UNDERSCORE: + return parse_const_item(::std::move(vis), ::std::move(outer_attrs)); case UNSAFE: case EXTERN_TOK: case FN_TOK: - return parse_inherent_impl_function_or_method(vis, outer_attrs); + return parse_inherent_impl_function_or_method( + ::std::move(vis), ::std::move(outer_attrs)); default: error_at(t->get_locus(), "unexpected token '%s' in some sort of const item in inherent impl", @@ -3524,30 +3958,21 @@ namespace Rust { case FN_TOK: // function or method return parse_inherent_impl_function_or_method( - AST::Visibility::create_error(), outer_attrs); + AST::Visibility::create_error(), ::std::move(outer_attrs)); case CONST: // lookahead to resolve production - could be function/method or const item t = lexer.peek_token(1); switch (t->get_id()) { case IDENTIFIER: - case UNDERSCORE: { - AST::ConstantItem* const_item - = parse_const_item(AST::Visibility::create_error(), outer_attrs); - - // have to do this then delete const item ptr because of taking param - // by value - AST::InherentImplItemConstant* return_val - = new AST::InherentImplItemConstant(*const_item, outer_attrs); - delete const_item; - // FIXME: ensure this doesn't cause double free - return return_val; - } + case UNDERSCORE: + return parse_const_item( + AST::Visibility::create_error(), ::std::move(outer_attrs)); case UNSAFE: case EXTERN_TOK: case FN_TOK: return parse_inherent_impl_function_or_method( - AST::Visibility::create_error(), outer_attrs); + AST::Visibility::create_error(), ::std::move(outer_attrs)); default: error_at(t->get_locus(), "unexpected token '%s' in some sort of const item in inherent impl", @@ -3567,8 +3992,11 @@ namespace Rust { /* For internal use only by parse_inherent_impl_item() - splits giant method into smaller ones * and prevents duplication of logic. Strictly, this parses a function or method item inside an * inherent impl item block. */ - AST::InherentImplItem* Parser::parse_inherent_impl_function_or_method( + // TODO: make this a templated function with "return type" as type param - InherentImplItem is this + // specialisation of the template while TraitImplItem will be the other. + ::std::unique_ptr<AST::InherentImplItem> Parser::parse_inherent_impl_function_or_method( AST::Visibility vis, ::std::vector<AST::Attribute> outer_attrs) { + location_t locus = lexer.peek_token()->get_locus(); // parse function or method qualifiers AST::FunctionQualifiers qualifiers = parse_function_qualifiers(); @@ -3610,7 +4038,7 @@ namespace Rust { } // parse return type (optional) - AST::Type* return_type = parse_function_return_type(); + ::std::unique_ptr<AST::Type> return_type = parse_function_return_type(); // parse where clause (optional) AST::WhereClause where_clause = parse_where_clause(); @@ -3623,7 +4051,7 @@ namespace Rust { lexer.skip_token(); return NULL; } - AST::BlockExpr* body = parse_block_expr(); + ::std::unique_ptr<AST::BlockExpr> body = parse_block_expr(); if (body == NULL) { error_at(lexer.peek_token()->get_locus(), "could not parse definition in inherent impl %s definition", @@ -3634,25 +4062,20 @@ namespace Rust { // do actual if instead of ternary for return value optimisation if (is_method) { - AST::Method method_decl(::std::move(ident), ::std::move(qualifiers), - ::std::move(generic_params), ::std::move(self_param), ::std::move(function_params), - return_type, ::std::move(where_clause), body); - - return new AST::InherentImplItemMethod( - ::std::move(method_decl), ::std::move(vis), outer_attrs); + return ::std::unique_ptr<AST::Method>(new AST::Method(::std::move(ident), + ::std::move(qualifiers), ::std::move(generic_params), ::std::move(self_param), + ::std::move(function_params), ::std::move(return_type), ::std::move(where_clause), + ::std::move(body), ::std::move(vis), ::std::move(outer_attrs), locus)); } else { - // TODO: this is bad - double up of outer attributes - AST::Function function_decl(::std::move(ident), ::std::move(qualifiers), - ::std::move(generic_params), ::std::move(function_params), return_type, - ::std::move(where_clause), body, ::std::move(vis), outer_attrs); - - // TODO: does this (function_decl) need move? - return new AST::InherentImplItemFunction(::std::move(function_decl), outer_attrs); + return ::std::unique_ptr<AST::Function>(new AST::Function(::std::move(ident), + ::std::move(qualifiers), ::std::move(generic_params), ::std::move(function_params), + ::std::move(return_type), ::std::move(where_clause), ::std::move(body), + ::std::move(vis), ::std::move(outer_attrs), locus)); } } // Parses a single trait impl item (item inside a trait impl block). - AST::TraitImplItem* Parser::parse_trait_impl_item() { + ::std::unique_ptr<AST::TraitImplItem> Parser::parse_trait_impl_item() { // parse outer attributes (if they exist) ::std::vector<AST::Attribute> outer_attrs = parse_outer_attributes(); @@ -3665,75 +4088,38 @@ namespace Rust { case SUPER: case SELF: case CRATE: - case DOLLAR_SIGN: { + case DOLLAR_SIGN: // these seem to be SimplePath tokens, so this is a macro invocation semi - AST::MacroInvocationSemi* macro_invoc = parse_macro_invocation_semi(outer_attrs); - if (macro_invoc == NULL) { - error_at(t->get_locus(), "could not parse macro inherent impl item"); - skip_after_semicolon(); - return NULL; - } - // TODO: keep ahead of possible hierachy changes - // have to do this then delete macro pointer because of taking param by value - AST::TraitImplItemMacro* return_val - = new AST::TraitImplItemMacro(*macro_invoc, outer_attrs); - delete macro_invoc; - // FIXME: ensure this doesn't cause double free - return return_val; - } - case TYPE: { - AST::TypeAlias* type_alias - = parse_type_alias(AST::Visibility::create_error(), outer_attrs); - - // have to do this then delete const item ptr because of taking param by value - AST::TraitImplItemTypeAlias* return_val - = new AST::TraitImplItemTypeAlias(*type_alias, outer_attrs); - delete type_alias; - // FIXME: ensure this doesn't cause double free - return return_val; - } + return parse_macro_invocation_semi(::std::move(outer_attrs)); + case TYPE: + return parse_type_alias(AST::Visibility::create_error(), ::std::move(outer_attrs)); case PUB: { // visibility, so not a macro invocation semi - must be constant, function, or method AST::Visibility vis = parse_visibility(); // TODO: is a recursive call to parse_trait_impl_item better? switch (lexer.peek_token()->get_id()) { - case TYPE: { - AST::TypeAlias* type_alias = parse_type_alias(vis, outer_attrs); - - // have to do this then delete const item ptr because of taking param by value - AST::TraitImplItemTypeAlias* return_val - = new AST::TraitImplItemTypeAlias(*type_alias, outer_attrs); - delete type_alias; - // FIXME: ensure this doesn't cause double free - return return_val; - } + case TYPE: + return parse_type_alias(::std::move(vis), ::std::move(outer_attrs)); case EXTERN_TOK: case UNSAFE: case FN_TOK: // function or method - return parse_trait_impl_function_or_method(vis, outer_attrs); + return parse_trait_impl_function_or_method( + ::std::move(vis), ::std::move(outer_attrs)); case CONST: // lookahead to resolve production - could be function/method or const item t = lexer.peek_token(1); switch (t->get_id()) { case IDENTIFIER: - case UNDERSCORE: { - AST::ConstantItem* const_item = parse_const_item(vis, outer_attrs); - - // have to do this then delete const item ptr because of taking param - // by value - AST::TraitImplItemConstant* return_val - = new AST::TraitImplItemConstant(*const_item, outer_attrs); - delete const_item; - // FIXME: ensure this doesn't cause double free - return return_val; - } + case UNDERSCORE: + return parse_const_item(::std::move(vis), ::std::move(outer_attrs)); case UNSAFE: case EXTERN_TOK: case FN_TOK: - return parse_trait_impl_function_or_method(vis, outer_attrs); + return parse_trait_impl_function_or_method( + ::std::move(vis), ::std::move(outer_attrs)); default: error_at(t->get_locus(), "unexpected token '%s' in some sort of const item in trait impl", @@ -3753,30 +4139,21 @@ namespace Rust { case FN_TOK: // function or method return parse_trait_impl_function_or_method( - AST::Visibility::create_error(), outer_attrs); + AST::Visibility::create_error(), ::std::move(outer_attrs)); case CONST: // lookahead to resolve production - could be function/method or const item t = lexer.peek_token(1); switch (t->get_id()) { case IDENTIFIER: - case UNDERSCORE: { - AST::ConstantItem* const_item - = parse_const_item(AST::Visibility::create_error(), outer_attrs); - - // have to do this then delete const item ptr because of taking param - // by value - AST::TraitImplItemConstant* return_val - = new AST::TraitImplItemConstant(*const_item, outer_attrs); - delete const_item; - // FIXME: ensure this doesn't cause double free - return return_val; - } + case UNDERSCORE: + return parse_const_item( + AST::Visibility::create_error(), ::std::move(outer_attrs)); case UNSAFE: case EXTERN_TOK: case FN_TOK: return parse_trait_impl_function_or_method( - AST::Visibility::create_error(), outer_attrs); + AST::Visibility::create_error(), ::std::move(outer_attrs)); default: error_at(t->get_locus(), "unexpected token '%s' in some sort of const item in trait impl", @@ -3796,9 +4173,10 @@ namespace Rust { /* For internal use only by parse_trait_impl_item() - splits giant method into smaller ones * and prevents duplication of logic. Strictly, this parses a function or method item inside a * trait impl item block. */ - AST::TraitImplItem* Parser::parse_trait_impl_function_or_method( + ::std::unique_ptr<AST::TraitImplItem> Parser::parse_trait_impl_function_or_method( AST::Visibility vis, ::std::vector<AST::Attribute> outer_attrs) { // this shares virtually all logic with parse_inherent_impl_function_or_method - template? + location_t locus = lexer.peek_token()->get_locus(); // parse function or method qualifiers AST::FunctionQualifiers qualifiers = parse_function_qualifiers(); @@ -3807,12 +4185,21 @@ namespace Rust { // parse function or method name const_TokenPtr ident_tok = expect_token(IDENTIFIER); + if (ident_tok == NULL) { + return NULL; + } Identifier ident = ident_tok->get_str(); + // DEBUG: + fprintf(stderr, "about to start parsing generic params in trait impl function or method\n"); + // parse generic params ::std::vector< ::std::unique_ptr<AST::GenericParam> > generic_params = parse_generic_params_in_angles(); + // DEBUG: + fprintf(stderr, "finished parsing generic params in trait impl function or method\n"); + if (!skip_token(LEFT_PAREN)) { // skip after somewhere? return NULL; @@ -3829,22 +4216,51 @@ namespace Rust { if (lexer.peek_token()->get_id() == COMMA) { lexer.skip_token(); } + + // DEBUG + fprintf(stderr, "successfully parsed self param in method trait impl item\n"); } - // parse trait function params - ::std::vector<AST::FunctionParam> function_params = parse_function_params(); + // DEBUG + fprintf(stderr, "started to parse function params in function or method trait impl item\n"); + + // parse trait function params (only if next token isn't right paren) + ::std::vector<AST::FunctionParam> function_params; + if (lexer.peek_token()->get_id() != RIGHT_PAREN) { + function_params = parse_function_params(); + + if (function_params.empty()) { + error_at(lexer.peek_token()->get_locus(), + "failed to parse function params in trait impl %s definition", + is_method ? "method" : "function"); + skip_after_next_block(); + return NULL; + } + } + + // FIXME: segfault occurs during parsing of function params + + // DEBUG + fprintf( + stderr, "successfully parsed function params in function or method trait impl item\n"); if (!skip_token(RIGHT_PAREN)) { - skip_after_end_block(); + skip_after_next_block(); return NULL; } // parse return type (optional) - AST::Type* return_type = parse_function_return_type(); + ::std::unique_ptr<AST::Type> return_type = parse_function_return_type(); + + // DEBUG + fprintf(stderr, "successfully parsed return type in function or method trait impl item\n"); // parse where clause (optional) AST::WhereClause where_clause = parse_where_clause(); + // DEBUG + fprintf(stderr, "successfully parsed where clause in function or method trait impl item\n"); + // parse function definition (in block) - semicolon not allowed if (lexer.peek_token()->get_id() == SEMICOLON) { error_at(lexer.peek_token()->get_locus(), @@ -3853,7 +4269,7 @@ namespace Rust { lexer.skip_token(); return NULL; } - AST::BlockExpr* body = parse_block_expr(); + ::std::unique_ptr<AST::BlockExpr> body = parse_block_expr(); if (body == NULL) { error_at(lexer.peek_token()->get_locus(), "could not parse definition in trait impl %s definition", @@ -3864,25 +4280,22 @@ namespace Rust { // do actual if instead of ternary for return value optimisation if (is_method) { - AST::Method method_decl(::std::move(ident), ::std::move(qualifiers), - ::std::move(generic_params), ::std::move(self_param), ::std::move(function_params), - return_type, ::std::move(where_clause), body); - - return new AST::TraitImplItemMethod( - ::std::move(method_decl), ::std::move(vis), ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::Method>(new AST::Method(::std::move(ident), + ::std::move(qualifiers), ::std::move(generic_params), ::std::move(self_param), + ::std::move(function_params), ::std::move(return_type), ::std::move(where_clause), + ::std::move(body), ::std::move(vis), ::std::move(outer_attrs), locus)); } else { - // TODO: this is bad - double up of outer attributes - AST::Function function_decl(::std::move(ident), ::std::move(qualifiers), - ::std::move(generic_params), ::std::move(function_params), return_type, - ::std::move(where_clause), body, ::std::move(vis), outer_attrs); - - return new AST::TraitImplItemFunction(::std::move(function_decl), outer_attrs); + return ::std::unique_ptr<AST::Function>(new AST::Function(::std::move(ident), + ::std::move(qualifiers), ::std::move(generic_params), ::std::move(function_params), + ::std::move(return_type), ::std::move(where_clause), ::std::move(body), + ::std::move(vis), ::std::move(outer_attrs), locus)); } } // Parses an extern block of declarations. - AST::ExternBlock* Parser::parse_extern_block( + ::std::unique_ptr<AST::ExternBlock> Parser::parse_extern_block( AST::Visibility vis, ::std::vector<AST::Attribute> outer_attrs) { + location_t locus = lexer.peek_token()->get_locus(); skip_token(EXTERN_TOK); // detect optional abi name @@ -3905,7 +4318,7 @@ namespace Rust { const_TokenPtr t = lexer.peek_token(); while (t->get_id() != RIGHT_CURLY) { - AST::ExternalItem* extern_item = parse_external_item(); + ::std::unique_ptr<AST::ExternalItem> extern_item = parse_external_item(); if (extern_item == NULL) { error_at(t->get_locus(), @@ -3913,7 +4326,7 @@ namespace Rust { return NULL; } - extern_items.push_back(::std::unique_ptr<AST::ExternalItem>(extern_item)); + extern_items.push_back(::std::move(extern_item)); t = lexer.peek_token(); } @@ -3923,15 +4336,18 @@ namespace Rust { return NULL; } - return new AST::ExternBlock(::std::move(abi), ::std::move(extern_items), ::std::move(vis), - ::std::move(inner_attrs), ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::ExternBlock>( + new AST::ExternBlock(::std::move(abi), ::std::move(extern_items), ::std::move(vis), + ::std::move(inner_attrs), ::std::move(outer_attrs), locus)); } // Parses a single extern block item (static or function declaration). - AST::ExternalItem* Parser::parse_external_item() { + ::std::unique_ptr<AST::ExternalItem> Parser::parse_external_item() { // parse optional outer attributes ::std::vector<AST::Attribute> outer_attrs = parse_outer_attributes(); + location_t locus = lexer.peek_token()->get_locus(); + // parse optional visibility AST::Visibility vis = parse_visibility(); @@ -3962,7 +4378,7 @@ namespace Rust { } // parse type (required) - AST::Type* type = parse_type(); + ::std::unique_ptr<AST::Type> type = parse_type(); if (type == NULL) { error_at(lexer.peek_token()->get_locus(), "failed to parse type in external static item"); @@ -3975,8 +4391,9 @@ namespace Rust { return NULL; } - return new AST::ExternalStaticItem( - ::std::move(ident), type, has_mut, ::std::move(vis), ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::ExternalStaticItem>( + new AST::ExternalStaticItem(::std::move(ident), ::std::move(type), has_mut, + ::std::move(vis), ::std::move(outer_attrs), locus)); } case FN_TOK: { // parse extern function declaration item @@ -4051,7 +4468,7 @@ namespace Rust { } // parse (optional) return type - AST::Type* return_type = parse_function_return_type(); + ::std::unique_ptr<AST::Type> return_type = parse_function_return_type(); // parse (optional) where clause AST::WhereClause where_clause = parse_where_clause(); @@ -4061,9 +4478,10 @@ namespace Rust { return NULL; } - return new AST::ExternalFunctionItem(::std::move(ident), ::std::move(generic_params), - return_type, ::std::move(where_clause), ::std::move(function_params), is_variadic, - ::std::move(vis), ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::ExternalFunctionItem>( + new AST::ExternalFunctionItem(::std::move(ident), ::std::move(generic_params), + ::std::move(return_type), ::std::move(where_clause), ::std::move(function_params), + is_variadic, ::std::move(vis), ::std::move(outer_attrs), locus)); } default: // error @@ -4100,7 +4518,7 @@ namespace Rust { } // parse (required) type - AST::Type* param_type = parse_type(); + ::std::unique_ptr<AST::Type> param_type = parse_type(); if (param_type == NULL) { error_at(lexer.peek_token()->get_locus(), "could not parse param type in extern block function declaration"); @@ -4108,15 +4526,16 @@ namespace Rust { return AST::NamedFunctionParam::create_error(); } - return AST::NamedFunctionParam(::std::move(name), param_type); + return AST::NamedFunctionParam(::std::move(name), ::std::move(param_type)); } // Parses a statement (will further disambiguate any statement). - AST::Stmt* Parser::parse_stmt() { + ::std::unique_ptr<AST::Stmt> Parser::parse_stmt() { // quick exit for empty statement - if (lexer.peek_token()->get_id() == SEMICOLON) { + const_TokenPtr t = lexer.peek_token(); + if (t->get_id() == SEMICOLON) { lexer.skip_token(); - return new AST::EmptyStmt(); + return ::std::unique_ptr<AST::EmptyStmt>(new AST::EmptyStmt(t->get_locus())); } // parse outer attributes @@ -4127,7 +4546,7 @@ namespace Rust { * attributes, and then pass them in to either a let statement or (fallback) expression * statement. */ // FIXME: think of a way to do this without such a large switch? - const_TokenPtr t = lexer.peek_token(); + t = lexer.peek_token(); switch (t->get_id()) { case LET: // let statement @@ -4184,11 +4603,13 @@ namespace Rust { } // Parses a let statement. - AST::LetStmt* Parser::parse_let_stmt(::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::LetStmt> Parser::parse_let_stmt( + ::std::vector<AST::Attribute> outer_attrs) { + location_t locus = lexer.peek_token()->get_locus(); skip_token(LET); // parse pattern (required) - AST::Pattern* pattern = parse_pattern(); + ::std::unique_ptr<AST::Pattern> pattern = parse_pattern(); if (pattern == NULL) { error_at(lexer.peek_token()->get_locus(), "failed to parse pattern in let statement"); skip_after_semicolon(); @@ -4196,7 +4617,7 @@ namespace Rust { } // parse type declaration (optional) - AST::Type* type = NULL; + ::std::unique_ptr<AST::Type> type = NULL; if (lexer.peek_token()->get_id() == COLON) { // must have a type declaration lexer.skip_token(); @@ -4210,7 +4631,7 @@ namespace Rust { } // parse expression to set variable to (optional) - AST::Expr* expr = NULL; + ::std::unique_ptr<AST::Expr> expr = NULL; if (lexer.peek_token()->get_id() == EQUAL) { // must have an expression lexer.skip_token(); @@ -4231,7 +4652,8 @@ namespace Rust { // missing? } - return new AST::LetStmt(pattern, expr, type, ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::LetStmt>(new AST::LetStmt(::std::move(pattern), + ::std::move(expr), ::std::move(type), ::std::move(outer_attrs), locus)); } // Parses a type path. @@ -4246,13 +4668,13 @@ namespace Rust { ::std::vector< ::std::unique_ptr<AST::TypePathSegment> > segments; // parse required initial segment - AST::TypePathSegment* initial_segment = parse_type_path_segment(); + ::std::unique_ptr<AST::TypePathSegment> initial_segment = parse_type_path_segment(); if (initial_segment == NULL) { // skip after somewhere? // don't necessarily throw error but yeah return AST::TypePath::create_error(); } - segments.push_back(::std::unique_ptr<AST::TypePathSegment>(initial_segment)); + segments.push_back(::std::move(initial_segment)); // parse optional segments (as long as scope resolution operator exists) const_TokenPtr t = lexer.peek_token(); @@ -4261,14 +4683,14 @@ namespace Rust { lexer.skip_token(); // parse the actual segment - it is an error if it doesn't exist now - AST::TypePathSegment* segment = parse_type_path_segment(); - if (initial_segment == NULL) { + ::std::unique_ptr<AST::TypePathSegment> segment = parse_type_path_segment(); + if (segment == NULL) { // skip after somewhere? error_at(t->get_locus(), "could not parse type path segment"); return AST::TypePath::create_error(); } - segments.push_back(::std::unique_ptr<AST::TypePathSegment>(segment)); + segments.push_back(::std::move(segment)); t = lexer.peek_token(); } @@ -4286,15 +4708,18 @@ namespace Rust { // try to parse lifetimes first ::std::vector<AST::Lifetime> lifetime_args; - // TODO: think of better control structure - while (true) { + const_TokenPtr t = lexer.peek_token(); + location_t locus = t->get_locus(); + const_TokenPtr t2 = lexer.peek_token(1); + while ( + t->get_id() == LIFETIME && (t2->get_id() == COMMA || !is_right_angle_tok(t2->get_id()))) { AST::Lifetime lifetime = parse_lifetime(); if (lifetime.is_error()) { // not necessarily an error break; } - lifetime_args.push_back(lifetime); + lifetime_args.push_back(::std::move(lifetime)); // if next token isn't comma, then it must be end of list if (lexer.peek_token()->get_id() != COMMA) { @@ -4302,20 +4727,29 @@ namespace Rust { } // skip comma lexer.skip_token(); + + t = lexer.peek_token(); + t2 = lexer.peek_token(1); } // try to parse types second ::std::vector< ::std::unique_ptr<AST::Type> > type_args; // TODO: think of better control structure - while (true) { - AST::Type* type = parse_type(); + t = lexer.peek_token(); + while (!is_right_angle_tok(t->get_id())) { + // ensure not binding being parsed as type accidently + if (t->get_id() == IDENTIFIER && lexer.peek_token(1)->get_id() == EQUAL) { + break; + } + + ::std::unique_ptr<AST::Type> type = parse_type(); if (type == NULL) { // not necessarily an error break; } - type_args.push_back(::std::unique_ptr<AST::Type>(type)); + type_args.push_back(::std::move(type)); // if next token isn't comma, then it must be end of list if (lexer.peek_token()->get_id() != COMMA) { @@ -4323,20 +4757,23 @@ namespace Rust { } // skip comma lexer.skip_token(); + + t = lexer.peek_token(); } // try to parse bindings third ::std::vector<AST::GenericArgsBinding> binding_args; // TODO: think of better control structure - while (true) { + t = lexer.peek_token(); + while (!is_right_angle_tok(t->get_id())) { AST::GenericArgsBinding binding = parse_generic_args_binding(); if (binding.is_error()) { // not necessarily an error break; } - binding_args.push_back(binding); + binding_args.push_back(::std::move(binding)); // if next token isn't comma, then it must be end of list if (lexer.peek_token()->get_id() != COMMA) { @@ -4344,6 +4781,8 @@ namespace Rust { } // skip comma lexer.skip_token(); + + t = lexer.peek_token(); } // skip any trailing commas @@ -4351,13 +4790,12 @@ namespace Rust { lexer.skip_token(); } - if (!skip_token(RIGHT_ANGLE)) { - // skip after somewhere? + if (!skip_generics_right_angle()) { return AST::GenericArgs::create_empty(); } return AST::GenericArgs( - ::std::move(lifetime_args), ::std::move(type_args), ::std::move(binding_args)); + ::std::move(lifetime_args), ::std::move(type_args), ::std::move(binding_args), locus); } // Parses a binding in a generic args path segment. @@ -4377,18 +4815,19 @@ namespace Rust { } // parse type (required) - AST::Type* type = parse_type(); + ::std::unique_ptr<AST::Type> type = parse_type(); if (type == NULL) { // skip somewhere? return AST::GenericArgsBinding::create_error(); } - return AST::GenericArgsBinding(::std::move(ident), type); + return AST::GenericArgsBinding(::std::move(ident), ::std::move(type), ident_tok->get_locus()); } /* Parses a single type path segment (not including opening scope resolution, but includes any * internal ones). Includes generic args or type path functions too. */ - AST::TypePathSegment* Parser::parse_type_path_segment() { + ::std::unique_ptr<AST::TypePathSegment> Parser::parse_type_path_segment() { + location_t locus = lexer.peek_token()->get_locus(); // parse ident segment part AST::PathIdentSegment ident_segment = parse_path_ident_segment(); if (ident_segment.is_error()) { @@ -4396,8 +4835,11 @@ namespace Rust { return NULL; } + // lookahead to determine if variants exist - only consume scope resolution then bool has_separating_scope_resolution = false; - if (lexer.peek_token()->get_id() == SCOPE_RESOLUTION) { + const_TokenPtr next = lexer.peek_token(1); + if (lexer.peek_token()->get_id() == SCOPE_RESOLUTION + && (next->get_id() == LEFT_ANGLE || next->get_id() == LEFT_PAREN)) { has_separating_scope_resolution = true; lexer.skip_token(); } @@ -4409,8 +4851,9 @@ namespace Rust { // parse generic args AST::GenericArgs generic_args = parse_path_generic_args(); - return new AST::TypePathSegmentGeneric( - ident_segment, has_separating_scope_resolution, ::std::move(generic_args)); + return ::std::unique_ptr<AST::TypePathSegmentGeneric>( + new AST::TypePathSegmentGeneric(::std::move(ident_segment), + has_separating_scope_resolution, ::std::move(generic_args), locus)); } case LEFT_PAREN: { // parse type path function @@ -4421,13 +4864,14 @@ namespace Rust { return NULL; } - return new AST::TypePathSegmentFunction(::std::move(ident_segment), - has_separating_scope_resolution, ::std::move(type_path_function)); + return ::std::unique_ptr<AST::TypePathSegmentFunction>( + new AST::TypePathSegmentFunction(::std::move(ident_segment), + has_separating_scope_resolution, ::std::move(type_path_function), locus)); } default: // neither of them - return new AST::TypePathSegment( - ::std::move(ident_segment), has_separating_scope_resolution); + return ::std::unique_ptr<AST::TypePathSegment>(new AST::TypePathSegment( + ::std::move(ident_segment), has_separating_scope_resolution, locus)); } gcc_unreachable(); } @@ -4444,13 +4888,13 @@ namespace Rust { // TODO: think of better control structure while (true) { - AST::Type* type = parse_type(); + ::std::unique_ptr<AST::Type> type = parse_type(); if (type == NULL) { // not necessarily an error break; } - inputs.push_back(::std::unique_ptr<AST::Type>(type)); + inputs.push_back(::std::move(type)); // skip commas, including trailing commas if (lexer.peek_token()->get_id() != COMMA) { @@ -4466,22 +4910,30 @@ namespace Rust { } // parse optional return type - AST::Type* return_type = parse_function_return_type(); + ::std::unique_ptr<AST::Type> return_type = parse_function_return_type(); - return AST::TypePathFunction(::std::move(inputs), return_type); + return AST::TypePathFunction(::std::move(inputs), ::std::move(return_type)); } // Parses a path inside an expression that allows generic arguments. AST::PathInExpression Parser::parse_path_in_expression() { + location_t locus = UNKNOWN_LOCATION; bool has_opening_scope_resolution = false; if (lexer.peek_token()->get_id() == SCOPE_RESOLUTION) { has_opening_scope_resolution = true; + + locus = lexer.peek_token()->get_locus(); + lexer.skip_token(); } // create segment vector ::std::vector<AST::PathExprSegment> segments; + if (locus == UNKNOWN_LOCATION) { + locus = lexer.peek_token()->get_locus(); + } + // parse required initial segment AST::PathExprSegment initial_segment = parse_path_expr_segment(); if (initial_segment.is_error()) { @@ -4489,7 +4941,7 @@ namespace Rust { // don't necessarily throw error but yeah return AST::PathInExpression::create_error(); } - segments.push_back(initial_segment); + segments.push_back(::std::move(initial_segment)); // parse optional segments (as long as scope resolution operator exists) const_TokenPtr t = lexer.peek_token(); @@ -4505,16 +4957,18 @@ namespace Rust { return AST::PathInExpression::create_error(); } - segments.push_back(segment); + segments.push_back(::std::move(segment)); t = lexer.peek_token(); } - return AST::PathInExpression(::std::move(segments), has_opening_scope_resolution); + return AST::PathInExpression(::std::move(segments), locus, has_opening_scope_resolution, + ::std::vector<AST::Attribute>()); } // Parses a single path in expression path segment (including generic arguments). AST::PathExprSegment Parser::parse_path_expr_segment() { + location_t locus = lexer.peek_token()->get_locus(); // parse ident segment AST::PathIdentSegment ident = parse_path_ident_segment(); if (ident.is_error()) { @@ -4532,15 +4986,15 @@ namespace Rust { AST::GenericArgs generic_args = parse_path_generic_args(); - return AST::PathExprSegment(::std::move(ident), ::std::move(generic_args)); + return AST::PathExprSegment(::std::move(ident), locus, ::std::move(generic_args)); } // return a generic parameter-less expr segment if not found - return AST::PathExprSegment(::std::move(ident)); + return AST::PathExprSegment(::std::move(ident), locus); } - // Parses a fully qualified path in expression (i.e. a pattern). - AST::QualifiedPathInExpression Parser::parse_qualified_path_in_expression() { + // Parses a fully qualified path in expression (i.e. a pattern). FIXME does not parse outer attrs. + AST::QualifiedPathInExpression Parser::parse_qualified_path_in_expression(bool pratt_parse) { /* Note: the Rust grammar is defined in such a way that it is impossible to determine whether * a prospective qualified path is a QualifiedPathInExpression or QualifiedPathInType in all * cases by the rules themselves (the only possible difference is a TypePathSegment with @@ -4550,11 +5004,12 @@ namespace Rust { * As such, this function will not attempt to minimise errors created by their confusion. */ // parse the qualified path type (required) - AST::QualifiedPathType qual_path_type = parse_qualified_path_type(); + AST::QualifiedPathType qual_path_type = parse_qualified_path_type(pratt_parse); if (qual_path_type.is_error()) { // TODO: should this create a parse error? return AST::QualifiedPathInExpression::create_error(); } + location_t locus = qual_path_type.get_locus(); // parse path segments ::std::vector<AST::PathExprSegment> segments; @@ -4595,19 +5050,28 @@ namespace Rust { t = lexer.peek_token(); } - return AST::QualifiedPathInExpression(::std::move(qual_path_type), ::std::move(segments)); + // FIXME: outer attr parsing + return AST::QualifiedPathInExpression( + ::std::move(qual_path_type), ::std::move(segments), locus, ::std::vector<AST::Attribute>()); } // Parses the type syntactical construction at the start of a qualified path. - AST::QualifiedPathType Parser::parse_qualified_path_type() { + AST::QualifiedPathType Parser::parse_qualified_path_type(bool pratt_parse) { + location_t locus = UNKNOWN_LOCATION; // TODO: should this actually be error? is there anywhere where this could be valid? - if (!skip_token(LEFT_ANGLE)) { - // skip after somewhere? - return AST::QualifiedPathType::create_error(); + if (!pratt_parse) { + locus = lexer.peek_token()->get_locus(); + if (!skip_token(LEFT_ANGLE)) { + // skip after somewhere? + return AST::QualifiedPathType::create_error(); + } + } else { + // move back by 1 if pratt parsing due to skipping '<' + locus = lexer.peek_token()->get_locus() - 1; } // parse type (required) - AST::Type* type = parse_type(); + ::std::unique_ptr<AST::Type> type = parse_type(); if (type == NULL) { error_at(lexer.peek_token()->get_locus(), "could not parse type in qualified path type"); // skip somewhere? @@ -4629,16 +5093,19 @@ namespace Rust { } } + // NOTE: should actually be a right-angle token, so skip_generics_right_angle shouldn't be + // required if (!skip_token(RIGHT_ANGLE)) { // skip after somewhere? return AST::QualifiedPathType::create_error(); } - return AST::QualifiedPathType(type, ::std::move(as_type_path)); + return AST::QualifiedPathType(::std::move(type), locus, ::std::move(as_type_path)); } // Parses a fully qualified path in type (i.e. a type). AST::QualifiedPathInType Parser::parse_qualified_path_in_type() { + location_t locus = lexer.peek_token()->get_locus(); // parse the qualified path type (required) AST::QualifiedPathType qual_path_type = parse_qualified_path_type(); if (qual_path_type.is_error()) { @@ -4655,14 +5122,14 @@ namespace Rust { return AST::QualifiedPathInType::create_error(); } - AST::TypePathSegment* initial_segment = parse_type_path_segment(); + ::std::unique_ptr<AST::TypePathSegment> initial_segment = parse_type_path_segment(); if (initial_segment == NULL) { // skip after somewhere? error_at(lexer.peek_token()->get_locus(), "required initial type path segment in qualified path in type could not be parsed"); return AST::QualifiedPathInType::create_error(); } - segments.push_back(::std::unique_ptr<AST::TypePathSegment>(initial_segment)); + segments.push_back(::std::move(initial_segment)); // parse optional segments (as long as scope resolution operator exists) const_TokenPtr t = lexer.peek_token(); @@ -4671,7 +5138,7 @@ namespace Rust { lexer.skip_token(); // parse the actual segment - it is an error if it doesn't exist now - AST::TypePathSegment* segment = parse_type_path_segment(); + ::std::unique_ptr<AST::TypePathSegment> segment = parse_type_path_segment(); if (segment == NULL) { // skip after somewhere? error_at( @@ -4679,19 +5146,21 @@ namespace Rust { return AST::QualifiedPathInType::create_error(); } - segments.push_back(::std::unique_ptr<AST::TypePathSegment>(segment)); + segments.push_back(::std::move(segment)); t = lexer.peek_token(); } - return AST::QualifiedPathInType(::std::move(qual_path_type), ::std::move(segments)); + return AST::QualifiedPathInType(::std::move(qual_path_type), ::std::move(segments), locus); } - // Parses a self param. + // Parses a self param. Also handles self param not existing. AST::SelfParam Parser::parse_self_param() { bool has_reference = false; AST::Lifetime lifetime = AST::Lifetime::error(); + location_t locus = lexer.peek_token()->get_locus(); + // test if self is a reference parameter if (lexer.peek_token()->get_id() == AMP) { has_reference = true; @@ -4719,13 +5188,15 @@ namespace Rust { } // skip self token - if (!skip_token(SELF)) { + const_TokenPtr self_tok = lexer.peek_token(); + if (self_tok->get_id() != SELF) { // skip after somewhere? return AST::SelfParam::create_error(); } + lexer.skip_token(); // parse optional type - AST::Type* type = NULL; + ::std::unique_ptr<AST::Type> type = NULL; if (lexer.peek_token()->get_id() == COLON) { lexer.skip_token(); @@ -4747,10 +5218,10 @@ namespace Rust { } if (has_reference) { - return AST::SelfParam(::std::move(lifetime), has_mut); + return AST::SelfParam(::std::move(lifetime), has_mut, locus); } else { // note that type may be NULL here and that's fine - return AST::SelfParam(type, has_mut); + return AST::SelfParam(::std::move(type), has_mut, locus); } } @@ -4759,6 +5230,7 @@ namespace Rust { * probably parse a "function or method" and then resolve it into whatever it is afterward. As * such, this is only here for algorithmically defining the grammar rule. */ AST::Method Parser::parse_method() { + location_t locus = lexer.peek_token()->get_locus(); // Note: as a result of the above, this will not attempt to disambiguate a function // parse qualifiers AST::FunctionQualifiers qualifiers = parse_function_qualifiers(); @@ -4767,7 +5239,7 @@ namespace Rust { const_TokenPtr ident_tok = expect_token(IDENTIFIER); if (ident_tok == NULL) { - skip_after_end_block(); + skip_after_next_block(); return AST::Method::create_error(); } Identifier method_name = ident_tok->get_str(); @@ -4779,7 +5251,7 @@ namespace Rust { if (!skip_token(LEFT_PAREN)) { error_at(lexer.peek_token()->get_locus(), "method missing opening parentheses before parameter list"); - skip_after_end_block(); + skip_after_next_block(); return AST::Method::create_error(); } @@ -4787,7 +5259,7 @@ namespace Rust { AST::SelfParam self_param = parse_self_param(); if (self_param.is_error()) { error_at(lexer.peek_token()->get_locus(), "could not parse self param in method"); - skip_after_end_block(); + skip_after_next_block(); return AST::Method::create_error(); } @@ -4802,31 +5274,34 @@ namespace Rust { if (!skip_token(RIGHT_PAREN)) { error_at(lexer.peek_token()->get_locus(), "method declaration missing closing parentheses after parameter list"); - skip_after_end_block(); + skip_after_next_block(); return AST::Method::create_error(); } // parse function return type - if exists - AST::Type* return_type = parse_function_return_type(); + ::std::unique_ptr<AST::Type> return_type = parse_function_return_type(); // parse where clause - if exists AST::WhereClause where_clause = parse_where_clause(); // parse block expression - AST::BlockExpr* block_expr = parse_block_expr(); + ::std::unique_ptr<AST::BlockExpr> block_expr = parse_block_expr(); if (block_expr == NULL) { error_at(lexer.peek_token()->get_locus(), "method declaration missing block expression"); skip_after_end_block(); return AST::Method::create_error(); } + // does not parse visibility, but this method isn't used, so doesn't matter return AST::Method(::std::move(method_name), ::std::move(qualifiers), ::std::move(generic_params), ::std::move(self_param), ::std::move(function_params), - return_type, ::std::move(where_clause), block_expr); + ::std::move(return_type), ::std::move(where_clause), ::std::move(block_expr), + AST::Visibility::create_error(), ::std::vector<AST::Attribute>(), locus); } // Parses an expression statement (disambiguates to expression with or without block statement). - AST::ExprStmt* Parser::parse_expr_stmt(::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::ExprStmt> Parser::parse_expr_stmt( + ::std::vector<AST::Attribute> outer_attrs) { /* potential thoughts - define new virtual method "has_block()" on expr. parse expr and then * determine whether semicolon is needed as a result of this method. * but then this would require dynamic_cast, which is not allowed. */ @@ -4880,9 +5355,9 @@ namespace Rust { } // Parses a expression statement containing an expression with block. Disambiguates internally. - AST::ExprStmtWithBlock* Parser::parse_expr_stmt_with_block( + ::std::unique_ptr<AST::ExprStmtWithBlock> Parser::parse_expr_stmt_with_block( ::std::vector<AST::Attribute> outer_attrs) { - AST::ExprWithBlock* expr_parsed = NULL; + ::std::unique_ptr<AST::ExprWithBlock> expr_parsed = NULL; const_TokenPtr t = lexer.peek_token(); switch (t->get_id()) { @@ -4942,7 +5417,7 @@ namespace Rust { "could not recognise expr beginning with '%s' as an expr with block in parsing " "expr statement.", t->get_token_description()); - skip_after_end_block(); + skip_after_next_block(); return NULL; } @@ -4954,11 +5429,12 @@ namespace Rust { } // return expr stmt created from expr - return new AST::ExprStmtWithBlock(expr_parsed); + return ::std::unique_ptr<AST::ExprStmtWithBlock>( + new AST::ExprStmtWithBlock(::std::move(expr_parsed), t->get_locus())); } // Parses an expression statement containing an expression without block. Disambiguates further. - AST::ExprStmtWithoutBlock* Parser::parse_expr_stmt_without_block( + ::std::unique_ptr<AST::ExprStmtWithoutBlock> Parser::parse_expr_stmt_without_block( ::std::vector<AST::Attribute> outer_attrs) { // TODO: maybe move more logic for expr without block in here for better error handling @@ -4966,7 +5442,8 @@ namespace Rust { /*AST::ExprWithoutBlock* expr = NULL; expr = parse_expr_without_block(::std::move(outer_attrs));*/ // HACK: parse expression instead of expression without block, due to Pratt parsing issues - AST::Expr* expr = NULL; + ::std::unique_ptr<AST::Expr> expr = NULL; + location_t locus = lexer.peek_token()->get_locus(); expr = parse_expr(::std::move(outer_attrs)); if (expr == NULL) { // expr is required, error @@ -4982,15 +5459,13 @@ namespace Rust { return NULL; } - return new AST::ExprStmtWithoutBlock(expr); + return ::std::unique_ptr<AST::ExprStmtWithoutBlock>( + new AST::ExprStmtWithoutBlock(::std::move(expr), locus)); } // Parses an expression without a block associated with it (further disambiguates). - AST::ExprWithoutBlock* Parser::parse_expr_without_block( + ::std::unique_ptr<AST::ExprWithoutBlock> Parser::parse_expr_without_block( ::std::vector<AST::Attribute> outer_attrs) { - // TODO - return NULL; - /* Notes on types of expr without block: * - literal expr tokens that are literals * - path expr path_in_expr or qual_path_in_expr @@ -5053,79 +5528,116 @@ namespace Rust { /* either grouped expr or tuple expr - depends on whether there is a comma inside the * parentheses - if so, tuple expr, otherwise, grouped expr. */ return parse_grouped_or_tuple_expr(::std::move(outer_attrs)); - default: - // TODO: - break; + default: { + // HACK: piggyback on pratt parsed expr and abuse polymorphism to essentially downcast + + // DEBUG + fprintf(stderr, "about to parse expr (in expr without block method)\n"); + + ::std::unique_ptr<AST::Expr> expr = parse_expr(::std::move(outer_attrs)); + + // DEBUG + fprintf(stderr, "successfully parsed expr (in expr without block method)\n"); + + if (expr == NULL) { + error_at(t->get_locus(), "failed to parse expression for expression without " + "block (pratt-parsed expression is null)"); + return NULL; + } + + ::std::unique_ptr<AST::ExprWithoutBlock> expr_without_block( + expr->as_expr_without_block()); + // THIS IS THE CAUSE OF THE SEGFAULT + + // DEBUG + fprintf(stderr, "expr to expr without block conversion didn't error\n"); + + if (expr_without_block != NULL) { + + // DEBUG + fprintf( + stderr, "expr to expr without block conversion was successful; returning\n"); + + return expr_without_block; + } else { + error_at(t->get_locus(), "converted expr without block is null"); + return NULL; + } + } } } // Parses a block expression, including the curly braces at start and end. - AST::BlockExpr* Parser::parse_block_expr(::std::vector<AST::Attribute> outer_attrs) { - if (!skip_token(LEFT_CURLY)) { - skip_after_end_block(); - return NULL; + ::std::unique_ptr<AST::BlockExpr> Parser::parse_block_expr( + ::std::vector<AST::Attribute> outer_attrs, bool pratt_parse) { + location_t locus = UNKNOWN_LOCATION; + if (!pratt_parse) { + locus = lexer.peek_token()->get_locus(); + if (!skip_token(LEFT_CURLY)) { + skip_after_end_block(); + return NULL; + } + } else { + locus = lexer.peek_token()->get_locus() - 1; } ::std::vector<AST::Attribute> inner_attrs = parse_inner_attributes(); - // parse statements + // parse statements and expression ::std::vector< ::std::unique_ptr<AST::Stmt> > stmts; + ::std::unique_ptr<AST::ExprWithoutBlock> expr = NULL; - // TODO: think of better control structure const_TokenPtr t = lexer.peek_token(); while (t->get_id() != RIGHT_CURLY) { - AST::Stmt* stmt = parse_stmt(); + ExprOrStmt expr_or_stmt = parse_stmt_or_expr_without_block(); + if (expr_or_stmt.is_error()) { + error_at(t->get_locus(), + "failed to parse statement or expression without block in block expression"); + return NULL; + } - if (stmt == NULL) { - // not necessarily an error + if (expr_or_stmt.stmt != NULL) { + // FIXME: determine if this move works + stmts.push_back(::std::move(expr_or_stmt.stmt)); + } else { + // assign to expression and end parsing inside + expr = ::std::move(expr_or_stmt.expr); break; } - stmts.push_back(::std::unique_ptr<AST::Stmt>(stmt)); - t = lexer.peek_token(); } - // parse final expression (optional) - AST::ExprWithoutBlock* expr = NULL; - if (t->get_id() != RIGHT_CURLY) { - expr = parse_expr_without_block(); - - if (expr == NULL) { - error_at(t->get_locus(), - "failed to parse final expression without block in block expression despite token " - "after last statement being '%s', not '}'", - t->get_token_description()); - skip_after_end_block(); - return NULL; - } - } - if (!skip_token(RIGHT_CURLY)) { + error_at(t->get_locus(), "error may be from having an expression (as opposed to " + "statement) in the body of the function but not last"); skip_after_end_block(); return NULL; } // ensure that there is at least either a statement or an expr - if (stmts.empty() && expr == NULL) { + /*if (stmts.empty() && expr == NULL) { error_at(lexer.peek_token()->get_id(), "block expression requires statements or an expression without block - found neither"); skip_after_end_block(); return NULL; - } + }*/ + // grammar allows for empty block expressions - return new AST::BlockExpr( - ::std::move(stmts), expr, ::std::move(inner_attrs), ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::BlockExpr>(new AST::BlockExpr(::std::move(stmts), + ::std::move(expr), ::std::move(inner_attrs), ::std::move(outer_attrs), locus)); } // Parses a "grouped" expression (expression in parentheses), used to control precedence. - AST::GroupedExpr* Parser::parse_grouped_expr(::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::GroupedExpr> Parser::parse_grouped_expr( + ::std::vector<AST::Attribute> outer_attrs) { + location_t locus = lexer.peek_token()->get_locus(); skip_token(LEFT_PAREN); ::std::vector<AST::Attribute> inner_attrs = parse_inner_attributes(); // parse required expr inside parentheses - AST::Expr* expr_in_parens = parse_expr(); + ::std::unique_ptr<AST::Expr> expr_in_parens = parse_expr(); if (expr_in_parens == NULL) { // skip after somewhere? // error? @@ -5137,12 +5649,14 @@ namespace Rust { return NULL; } - return new AST::GroupedExpr( - expr_in_parens, ::std::move(inner_attrs), ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::GroupedExpr>(new AST::GroupedExpr( + ::std::move(expr_in_parens), ::std::move(inner_attrs), ::std::move(outer_attrs), locus)); } // Parses a closure expression (closure definition). - AST::ClosureExpr* Parser::parse_closure_expr(::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::ClosureExpr> Parser::parse_closure_expr( + ::std::vector<AST::Attribute> outer_attrs) { + location_t locus = lexer.peek_token()->get_locus(); // detect optional "move" bool has_move = false; if (lexer.peek_token()->get_id() == MOVE) { @@ -5199,7 +5713,7 @@ namespace Rust { lexer.skip_token(); // parse actual type, which is required - AST::TypeNoBounds* type = parse_type_no_bounds(); + ::std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds(); if (type == NULL) { // error error_at(t->get_locus(), "failed to parse type for closure"); @@ -5208,7 +5722,7 @@ namespace Rust { } // parse block expr, which is required - AST::BlockExpr* block = parse_block_expr(); + ::std::unique_ptr<AST::BlockExpr> block = parse_block_expr(); if (block == NULL) { // error error_at(lexer.peek_token()->get_locus(), "failed to parse block expr in closure"); @@ -5216,26 +5730,28 @@ namespace Rust { return NULL; } - return new AST::ClosureExprInnerTyped( - type, block, ::std::move(params), has_move, ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::ClosureExprInnerTyped>( + new AST::ClosureExprInnerTyped(::std::move(type), ::std::move(block), + ::std::move(params), locus, has_move, ::std::move(outer_attrs))); } else { // must be expr-only closure // parse expr, which is required - AST::Expr* expr = parse_expr(); + ::std::unique_ptr<AST::Expr> expr = parse_expr(); if (expr == NULL) { error_at(t->get_locus(), "failed to parse expression in closure"); // skip somewhere? return NULL; } - return new AST::ClosureExprInner( - expr, ::std::move(params), has_move, ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::ClosureExprInner>(new AST::ClosureExprInner( + ::std::move(expr), ::std::move(params), locus, has_move, ::std::move(outer_attrs))); } } // Parses a literal token (to literal expression). - AST::LiteralExpr* Parser::parse_literal_expr(::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::LiteralExpr> Parser::parse_literal_expr( + ::std::vector<AST::Attribute> outer_attrs) { // TODO: change if literal representation in lexer changes ::std::string literal_value; @@ -5298,28 +5814,44 @@ namespace Rust { } // create literal based on stuff in switch - return new AST::LiteralExpr(::std::move(literal_value), type, ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::LiteralExpr>(new AST::LiteralExpr( + ::std::move(literal_value), ::std::move(type), t->get_locus(), ::std::move(outer_attrs))); } // Parses a return expression (including any expression to return). - AST::ReturnExpr* Parser::parse_return_expr( + ::std::unique_ptr<AST::ReturnExpr> Parser::parse_return_expr( ::std::vector<AST::Attribute> outer_attrs, bool pratt_parse) { + location_t locus = UNKNOWN_LOCATION; if (!pratt_parse) { + locus = lexer.peek_token()->get_locus(); + skip_token(RETURN_TOK); + } else { + // minus 7 chars for 6 in return and a space + // or just TODO: pass in location data + locus = lexer.peek_token()->get_locus() - 7; } // parse expression to return, if it exists - AST::Expr* returned_expr = parse_expr(); + ::std::unique_ptr<AST::Expr> returned_expr = parse_expr(); // FIXME: ensure this doesn't ruin the middle of any expressions or anything - return new AST::ReturnExpr(returned_expr, ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::ReturnExpr>( + new AST::ReturnExpr(locus, ::std::move(returned_expr), ::std::move(outer_attrs))); } // Parses a break expression (including any label to break to AND any return expression). - AST::BreakExpr* Parser::parse_break_expr( + ::std::unique_ptr<AST::BreakExpr> Parser::parse_break_expr( ::std::vector<AST::Attribute> outer_attrs, bool pratt_parse) { + location_t locus = UNKNOWN_LOCATION; if (!pratt_parse) { + locus = lexer.peek_token()->get_locus(); + skip_token(BREAK); + } else { + // minus 6 chars for 5 in return and a space + // or just TODO: pass in location data + locus = lexer.peek_token()->get_locus() - 6; } // parse label (lifetime) if it exists - create dummy first @@ -5329,14 +5861,25 @@ namespace Rust { } // parse break return expression if it exists - AST::Expr* return_expr = parse_expr(); + ::std::unique_ptr<AST::Expr> return_expr = parse_expr(); - return new AST::BreakExpr(label, return_expr, ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::BreakExpr>(new AST::BreakExpr( + locus, ::std::move(label), ::std::move(return_expr), ::std::move(outer_attrs))); } // Parses a continue expression (including any label to continue from). - AST::ContinueExpr* Parser::parse_continue_expr(::std::vector<AST::Attribute> outer_attrs) { - skip_token(CONTINUE); + ::std::unique_ptr<AST::ContinueExpr> Parser::parse_continue_expr( + ::std::vector<AST::Attribute> outer_attrs, bool pratt_parse) { + location_t locus = UNKNOWN_LOCATION; + if (!pratt_parse) { + locus = lexer.peek_token()->get_locus(); + + skip_token(CONTINUE); + } else { + // minus 9 chars for 8 in return and a space + // or just TODO: pass in location data + locus = lexer.peek_token()->get_locus() - 9; + } // parse label (lifetime) if it exists - create dummy first AST::Lifetime label = AST::Lifetime::error(); @@ -5344,7 +5887,8 @@ namespace Rust { label = parse_lifetime(); } - return new AST::ContinueExpr(label, ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::ContinueExpr>( + new AST::ContinueExpr(locus, ::std::move(label), ::std::move(outer_attrs))); } // Parses a loop label used in loop expressions. @@ -5363,14 +5907,16 @@ namespace Rust { return AST::LoopLabel::error(); } - return AST::LoopLabel(::std::move(label)); + return AST::LoopLabel(::std::move(label), t->get_locus()); } /* Parses an if expression of any kind, including with else, else if, else if let, and neither. * Note that any outer attributes will be ignored because if expressions don't support them. */ - AST::IfExpr* Parser::parse_if_expr(::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::IfExpr> Parser::parse_if_expr( + ::std::vector<AST::Attribute> outer_attrs ATTRIBUTE_UNUSED) { // TODO: make having outer attributes an error? + location_t locus = lexer.peek_token()->get_locus(); skip_token(IF); // detect accidental if let @@ -5382,8 +5928,11 @@ namespace Rust { return NULL; } - // parse required condition expr - AST::Expr* condition = parse_expr(); + // parse required condition expr - HACK to prevent struct expr from being parsed + ParseRestrictions no_struct_expr; + no_struct_expr.can_be_struct_expr = false; + ::std::unique_ptr<AST::Expr> condition + = parse_expr(::std::vector<AST::Attribute>(), no_struct_expr); if (condition == NULL) { error_at(lexer.peek_token()->get_locus(), "failed to parse condition expression in if expression"); @@ -5392,7 +5941,7 @@ namespace Rust { } // parse required block expr - AST::BlockExpr* if_body = parse_block_expr(); + ::std::unique_ptr<AST::BlockExpr> if_body = parse_block_expr(); if (if_body == NULL) { error_at(lexer.peek_token()->get_locus(), "failed to parse if body block expression in if expression"); @@ -5403,7 +5952,8 @@ namespace Rust { // branch to parse end or else (and then else, else if, or else if let) if (lexer.peek_token()->get_id() != ELSE) { // single selection - end of if expression - return new AST::IfExpr(condition, if_body); + return ::std::unique_ptr<AST::IfExpr>( + new AST::IfExpr(::std::move(condition), ::std::move(if_body), locus)); } else { // double or multiple selection - branch on end, else if, or else if let @@ -5416,7 +5966,7 @@ namespace Rust { case LEFT_CURLY: { // double selection - else // parse else block expr (required) - AST::BlockExpr* else_body = parse_block_expr(); + ::std::unique_ptr<AST::BlockExpr> else_body = parse_block_expr(); if (else_body == NULL) { error_at(lexer.peek_token()->get_locus(), "failed to parse else body block expression in if expression"); @@ -5424,14 +5974,15 @@ namespace Rust { return NULL; } - return new AST::IfExprConseqElse(condition, if_body, else_body); + return ::std::unique_ptr<AST::IfExprConseqElse>(new AST::IfExprConseqElse( + ::std::move(condition), ::std::move(if_body), ::std::move(else_body), locus)); } case IF: { // multiple selection - else if or else if let // branch on whether next token is 'let' or not if (lexer.peek_token(1)->get_id() == LET) { // parse if let expr (required) - AST::IfLetExpr* if_let_expr = parse_if_let_expr(); + ::std::unique_ptr<AST::IfLetExpr> if_let_expr = parse_if_let_expr(); if (if_let_expr == NULL) { error_at(lexer.peek_token()->get_locus(), "failed to parse (else) if let expression after if expression"); @@ -5439,10 +5990,12 @@ namespace Rust { return NULL; } - return new AST::IfExprConseqIfLet(condition, if_body, if_let_expr); + return ::std::unique_ptr<AST::IfExprConseqIfLet>( + new AST::IfExprConseqIfLet(::std::move(condition), ::std::move(if_body), + ::std::move(if_let_expr), locus)); } else { // parse if expr (required) - AST::IfExpr* if_expr = parse_if_expr(); + ::std::unique_ptr<AST::IfExpr> if_expr = parse_if_expr(); if (if_expr == NULL) { error_at(lexer.peek_token()->get_locus(), "failed to parse (else) if expression after if expression"); @@ -5450,7 +6003,8 @@ namespace Rust { return NULL; } - return new AST::IfExprConseqIf(condition, if_body, if_expr); + return ::std::unique_ptr<AST::IfExprConseqIf>(new AST::IfExprConseqIf( + ::std::move(condition), ::std::move(if_body), ::std::move(if_expr), locus)); } } default: @@ -5465,9 +6019,11 @@ namespace Rust { /* Parses an if let expression of any kind, including with else, else if, else if let, and none. * Note that any outer attributes will be ignored as if let expressions don't support them. */ - AST::IfLetExpr* Parser::parse_if_let_expr(::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::IfLetExpr> Parser::parse_if_let_expr( + ::std::vector<AST::Attribute> outer_attrs ATTRIBUTE_UNUSED) { // TODO: make having outer attributes an error? + location_t locus = lexer.peek_token()->get_locus(); skip_token(IF); // detect accidental if expr parsed as if let expr @@ -5482,7 +6038,7 @@ namespace Rust { // parse match arm patterns (which are required) ::std::vector< ::std::unique_ptr<AST::Pattern> > match_arm_patterns - = parse_match_arm_patterns(); + = parse_match_arm_patterns(EQUAL); if (match_arm_patterns.empty()) { error_at(lexer.peek_token()->get_locus(), "failed to parse any match arm patterns in if let expression"); @@ -5495,8 +6051,11 @@ namespace Rust { return NULL; } - // parse expression (required) - AST::Expr* scrutinee_expr = parse_expr(); + // parse expression (required) - HACK to prevent struct expr being parsed + ParseRestrictions no_struct_expr; + no_struct_expr.can_be_struct_expr = false; + ::std::unique_ptr<AST::Expr> scrutinee_expr + = parse_expr(::std::vector<AST::Attribute>(), no_struct_expr); if (scrutinee_expr == NULL) { error_at(lexer.peek_token()->get_locus(), "failed to parse scrutinee expression in if let expression"); @@ -5507,7 +6066,7 @@ namespace Rust { * or actually probably in semantic analysis. */ // parse block expression (required) - AST::BlockExpr* if_let_body = parse_block_expr(); + ::std::unique_ptr<AST::BlockExpr> if_let_body = parse_block_expr(); if (if_let_body == NULL) { error_at(lexer.peek_token()->get_locus(), "failed to parse if let body block expression in if let expression"); @@ -5518,7 +6077,9 @@ namespace Rust { // branch to parse end or else (and then else, else if, or else if let) if (lexer.peek_token()->get_id() != ELSE) { // single selection - end of if let expression - return new AST::IfLetExpr(::std::move(match_arm_patterns), scrutinee_expr, if_let_body); + return ::std::unique_ptr<AST::IfLetExpr>( + new AST::IfLetExpr(::std::move(match_arm_patterns), ::std::move(scrutinee_expr), + ::std::move(if_let_body), locus)); } else { // double or multiple selection - branch on end, else if, or else if let @@ -5531,7 +6092,7 @@ namespace Rust { case LEFT_CURLY: { // double selection - else // parse else block expr (required) - AST::BlockExpr* else_body = parse_block_expr(); + ::std::unique_ptr<AST::BlockExpr> else_body = parse_block_expr(); if (else_body == NULL) { error_at(lexer.peek_token()->get_locus(), "failed to parse else body block expression in if let expression"); @@ -5539,15 +6100,16 @@ namespace Rust { return NULL; } - return new AST::IfLetExprConseqElse( - ::std::move(match_arm_patterns), scrutinee_expr, if_let_body, else_body); + return ::std::unique_ptr<AST::IfLetExprConseqElse>(new AST::IfLetExprConseqElse( + ::std::move(match_arm_patterns), ::std::move(scrutinee_expr), + ::std::move(if_let_body), ::std::move(else_body), locus)); } case IF: { // multiple selection - else if or else if let // branch on whether next token is 'let' or not if (lexer.peek_token(1)->get_id() == LET) { // parse if let expr (required) - AST::IfLetExpr* if_let_expr = parse_if_let_expr(); + ::std::unique_ptr<AST::IfLetExpr> if_let_expr = parse_if_let_expr(); if (if_let_expr == NULL) { error_at(lexer.peek_token()->get_locus(), "failed to parse (else) if let expression after if let expression"); @@ -5555,11 +6117,13 @@ namespace Rust { return NULL; } - return new AST::IfLetExprConseqIfLet( - ::std::move(match_arm_patterns), scrutinee_expr, if_let_body, if_let_expr); + return ::std::unique_ptr<AST::IfLetExprConseqIfLet>( + new AST::IfLetExprConseqIfLet(::std::move(match_arm_patterns), + ::std::move(scrutinee_expr), ::std::move(if_let_body), + ::std::move(if_let_expr), locus)); } else { // parse if expr (required) - AST::IfExpr* if_expr = parse_if_expr(); + ::std::unique_ptr<AST::IfExpr> if_expr = parse_if_expr(); if (if_expr == NULL) { error_at(lexer.peek_token()->get_locus(), "failed to parse (else) if expression after if let expression"); @@ -5567,8 +6131,9 @@ namespace Rust { return NULL; } - return new AST::IfLetExprConseqIf( - ::std::move(match_arm_patterns), scrutinee_expr, if_let_body, if_expr); + return ::std::unique_ptr<AST::IfLetExprConseqIf>(new AST::IfLetExprConseqIf( + ::std::move(match_arm_patterns), ::std::move(scrutinee_expr), + ::std::move(if_let_body), ::std::move(if_expr), locus)); } } default: @@ -5585,25 +6150,38 @@ namespace Rust { /* Parses a "loop" infinite loop expression. Label is not parsed and should be parsed via * parse_labelled_loop_expr, which would call this. */ - AST::LoopExpr* Parser::parse_loop_expr( + ::std::unique_ptr<AST::LoopExpr> Parser::parse_loop_expr( ::std::vector<AST::Attribute> outer_attrs, AST::LoopLabel label) { + location_t locus = UNKNOWN_LOCATION; + if (label.is_error()) { + locus = lexer.peek_token()->get_locus(); + } else { + locus = label.get_locus(); + } skip_token(LOOP); // parse loop body, which is required - AST::BlockExpr* loop_body = parse_block_expr(); + ::std::unique_ptr<AST::BlockExpr> loop_body = parse_block_expr(); if (loop_body == NULL) { error_at(lexer.peek_token()->get_locus(), "could not parse loop body in (infinite) loop expression"); return NULL; } - return new AST::LoopExpr(loop_body, ::std::move(label), ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::LoopExpr>(new AST::LoopExpr( + ::std::move(loop_body), locus, ::std::move(label), ::std::move(outer_attrs))); } /* Parses a "while" loop expression. Label is not parsed and should be parsed via * parse_labelled_loop_expr, which would call this. */ - AST::WhileLoopExpr* Parser::parse_while_loop_expr( + ::std::unique_ptr<AST::WhileLoopExpr> Parser::parse_while_loop_expr( ::std::vector<AST::Attribute> outer_attrs, AST::LoopLabel label) { + location_t locus = UNKNOWN_LOCATION; + if (label.is_error()) { + locus = lexer.peek_token()->get_locus(); + } else { + locus = label.get_locus(); + } skip_token(WHILE); // ensure it isn't a while let loop @@ -5615,8 +6193,11 @@ namespace Rust { return NULL; } - // parse loop predicate (required) - AST::Expr* predicate = parse_expr(); + // parse loop predicate (required) with HACK to prevent struct expr parsing + ParseRestrictions no_struct_expr; + no_struct_expr.can_be_struct_expr = false; + ::std::unique_ptr<AST::Expr> predicate + = parse_expr(::std::vector<AST::Attribute>(), no_struct_expr); if (predicate == NULL) { error_at( lexer.peek_token()->get_locus(), "failed to parse predicate expression in while loop"); @@ -5626,7 +6207,7 @@ namespace Rust { // TODO: check that it isn't struct expression here? actually, probably in semantic analysis // parse loop body (required) - AST::BlockExpr* body = parse_block_expr(); + ::std::unique_ptr<AST::BlockExpr> body = parse_block_expr(); if (body == NULL) { error_at(lexer.peek_token()->get_locus(), "failed to parse loop body block expression in while loop"); @@ -5634,13 +6215,20 @@ namespace Rust { return NULL; } - return new AST::WhileLoopExpr(predicate, body, ::std::move(label), ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::WhileLoopExpr>(new AST::WhileLoopExpr(::std::move(predicate), + ::std::move(body), locus, ::std::move(label), ::std::move(outer_attrs))); } /* Parses a "while let" loop expression. Label is not parsed and should be parsed via * parse_labelled_loop_expr, which would call this. */ - AST::WhileLetLoopExpr* Parser::parse_while_let_loop_expr( + ::std::unique_ptr<AST::WhileLetLoopExpr> Parser::parse_while_let_loop_expr( ::std::vector<AST::Attribute> outer_attrs, AST::LoopLabel label) { + location_t locus = UNKNOWN_LOCATION; + if (label.is_error()) { + locus = lexer.peek_token()->get_locus(); + } else { + locus = label.get_locus(); + } skip_token(WHILE); // check for possible accidental recognition of a while loop as a while let loop @@ -5656,7 +6244,7 @@ namespace Rust { // parse predicate patterns ::std::vector< ::std::unique_ptr<AST::Pattern> > predicate_patterns - = parse_match_arm_patterns(); + = parse_match_arm_patterns(EQUAL); // TODO: have to ensure that there is at least 1 pattern? if (!skip_token(EQUAL)) { @@ -5664,8 +6252,11 @@ namespace Rust { return NULL; } - // parse predicate expression, which is required - AST::Expr* predicate_expr = parse_expr(); + // parse predicate expression, which is required (and HACK to prevent struct expr) + ParseRestrictions no_struct_expr; + no_struct_expr.can_be_struct_expr = false; + ::std::unique_ptr<AST::Expr> predicate_expr + = parse_expr(::std::vector<AST::Attribute>(), no_struct_expr); if (predicate_expr == NULL) { error_at(lexer.peek_token()->get_locus(), "failed to parse predicate expression in while let loop"); @@ -5675,7 +6266,7 @@ namespace Rust { // TODO: ensure that struct expression is not parsed? Actually, probably in semantic analysis. // parse loop body, which is required - AST::BlockExpr* body = parse_block_expr(); + ::std::unique_ptr<AST::BlockExpr> body = parse_block_expr(); if (body == NULL) { error_at(lexer.peek_token()->get_locus(), "failed to parse block expr (loop body) of while let loop"); @@ -5683,18 +6274,25 @@ namespace Rust { return NULL; } - return new AST::WhileLetLoopExpr(::std::move(predicate_patterns), predicate_expr, body, - ::std::move(label), ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::WhileLetLoopExpr>( + new AST::WhileLetLoopExpr(::std::move(predicate_patterns), ::std::move(predicate_expr), + ::std::move(body), locus, ::std::move(label), ::std::move(outer_attrs))); } /* Parses a "for" iterative loop. Label is not parsed and should be parsed via * parse_labelled_loop_expr, which would call this. */ - AST::ForLoopExpr* Parser::parse_for_loop_expr( + ::std::unique_ptr<AST::ForLoopExpr> Parser::parse_for_loop_expr( ::std::vector<AST::Attribute> outer_attrs, AST::LoopLabel label) { + location_t locus = UNKNOWN_LOCATION; + if (label.is_error()) { + locus = lexer.peek_token()->get_locus(); + } else { + locus = label.get_locus(); + } skip_token(FOR); // parse pattern, which is required - AST::Pattern* pattern = parse_pattern(); + ::std::unique_ptr<AST::Pattern> pattern = parse_pattern(); if (pattern == NULL) { error_at(lexer.peek_token()->get_locus(), "failed to parse iterator pattern in for loop"); // skip somewhere? @@ -5706,8 +6304,11 @@ namespace Rust { return NULL; } - // parse iterator expression, which is required - AST::Expr* expr = parse_expr(); + // parse iterator expression, which is required - also HACK to prevent struct expr + ParseRestrictions no_struct_expr; + no_struct_expr.can_be_struct_expr = false; + ::std::unique_ptr<AST::Expr> expr + = parse_expr(::std::vector<AST::Attribute>(), no_struct_expr); if (expr == NULL) { error_at( lexer.peek_token()->get_locus(), "failed to parse iterator expression in for loop"); @@ -5717,7 +6318,7 @@ namespace Rust { // TODO: check to ensure this isn't struct expr? Or in semantic analysis. // parse loop body, which is required - AST::BlockExpr* body = parse_block_expr(); + ::std::unique_ptr<AST::BlockExpr> body = parse_block_expr(); if (body == NULL) { error_at(lexer.peek_token()->get_locus(), "failed to parse loop body block expression in for loop"); @@ -5725,12 +6326,13 @@ namespace Rust { return NULL; } - return new AST::ForLoopExpr( - pattern, expr, body, ::std::move(label), ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::ForLoopExpr>(new AST::ForLoopExpr(::std::move(pattern), + ::std::move(expr), ::std::move(body), locus, ::std::move(label), ::std::move(outer_attrs))); } // Parses a loop expression with label (any kind of loop - disambiguates). - AST::BaseLoopExpr* Parser::parse_labelled_loop_expr(::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::BaseLoopExpr> Parser::parse_labelled_loop_expr( + ::std::vector<AST::Attribute> outer_attrs) { // TODO: decide whether it should not work if there is no label, or parse it with no label // at the moment, I will make it not work with no label because that's the implication. @@ -5775,11 +6377,24 @@ namespace Rust { } // Parses a match expression. - AST::MatchExpr* Parser::parse_match_expr(::std::vector<AST::Attribute> outer_attrs) { - skip_token(MATCH_TOK); + ::std::unique_ptr<AST::MatchExpr> Parser::parse_match_expr( + ::std::vector<AST::Attribute> outer_attrs, bool pratt_parse) { + location_t locus = UNKNOWN_LOCATION; + if (!pratt_parse) { + locus = lexer.peek_token()->get_locus(); + + skip_token(MATCH_TOK); + } else { + // TODO: probably just pass in location data as param + // get current pos then move back 6 - 5 for match, 1 for space + locus = lexer.peek_token()->get_locus() - 6; + } - // parse scrutinee expression, which is required - AST::Expr* scrutinee = parse_expr(); + // parse scrutinee expression, which is required (and HACK to prevent struct expr) + ParseRestrictions no_struct_expr; + no_struct_expr.can_be_struct_expr = false; + ::std::unique_ptr<AST::Expr> scrutinee + = parse_expr(::std::vector<AST::Attribute>(), no_struct_expr); if (scrutinee == NULL) { error_at(lexer.peek_token()->get_locus(), "failed to parse scrutinee expression in match expression"); @@ -5799,26 +6414,38 @@ namespace Rust { // parse match arms (if they exist) ::std::vector< ::std::unique_ptr<AST::MatchCase> > match_arms; + // DEBUG + fprintf(stderr, "about to start loop to start parsing match cases\n"); + // FIXME: absolute worst control structure ever // parse match cases while (true) { // parse match arm itself, which is required AST::MatchArm arm = parse_match_arm(); if (arm.is_error()) { + // DEBUG + fprintf(stderr, "broke loop on invalid match arm\n"); + // not necessarily an error break; } + // DEBUG + fprintf(stderr, "parsed valid match arm\n"); + if (!skip_token(MATCH_ARROW)) { // skip after somewhere? // TODO is returning here a good idea? or is break better? return NULL; } + // DEBUG + fprintf(stderr, "skipped match arrow\n"); + // branch on next token - if '{', block expr, otherwise just expr if (lexer.peek_token()->get_id() == LEFT_CURLY) { // block expr - AST::BlockExpr* block_expr = parse_block_expr(); + ::std::unique_ptr<AST::BlockExpr> block_expr = parse_block_expr(); if (block_expr == NULL) { error_at(lexer.peek_token()->get_locus(), "failed to parse block expr in match arm in match expr"); @@ -5827,9 +6454,9 @@ namespace Rust { } // create match case block expr and add to cases - AST::MatchCaseBlockExpr* match_case_block - = new AST::MatchCaseBlockExpr(::std::move(arm), block_expr); - match_arms.push_back(::std::unique_ptr<AST::MatchCaseBlockExpr>(match_case_block)); + ::std::unique_ptr<AST::MatchCaseBlockExpr> match_case_block( + new AST::MatchCaseBlockExpr(::std::move(arm), ::std::move(block_expr))); + match_arms.push_back(::std::move(match_case_block)); // skip optional comma if (lexer.peek_token()->get_id() == COMMA) { @@ -5837,7 +6464,7 @@ namespace Rust { } } else { // regular expr - AST::Expr* expr = parse_expr(); + ::std::unique_ptr<AST::Expr> expr = parse_expr(); if (expr == NULL) { error_at(lexer.peek_token()->get_locus(), "failed to parse expr in match arm in match expr"); @@ -5846,8 +6473,9 @@ namespace Rust { } // construct match case expr and add to cases - AST::MatchCaseExpr* match_case_expr = new AST::MatchCaseExpr(::std::move(arm), expr); - match_arms.push_back(::std::unique_ptr<AST::MatchCaseExpr>(match_case_expr)); + ::std::unique_ptr<AST::MatchCaseExpr> match_case_expr( + new AST::MatchCaseExpr(::std::move(arm), ::std::move(expr))); + match_arms.push_back(::std::move(match_case_expr)); // skip REQUIRED comma - if no comma, break if (lexer.peek_token()->get_id() != COMMA) { @@ -5863,8 +6491,8 @@ namespace Rust { return NULL; } - return new AST::MatchExpr( - scrutinee, ::std::move(match_arms), ::std::move(inner_attrs), ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::MatchExpr>(new AST::MatchExpr(::std::move(scrutinee), + ::std::move(match_arms), ::std::move(inner_attrs), ::std::move(outer_attrs), locus)); } // Parses the "pattern" part of the match arm (the 'case x:' equivalent). @@ -5872,17 +6500,29 @@ namespace Rust { // parse optional outer attributes ::std::vector<AST::Attribute> outer_attrs = parse_outer_attributes(); + // DEBUG + fprintf(stderr, "about to start parsing match arm patterns\n"); + + // break early if find right curly + if (lexer.peek_token()->get_id() == RIGHT_CURLY) { + // not an error + return AST::MatchArm::create_error(); + } + // parse match arm patterns - at least 1 is required ::std::vector< ::std::unique_ptr<AST::Pattern> > match_arm_patterns - = parse_match_arm_patterns(); + = parse_match_arm_patterns(RIGHT_CURLY); if (match_arm_patterns.empty()) { error_at(lexer.peek_token()->get_locus(), "failed to parse any patterns in match arm"); // skip somewhere? return AST::MatchArm::create_error(); } + // DEBUG + fprintf(stderr, "successfully parsed match arm patterns\n"); + // parse match arm guard expr if it exists - AST::Expr* guard_expr = NULL; + ::std::unique_ptr<AST::Expr> guard_expr = NULL; if (lexer.peek_token()->get_id() == IF) { lexer.skip_token(); @@ -5895,11 +6535,17 @@ namespace Rust { } } - return AST::MatchArm(::std::move(match_arm_patterns), guard_expr, ::std::move(outer_attrs)); + // DEBUG + fprintf(stderr, "successfully parsed match arm\n"); + + return AST::MatchArm( + ::std::move(match_arm_patterns), ::std::move(guard_expr), ::std::move(outer_attrs)); } - // Parses the patterns used in a match arm. - ::std::vector< ::std::unique_ptr<AST::Pattern> > Parser::parse_match_arm_patterns() { + /* Parses the patterns used in a match arm. End token id is the id of the token that would exist + * after the patterns are done (e.g. '}' for match expr, '=' for if let and while let). */ + ::std::vector< ::std::unique_ptr<AST::Pattern> > Parser::parse_match_arm_patterns( + TokenId end_token_id) { // skip optional leading '|' bool has_leading_pipe = false; if (lexer.peek_token()->get_id() == PIPE) { @@ -5911,13 +6557,21 @@ namespace Rust { ::std::vector< ::std::unique_ptr<AST::Pattern> > patterns; + // quick break out if end_token_id + if (lexer.peek_token()->get_id() == end_token_id) { + return patterns; + } + // parse required pattern - if doesn't exist, return empty - AST::Pattern* initial_pattern = parse_pattern(); + ::std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern(); if (initial_pattern == NULL) { // FIXME: should this be an error? return patterns; } - patterns.push_back(::std::unique_ptr<AST::Pattern>(initial_pattern)); + patterns.push_back(::std::move(initial_pattern)); + + // DEBUG + fprintf(stderr, "successfully parsed initial match arm pattern\n"); // parse new patterns as long as next char is '|' const_TokenPtr t = lexer.peek_token(); @@ -5925,8 +6579,13 @@ namespace Rust { // skip pipe token lexer.skip_token(); + // break if hit end token id + if (lexer.peek_token()->get_id() == end_token_id) { + break; + } + // parse pattern - AST::Pattern* pattern = parse_pattern(); + ::std::unique_ptr<AST::Pattern> pattern = parse_pattern(); if (pattern == NULL) { // this is an error error_at( @@ -5935,7 +6594,7 @@ namespace Rust { return ::std::vector< ::std::unique_ptr<AST::Pattern> >(); } - patterns.push_back(::std::unique_ptr<AST::Pattern>(pattern)); + patterns.push_back(::std::move(pattern)); t = lexer.peek_token(); } @@ -5944,7 +6603,9 @@ namespace Rust { } // Parses an async block expression. - AST::AsyncBlockExpr* Parser::parse_async_block_expr(::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::AsyncBlockExpr> Parser::parse_async_block_expr( + ::std::vector<AST::Attribute> outer_attrs) { + location_t locus = lexer.peek_token()->get_locus(); skip_token(ASYNC); // detect optional move token @@ -5955,7 +6616,7 @@ namespace Rust { } // parse block expression (required) - AST::BlockExpr* block_expr = parse_block_expr(); + ::std::unique_ptr<AST::BlockExpr> block_expr = parse_block_expr(); if (block_expr == NULL) { error_at(lexer.peek_token()->get_locus(), "failed to parse block expression of async block expression"); @@ -5963,15 +6624,18 @@ namespace Rust { return NULL; } - return new AST::AsyncBlockExpr(block_expr, has_move, ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::AsyncBlockExpr>(new AST::AsyncBlockExpr( + ::std::move(block_expr), has_move, ::std::move(outer_attrs), locus)); } // Parses an unsafe block expression. - AST::UnsafeBlockExpr* Parser::parse_unsafe_block_expr(::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::UnsafeBlockExpr> Parser::parse_unsafe_block_expr( + ::std::vector<AST::Attribute> outer_attrs) { + location_t locus = lexer.peek_token()->get_locus(); skip_token(UNSAFE); // parse block expression (required) - AST::BlockExpr* block_expr = parse_block_expr(); + ::std::unique_ptr<AST::BlockExpr> block_expr = parse_block_expr(); if (block_expr == NULL) { error_at(lexer.peek_token()->get_locus(), "failed to parse block expression of unsafe block expression"); @@ -5979,12 +6643,21 @@ namespace Rust { return NULL; } - return new AST::UnsafeBlockExpr(block_expr, ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::UnsafeBlockExpr>( + new AST::UnsafeBlockExpr(::std::move(block_expr), ::std::move(outer_attrs), locus)); } // Parses an array definition expression. - AST::ArrayExpr* Parser::parse_array_expr(::std::vector<AST::Attribute> outer_attrs) { - skip_token(LEFT_SQUARE); + ::std::unique_ptr<AST::ArrayExpr> Parser::parse_array_expr( + ::std::vector<AST::Attribute> outer_attrs, bool pratt_parse) { + location_t locus = UNKNOWN_LOCATION; + if (!pratt_parse) { + locus = lexer.peek_token()->get_locus(); + + skip_token(LEFT_SQUARE); + } else { + locus = lexer.peek_token()->get_locus() - 1; + } // parse optional inner attributes ::std::vector<AST::Attribute> inner_attrs = parse_inner_attributes(); @@ -5994,11 +6667,12 @@ namespace Rust { // no array elements lexer.skip_token(); - return new AST::ArrayExpr(NULL, ::std::move(inner_attrs), ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::ArrayExpr>( + new AST::ArrayExpr(NULL, ::std::move(inner_attrs), ::std::move(outer_attrs), locus)); } else { // should have array elements // parse initial expression, which is required for either - AST::Expr* initial_expr = parse_expr(); + ::std::unique_ptr<AST::Expr> initial_expr = parse_expr(); if (initial_expr == NULL) { error_at(lexer.peek_token()->get_locus(), "could not parse expression in array expression " @@ -6012,7 +6686,7 @@ namespace Rust { lexer.skip_token(); // parse copy amount expression (required) - AST::Expr* copy_amount = parse_expr(); + ::std::unique_ptr<AST::Expr> copy_amount = parse_expr(); if (copy_amount == NULL) { error_at(lexer.peek_token()->get_locus(), "could not parse copy amount expression in array expression (arrayelems)"); @@ -6020,22 +6694,24 @@ namespace Rust { return NULL; } - AST::ArrayElemsCopied* copied_array_elems - = new AST::ArrayElemsCopied(initial_expr, copy_amount); - return new AST::ArrayExpr( - copied_array_elems, ::std::move(inner_attrs), ::std::move(outer_attrs)); + ::std::unique_ptr<AST::ArrayElemsCopied> copied_array_elems( + new AST::ArrayElemsCopied(::std::move(initial_expr), ::std::move(copy_amount))); + return ::std::unique_ptr<AST::ArrayExpr>( + new AST::ArrayExpr(::std::move(copied_array_elems), ::std::move(inner_attrs), + ::std::move(outer_attrs), locus)); } else if (lexer.peek_token()->get_id() == RIGHT_SQUARE) { // single-element array expression ::std::vector< ::std::unique_ptr<AST::Expr> > exprs; - exprs.push_back(::std::unique_ptr<AST::Expr>(initial_expr)); + exprs.push_back(::std::move(initial_expr)); - AST::ArrayElemsValues* array_elems = new AST::ArrayElemsValues(::std::move(exprs)); - return new AST::ArrayExpr( - array_elems, ::std::move(inner_attrs), ::std::move(outer_attrs)); + ::std::unique_ptr<AST::ArrayElemsValues> array_elems( + new AST::ArrayElemsValues(::std::move(exprs))); + return ::std::unique_ptr<AST::ArrayExpr>(new AST::ArrayExpr(::std::move(array_elems), + ::std::move(inner_attrs), ::std::move(outer_attrs), locus)); } else if (lexer.peek_token()->get_id() == COMMA) { // multi-element array expression (or trailing comma) ::std::vector< ::std::unique_ptr<AST::Expr> > exprs; - exprs.push_back(::std::unique_ptr<AST::Expr>(initial_expr)); + exprs.push_back(::std::move(initial_expr)); const_TokenPtr t = lexer.peek_token(); while (t->get_id() == COMMA) { @@ -6047,23 +6723,24 @@ namespace Rust { } // parse expression (required) - AST::Expr* expr = parse_expr(); + ::std::unique_ptr<AST::Expr> expr = parse_expr(); if (expr == NULL) { error_at(lexer.peek_token()->get_locus(), "failed to parse element in array expression"); // skip somewhere? return NULL; } - exprs.push_back(::std::unique_ptr<AST::Expr>(expr)); + exprs.push_back(::std::move(expr)); t = lexer.peek_token(); } skip_token(RIGHT_SQUARE); - AST::ArrayElemsValues* array_elems = new AST::ArrayElemsValues(::std::move(exprs)); - return new AST::ArrayExpr( - array_elems, ::std::move(inner_attrs), ::std::move(outer_attrs)); + ::std::unique_ptr<AST::ArrayElemsValues> array_elems( + new AST::ArrayElemsValues(::std::move(exprs))); + return ::std::unique_ptr<AST::ArrayExpr>(new AST::ArrayExpr(::std::move(array_elems), + ::std::move(inner_attrs), ::std::move(outer_attrs), locus)); } else { // error error_at(lexer.peek_token()->get_locus(), @@ -6078,14 +6755,14 @@ namespace Rust { // Parses a single parameter used in a closure definition. AST::ClosureParam Parser::parse_closure_param() { // parse pattern (which is required) - AST::Pattern* pattern = parse_pattern(); + ::std::unique_ptr<AST::Pattern> pattern = parse_pattern(); if (pattern == NULL) { // not necessarily an error return AST::ClosureParam::create_error(); } // parse optional type of param - AST::Type* type = NULL; + ::std::unique_ptr<AST::Type> type = NULL; if (lexer.peek_token()->get_id() == COLON) { lexer.skip_token(); @@ -6098,15 +6775,20 @@ namespace Rust { } } - return AST::ClosureParam(pattern, type); + return AST::ClosureParam(::std::move(pattern), ::std::move(type)); } // Parses a grouped or tuple expression (disambiguates). - AST::ExprWithoutBlock* Parser::parse_grouped_or_tuple_expr( + ::std::unique_ptr<AST::ExprWithoutBlock> Parser::parse_grouped_or_tuple_expr( ::std::vector<AST::Attribute> outer_attrs, bool pratt_parse) { // adjustment to allow Pratt parsing to reuse function without copy-paste + location_t locus = UNKNOWN_LOCATION; if (!pratt_parse) { + locus = lexer.peek_token()->get_locus(); + skip_token(LEFT_PAREN); + } else { + locus = lexer.peek_token()->get_locus() - 1; } // parse optional inner attributes @@ -6117,12 +6799,13 @@ namespace Rust { lexer.skip_token(); // create tuple with empty tuple elems - return new AST::TupleExpr(::std::vector< ::std::unique_ptr<AST::Expr> >(), - ::std::move(inner_attrs), ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::TupleExpr>( + new AST::TupleExpr(::std::vector< ::std::unique_ptr<AST::Expr> >(), + ::std::move(inner_attrs), ::std::move(outer_attrs), locus)); } // parse first expression (required) - AST::Expr* first_expr = parse_expr(); + ::std::unique_ptr<AST::Expr> first_expr = parse_expr(); if (first_expr == NULL) { error_at(lexer.peek_token()->get_locus(), "failed to parse expression in grouped or tuple expression"); @@ -6136,12 +6819,12 @@ namespace Rust { lexer.skip_token(); // create grouped expr - return new AST::GroupedExpr( - first_expr, ::std::move(inner_attrs), ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::GroupedExpr>(new AST::GroupedExpr( + ::std::move(first_expr), ::std::move(inner_attrs), ::std::move(outer_attrs), locus)); } else if (lexer.peek_token()->get_id() == COMMA) { // tuple expr ::std::vector< ::std::unique_ptr<AST::Expr> > exprs; - exprs.push_back(::std::unique_ptr<AST::Expr>(first_expr)); + exprs.push_back(::std::move(first_expr)); // parse potential other tuple exprs const_TokenPtr t = lexer.peek_token(); @@ -6154,13 +6837,13 @@ namespace Rust { } // parse expr, which is now required - AST::Expr* expr = parse_expr(); + ::std::unique_ptr<AST::Expr> expr = parse_expr(); if (expr == NULL) { error_at(lexer.peek_token()->get_locus(), "failed to parse expr in tuple expr"); // skip somewhere? return NULL; } - exprs.push_back(::std::unique_ptr<AST::Expr>(expr)); + exprs.push_back(::std::move(expr)); t = lexer.peek_token(); } @@ -6168,22 +6851,22 @@ namespace Rust { // skip right paren skip_token(RIGHT_PAREN); - return new AST::TupleExpr( - ::std::move(exprs), ::std::move(inner_attrs), ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::TupleExpr>(new AST::TupleExpr( + ::std::move(exprs), ::std::move(inner_attrs), ::std::move(outer_attrs), locus)); } else { // error const_TokenPtr t = lexer.peek_token(); error_at(t->get_locus(), "unexpected token '%s' in grouped or tuple expression (parenthesised expression) - " "expected ')' for grouped expr and ',' for tuple expr", - t->get_str().c_str()); + t->get_token_description()); // skip somewhere? return NULL; } } // Parses a type (will further disambiguate any type). - AST::Type* Parser::parse_type() { + ::std::unique_ptr<AST::Type> Parser::parse_type() { /* rules for all types: * NeverType: '!' * SliceType: '[' Type ']' @@ -6220,7 +6903,7 @@ namespace Rust { case EXCLAM: // never type - can't be macro as no path beforehand lexer.skip_token(); - return new AST::NeverType(); + return ::std::unique_ptr<AST::NeverType>(new AST::NeverType(t->get_locus())); case LEFT_SQUARE: // slice type or array type - requires further disambiguation return parse_slice_or_array_type(); @@ -6231,12 +6914,13 @@ namespace Rust { error_at(t->get_locus(), "failed to parse qualified path in type"); return NULL; } - return new AST::QualifiedPathInType(::std::move(path)); + return ::std::unique_ptr<AST::QualifiedPathInType>( + new AST::QualifiedPathInType(::std::move(path))); } case UNDERSCORE: // inferred type lexer.skip_token(); - return new AST::InferredType(); + return ::std::unique_ptr<AST::InferredType>(new AST::InferredType(t->get_locus())); case ASTERISK: // raw pointer type return parse_raw_pointer_type(); @@ -6248,7 +6932,8 @@ namespace Rust { ::std::vector< ::std::unique_ptr<AST::TypeParamBound> > bounds = parse_type_param_bounds(); - return new AST::TraitObjectType(::std::move(bounds)); + return ::std::unique_ptr<AST::TraitObjectType>( + new AST::TraitObjectType(::std::move(bounds), t->get_locus())); } case IDENTIFIER: case SUPER: @@ -6271,6 +6956,7 @@ namespace Rust { error_at(t->get_locus(), "failed to parse path as first component of type"); return NULL; } + location_t locus = path.get_locus(); // branch on next token t = lexer.peek_token(); @@ -6289,37 +6975,39 @@ namespace Rust { AST::DelimTokenTree tok_tree = parse_delim_token_tree(); - return new AST::MacroInvocation(::std::move(macro_path), - ::std::move(tok_tree), ::std::vector<AST::Attribute>()); + return ::std::unique_ptr<AST::MacroInvocation>( + new AST::MacroInvocation(::std::move(macro_path), ::std::move(tok_tree), + ::std::vector<AST::Attribute>(), locus)); } case PLUS: { // type param bounds ::std::vector< ::std::unique_ptr<AST::TypeParamBound> > bounds; // convert type path to trait bound - AST::TraitBound* path_bound - = new AST::TraitBound(::std::move(path), false, false); - bounds.push_back(::std::unique_ptr<AST::TraitBound>(path_bound)); + ::std::unique_ptr<AST::TraitBound> path_bound( + new AST::TraitBound(::std::move(path), locus, false, false)); + bounds.push_back(::std::move(path_bound)); // parse rest of bounds - FIXME: better way to find when to stop parsing while (t->get_id() == PLUS) { lexer.skip_token(); // parse bound if it exists - if not, assume end of sequence - AST::TypeParamBound* bound = parse_type_param_bound(); + ::std::unique_ptr<AST::TypeParamBound> bound = parse_type_param_bound(); if (bound == NULL) { break; } - bounds.push_back(::std::unique_ptr<AST::TypeParamBound>(bound)); + bounds.push_back(::std::move(bound)); t = lexer.peek_token(); } - return new AST::TraitObjectType(::std::move(bounds)); + return ::std::unique_ptr<AST::TraitObjectType>( + new AST::TraitObjectType(::std::move(bounds), locus)); } default: // assume that this is a type path and not an error - return new AST::TypePath(::std::move(path)); + return ::std::unique_ptr<AST::TypePath>(new AST::TypePath(::std::move(path))); } } case LEFT_PAREN: @@ -6344,44 +7032,51 @@ namespace Rust { ::std::vector< ::std::unique_ptr<AST::TypeParamBound> > bounds = parse_type_param_bounds(); - return new AST::ImplTraitType(::std::move(bounds)); + return ::std::unique_ptr<AST::ImplTraitType>( + new AST::ImplTraitType(::std::move(bounds), t->get_locus())); } else { // should be trait bound, so parse trait bound - AST::TraitBound* initial_bound = parse_trait_bound(); + ::std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound(); if (initial_bound == NULL) { error_at(lexer.peek_token()->get_locus(), "failed to parse ImplTraitType initial bound"); return NULL; } + location_t locus = t->get_locus(); + // short cut if next token isn't '+' t = lexer.peek_token(); if (t->get_id() != PLUS) { // convert trait bound to value object AST::TraitBound value_bound(*initial_bound); - delete initial_bound; - return new AST::ImplTraitTypeOneBound(::std::move(value_bound)); + // DEBUG: removed as unique ptr, so should auto-delete + // delete initial_bound; + + return ::std::unique_ptr<AST::ImplTraitTypeOneBound>( + new AST::ImplTraitTypeOneBound(::std::move(value_bound), locus)); } // parse additional type param bounds ::std::vector< ::std::unique_ptr<AST::TypeParamBound> > bounds; - bounds.push_back(::std::unique_ptr<AST::TraitBound>(initial_bound)); + bounds.push_back(::std::move(initial_bound)); while (t->get_id() == PLUS) { lexer.skip_token(); // parse bound if it exists - AST::TypeParamBound* bound = parse_type_param_bound(); + ::std::unique_ptr<AST::TypeParamBound> bound = parse_type_param_bound(); if (bound == NULL) { // not an error as trailing plus may exist break; } - bounds.push_back(::std::unique_ptr<AST::TypeParamBound>(bound)); + bounds.push_back(::std::move(bound)); t = lexer.peek_token(); } - return new AST::ImplTraitType(::std::move(bounds)); + return ::std::unique_ptr<AST::ImplTraitType>( + new AST::ImplTraitType(::std::move(bounds), locus)); } case DYN: case QUESTION_MARK: { @@ -6397,10 +7092,11 @@ namespace Rust { ::std::vector< ::std::unique_ptr<AST::TypeParamBound> > bounds = parse_type_param_bounds(); - return new AST::TraitObjectType(::std::move(bounds), has_dyn); + return ::std::unique_ptr<AST::TraitObjectType>( + new AST::TraitObjectType(::std::move(bounds), t->get_locus(), has_dyn)); } else { // should be trait bound, so parse trait bound - AST::TraitBound* initial_bound = parse_trait_bound(); + ::std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound(); if (initial_bound == NULL) { error_at(lexer.peek_token()->get_locus(), "failed to parse TraitObjectType initial bound"); @@ -6412,41 +7108,46 @@ namespace Rust { if (t->get_id() != PLUS) { // convert trait bound to value object AST::TraitBound value_bound(*initial_bound); - delete initial_bound; - return new AST::TraitObjectTypeOneBound(::std::move(value_bound), has_dyn); + // DEBUG: removed as unique ptr, so should auto delete + // delete initial_bound; + + return ::std::unique_ptr<AST::TraitObjectTypeOneBound>( + new AST::TraitObjectTypeOneBound( + ::std::move(value_bound), t->get_locus(), has_dyn)); } // parse additional type param bounds ::std::vector< ::std::unique_ptr<AST::TypeParamBound> > bounds; - bounds.push_back(::std::unique_ptr<AST::TraitBound>(initial_bound)); + bounds.push_back(::std::move(initial_bound)); while (t->get_id() == PLUS) { lexer.skip_token(); // parse bound if it exists - AST::TypeParamBound* bound = parse_type_param_bound(); + ::std::unique_ptr<AST::TypeParamBound> bound = parse_type_param_bound(); if (bound == NULL) { // not an error as trailing plus may exist break; } - bounds.push_back(::std::unique_ptr<AST::TypeParamBound>(bound)); + bounds.push_back(::std::move(bound)); t = lexer.peek_token(); } - return new AST::TraitObjectType(::std::move(bounds), has_dyn); + return ::std::unique_ptr<AST::TraitObjectType>( + new AST::TraitObjectType(::std::move(bounds), t->get_locus(), has_dyn)); } } default: error_at( - t->get_locus(), "unrecognised token in type '%s'", t->get_token_description()); + t->get_locus(), "unrecognised token '%s' in type", t->get_token_description()); return NULL; } } /* Parses a type that has '(' as its first character. Returns a tuple type, parenthesised type, * TraitObjectTypeOneBound, or TraitObjectType depending on following characters. */ - AST::Type* Parser::parse_paren_prefixed_type() { + ::std::unique_ptr<AST::Type> Parser::parse_paren_prefixed_type() { /* NOTE: Syntactical ambiguity of a parenthesised trait bound is considered a trait bound, * not a parenthesised type, so that it can still be used in type param bounds. */ @@ -6454,6 +7155,7 @@ namespace Rust { * essentially breaking polymorphism and downcasting via virtual method abuse, as it was * copied from the rustc implementation (in which types are reified due to tagged union), * after a more OOP attempt by me failed. */ + location_t left_delim_locus = lexer.peek_token()->get_locus(); // skip left delim lexer.skip_token(); @@ -6464,13 +7166,13 @@ namespace Rust { ::std::vector< ::std::unique_ptr<AST::Type> > types; while (t->get_id() != RIGHT_PAREN) { - AST::Type* type = parse_type(); + ::std::unique_ptr<AST::Type> type = parse_type(); if (type == NULL) { error_at(t->get_locus(), "failed to parse type inside parentheses (probably tuple or parenthesised)"); return NULL; } - types.push_back(::std::unique_ptr<AST::Type>(type)); + types.push_back(::std::move(type)); t = lexer.peek_token(); if (t->get_id() != COMMA) { @@ -6503,44 +7205,55 @@ namespace Rust { return NULL; } bounds.push_back(::std::unique_ptr<AST::TraitBound>(converted_bound)); + // FIXME: possibly issues wrt memory here t = lexer.peek_token(); while (t->get_id() == PLUS) { lexer.skip_token(); // attempt to parse typeparambound - AST::TypeParamBound* bound = parse_type_param_bound(); + ::std::unique_ptr<AST::TypeParamBound> bound = parse_type_param_bound(); if (bound == NULL) { // not an error if null break; } - bounds.push_back(::std::unique_ptr<AST::TypeParamBound>(bound)); + bounds.push_back(::std::move(bound)); t = lexer.peek_token(); } - return new AST::TraitObjectType(::std::move(bounds)); + return ::std::unique_ptr<AST::TraitObjectType>( + new AST::TraitObjectType(::std::move(bounds), left_delim_locus)); } else { // release vector pointer - AST::Type* released_ptr = types[0].release(); + ::std::unique_ptr<AST::Type> released_ptr(types[0].release()); // HACK: attempt to convert to trait bound. if fails, parenthesised type - AST::TraitBound* converted_bound = released_ptr->to_trait_bound(true); + ::std::unique_ptr<AST::TraitBound> converted_bound( + released_ptr->to_trait_bound(true)); if (converted_bound == NULL) { // parenthesised type - return new AST::ParenthesisedType(released_ptr); + return ::std::unique_ptr<AST::ParenthesisedType>( + new AST::ParenthesisedType(::std::move(released_ptr), left_delim_locus)); } else { // trait object type (one bound) - delete released_ptr; + + // DEBUG: removed as unique_ptr should auto-delete + // delete released_ptr; // get value semantics trait bound AST::TraitBound value_bound(*converted_bound); - delete converted_bound; - return new AST::TraitObjectTypeOneBound(value_bound); + // DEBUG: removed as unique ptr should auto-delete + // delete converted_bound; + + return ::std::unique_ptr<AST::TraitObjectTypeOneBound>( + new AST::TraitObjectTypeOneBound(value_bound, left_delim_locus)); } + // FIXME: may be issues wrt memory here } } else { - return new AST::TupleType(::std::move(types)); + return ::std::unique_ptr<AST::TupleType>( + new AST::TupleType(::std::move(types), left_delim_locus)); } // TODO: ensure that this ensures that dynamic dispatch for traits is not lost somehow } @@ -6548,7 +7261,8 @@ namespace Rust { /* Parses a type that has 'for' as its first character. This means it has a "for lifetimes", so * returns either a BareFunctionType, TraitObjectType, or TraitObjectTypeOneBound depending on * following characters. */ - AST::Type* Parser::parse_for_prefixed_type() { + ::std::unique_ptr<AST::Type> Parser::parse_for_prefixed_type() { + location_t for_locus = lexer.peek_token()->get_locus(); // parse for lifetimes in type ::std::vector<AST::LifetimeParam> for_lifetimes = parse_for_lifetimes(); @@ -6578,33 +7292,35 @@ namespace Rust { // must be one-bound trait type // create trait bound value object AST::TraitBound bound( - ::std::move(path), false, false, ::std::move(for_lifetimes)); + ::std::move(path), for_locus, false, false, ::std::move(for_lifetimes)); - return new AST::TraitObjectTypeOneBound(::std::move(bound)); + return ::std::unique_ptr<AST::TraitObjectTypeOneBound>( + new AST::TraitObjectTypeOneBound(::std::move(bound), for_locus)); } // more than one bound trait type (or at least parsed as it - could be trailing '+') // create trait bound pointer and bounds - AST::TraitBound* initial_bound - = new AST::TraitBound(::std::move(path), false, false, ::std::move(for_lifetimes)); + ::std::unique_ptr<AST::TraitBound> initial_bound(new AST::TraitBound( + ::std::move(path), for_locus, false, false, ::std::move(for_lifetimes))); ::std::vector< ::std::unique_ptr<AST::TypeParamBound> > bounds; - bounds.push_back(::std::unique_ptr<AST::TraitBound>(initial_bound)); + bounds.push_back(::std::move(initial_bound)); while (t->get_id() == PLUS) { lexer.skip_token(); // parse type param bound if it exists - AST::TypeParamBound* bound = parse_type_param_bound(); + ::std::unique_ptr<AST::TypeParamBound> bound = parse_type_param_bound(); if (bound == NULL) { // not an error - e.g. trailing plus return NULL; } - bounds.push_back(::std::unique_ptr<AST::TypeParamBound>(bound)); + bounds.push_back(::std::move(bound)); t = lexer.peek_token(); } - return new AST::TraitObjectType(::std::move(bounds)); + return ::std::unique_ptr<AST::TraitObjectType>( + new AST::TraitObjectType(::std::move(bounds), for_locus)); } default: // error @@ -6641,19 +7357,22 @@ namespace Rust { } // parse type (required) - AST::Type* type = parse_type(); + ::std::unique_ptr<AST::Type> type = parse_type(); if (type == NULL) { error_at(lexer.peek_token()->get_locus(), "failed to parse type in maybe named param"); return AST::MaybeNamedParam::create_error(); } - return AST::MaybeNamedParam(::std::move(name), kind, type); + return AST::MaybeNamedParam(::std::move(name), kind, ::std::move(type), current->get_locus()); } /* Parses a bare function type (with the given for lifetimes for convenience - does not parse them * itself). */ - AST::BareFunctionType* Parser::parse_bare_function_type( + ::std::unique_ptr<AST::BareFunctionType> Parser::parse_bare_function_type( ::std::vector<AST::LifetimeParam> for_lifetimes) { + // TODO: pass in for lifetime location as param + location_t best_try_locus = lexer.peek_token()->get_locus(); + AST::FunctionQualifiers qualifiers = parse_function_qualifiers(); if (!skip_token(FN_TOK)) { @@ -6703,7 +7422,7 @@ namespace Rust { } // bare function return type, if exists - AST::TypeNoBounds* return_type = NULL; + ::std::unique_ptr<AST::TypeNoBounds> return_type = NULL; if (lexer.peek_token()->get_id() == RETURN_TYPE) { lexer.skip_token(); @@ -6716,12 +7435,14 @@ namespace Rust { } } - return new AST::BareFunctionType(::std::move(for_lifetimes), ::std::move(qualifiers), - ::std::move(params), is_variadic, return_type); + return ::std::unique_ptr<AST::BareFunctionType>( + new AST::BareFunctionType(::std::move(for_lifetimes), ::std::move(qualifiers), + ::std::move(params), is_variadic, ::std::move(return_type), best_try_locus)); } // Parses a reference type (mutable or immutable, with given lifetime). - AST::ReferenceType* Parser::parse_reference_type() { + ::std::unique_ptr<AST::ReferenceType> Parser::parse_reference_type() { + location_t locus = lexer.peek_token()->get_locus(); skip_token(AMP); // parse optional lifetime @@ -6742,18 +7463,20 @@ namespace Rust { } // parse type no bounds, which is required - AST::TypeNoBounds* type = parse_type_no_bounds(); + ::std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds(); if (type == NULL) { error_at( lexer.peek_token()->get_id(), "failed to parse referenced type in reference type"); return NULL; } - return new AST::ReferenceType(is_mut, type, ::std::move(lifetime)); + return ::std::unique_ptr<AST::ReferenceType>( + new AST::ReferenceType(is_mut, ::std::move(type), locus, ::std::move(lifetime))); } // Parses a raw (unsafe) pointer type. - AST::RawPointerType* Parser::parse_raw_pointer_type() { + ::std::unique_ptr<AST::RawPointerType> Parser::parse_raw_pointer_type() { + location_t locus = lexer.peek_token()->get_locus(); skip_token(ASTERISK); AST::RawPointerType::PointerType kind = AST::RawPointerType::CONST; @@ -6776,22 +7499,24 @@ namespace Rust { } // parse type no bounds (required) - AST::TypeNoBounds* type = parse_type_no_bounds(); + ::std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds(); if (type == NULL) { error_at( lexer.peek_token()->get_locus(), "failed to parse pointed type of raw pointer type"); return NULL; } - return new AST::RawPointerType(kind, type); + return ::std::unique_ptr<AST::RawPointerType>( + new AST::RawPointerType(kind, ::std::move(type), locus)); } // Parses a slice or array type, depending on following arguments (as lookahead is not possible). - AST::TypeNoBounds* Parser::parse_slice_or_array_type() { + ::std::unique_ptr<AST::TypeNoBounds> Parser::parse_slice_or_array_type() { + location_t locus = lexer.peek_token()->get_locus(); skip_token(LEFT_SQUARE); // parse inner type (required) - AST::Type* inner_type = parse_type(); + ::std::unique_ptr<AST::Type> inner_type = parse_type(); if (inner_type == NULL) { error_at( lexer.peek_token()->get_locus(), "failed to parse inner type in slice or array type"); @@ -6805,13 +7530,14 @@ namespace Rust { // slice type lexer.skip_token(); - return new AST::SliceType(inner_type); + return ::std::unique_ptr<AST::SliceType>( + new AST::SliceType(::std::move(inner_type), locus)); case SEMICOLON: { // array type lexer.skip_token(); // parse required array size expression - AST::Expr* size = parse_expr(); + ::std::unique_ptr<AST::Expr> size = parse_expr(); if (size == NULL) { error_at(lexer.peek_token()->get_locus(), "failed to parse size expression in array type"); @@ -6822,7 +7548,8 @@ namespace Rust { return NULL; } - return new AST::ArrayType(inner_type, size); + return ::std::unique_ptr<AST::ArrayType>( + new AST::ArrayType(::std::move(inner_type), ::std::move(size), locus)); } default: // error @@ -6834,13 +7561,13 @@ namespace Rust { } // Parses a type, taking into account type boundary disambiguation. - AST::TypeNoBounds* Parser::parse_type_no_bounds() { + ::std::unique_ptr<AST::TypeNoBounds> Parser::parse_type_no_bounds() { const_TokenPtr t = lexer.peek_token(); switch (t->get_id()) { case EXCLAM: // never type - can't be macro as no path beforehand lexer.skip_token(); - return new AST::NeverType(); + return ::std::unique_ptr<AST::NeverType>(new AST::NeverType(t->get_locus())); case LEFT_SQUARE: // slice type or array type - requires further disambiguation return parse_slice_or_array_type(); @@ -6851,12 +7578,13 @@ namespace Rust { error_at(t->get_locus(), "failed to parse qualified path in type"); return NULL; } - return new AST::QualifiedPathInType(::std::move(path)); + return ::std::unique_ptr<AST::QualifiedPathInType>( + new AST::QualifiedPathInType(::std::move(path))); } case UNDERSCORE: // inferred type lexer.skip_token(); - return new AST::InferredType(); + return ::std::unique_ptr<AST::InferredType>(new AST::InferredType(t->get_locus())); case ASTERISK: // raw pointer type return parse_raw_pointer_type(); @@ -6892,6 +7620,7 @@ namespace Rust { t->get_locus(), "failed to parse path as first component of type no bounds"); return NULL; } + location_t locus = path.get_locus(); // branch on next token t = lexer.peek_token(); @@ -6910,8 +7639,9 @@ namespace Rust { AST::DelimTokenTree tok_tree = parse_delim_token_tree(); - return new AST::MacroInvocation(::std::move(macro_path), - ::std::move(tok_tree), ::std::vector<AST::Attribute>()); + return ::std::unique_ptr<AST::MacroInvocation>( + new AST::MacroInvocation(::std::move(macro_path), ::std::move(tok_tree), + ::std::vector<AST::Attribute>(), locus)); } case PLUS: { // type param bounds - not allowed, here for error message @@ -6921,12 +7651,12 @@ namespace Rust { } default: // assume that this is a type path and not an error - return new AST::TypePath(::std::move(path)); + return ::std::unique_ptr<AST::TypePath>(new AST::TypePath(::std::move(path))); } } case LEFT_PAREN: // tuple type or parenthesised type - requires further disambiguation (the usual) - // ok apparently can be a parenthesised TraitBound too, so could be + // ok apparently can be a parenthesised TraitBound too, so could be // TraitObjectTypeOneBound return parse_paren_prefixed_type_no_bounds(); case FOR: @@ -6948,13 +7678,15 @@ namespace Rust { return NULL; } else { // should be trait bound, so parse trait bound - AST::TraitBound* initial_bound = parse_trait_bound(); + ::std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound(); if (initial_bound == NULL) { error_at(lexer.peek_token()->get_locus(), "failed to parse ImplTraitTypeOneBound bound"); return NULL; } + location_t locus = t->get_locus(); + // ensure not a trait with multiple bounds t = lexer.peek_token(); if (t->get_id() == PLUS) { @@ -6965,9 +7697,12 @@ namespace Rust { // convert trait bound to value object AST::TraitBound value_bound(*initial_bound); - delete initial_bound; - return new AST::ImplTraitTypeOneBound(::std::move(value_bound)); + // DEBUG: removed as unique ptr so should auto-delete + // delete initial_bound; + + return ::std::unique_ptr<AST::ImplTraitTypeOneBound>( + new AST::ImplTraitTypeOneBound(::std::move(value_bound), locus)); } case DYN: case QUESTION_MARK: { @@ -6987,13 +7722,15 @@ namespace Rust { } // should be trait bound, so parse trait bound - AST::TraitBound* initial_bound = parse_trait_bound(); + ::std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound(); if (initial_bound == NULL) { error_at(lexer.peek_token()->get_locus(), "failed to parse TraitObjectTypeOneBound initial bound"); return NULL; } + location_t locus = t->get_locus(); + // detect error with plus as next token t = lexer.peek_token(); if (t->get_id() == PLUS) { @@ -7004,9 +7741,12 @@ namespace Rust { // convert trait bound to value object AST::TraitBound value_bound(*initial_bound); - delete initial_bound; - return new AST::TraitObjectTypeOneBound(::std::move(value_bound), has_dyn); + // DEBUG: removed as unique ptr so should auto delete + // delete initial_bound; + + return ::std::unique_ptr<AST::TraitObjectTypeOneBound>( + new AST::TraitObjectTypeOneBound(::std::move(value_bound), locus, has_dyn)); } default: error_at(t->get_locus(), "unrecognised token '%s' in type no bounds", @@ -7016,12 +7756,14 @@ namespace Rust { } // Parses a type no bounds beginning with '('. - AST::TypeNoBounds* Parser::parse_paren_prefixed_type_no_bounds() { - /* NOTE: this could probably be parsed without the HACK solution of parse_paren_prefixed_type, but - * I was lazy. So FIXME for future.*/ - - /* NOTE: again, syntactical ambiguity of a parenthesised trait bound is considered a trait bound, - * not a parenthesised type, so that it can still be used in type param bounds. */ + ::std::unique_ptr<AST::TypeNoBounds> Parser::parse_paren_prefixed_type_no_bounds() { + /* NOTE: this could probably be parsed without the HACK solution of parse_paren_prefixed_type, + * but I was lazy. So FIXME for future.*/ + + /* NOTE: again, syntactical ambiguity of a parenthesised trait bound is considered a trait + * bound, not a parenthesised type, so that it can still be used in type param bounds. */ + + location_t left_paren_locus = lexer.peek_token()->get_locus(); // skip left delim lexer.skip_token(); @@ -7032,13 +7774,13 @@ namespace Rust { ::std::vector< ::std::unique_ptr<AST::Type> > types; while (t->get_id() != RIGHT_PAREN) { - AST::Type* type = parse_type(); + ::std::unique_ptr<AST::Type> type = parse_type(); if (type == NULL) { error_at(t->get_locus(), "failed to parse type inside parentheses (probably tuple or parenthesised)"); return NULL; } - types.push_back(::std::unique_ptr<AST::Type>(type)); + types.push_back(::std::move(type)); t = lexer.peek_token(); if (t->get_id() != COMMA) { @@ -7059,36 +7801,46 @@ namespace Rust { // must be a TraitObjectType (with more than one bound) if (lexer.peek_token()->get_id() == PLUS) { // error - this is not allowed for type no bounds - error_at(lexer.peek_token()->get_id(), "plus (implying TraitObjectType as type param bounds) is not allowed in type no bounds"); + error_at(lexer.peek_token()->get_id(), "plus (implying TraitObjectType as type param " + "bounds) is not allowed in type no bounds"); return NULL; } else { // release vector pointer - AST::Type* released_ptr = types[0].release(); + ::std::unique_ptr<AST::Type> released_ptr(types[0].release()); // HACK: attempt to convert to trait bound. if fails, parenthesised type - AST::TraitBound* converted_bound = released_ptr->to_trait_bound(true); + ::std::unique_ptr<AST::TraitBound> converted_bound( + released_ptr->to_trait_bound(true)); if (converted_bound == NULL) { // parenthesised type - return new AST::ParenthesisedType(released_ptr); + return ::std::unique_ptr<AST::ParenthesisedType>( + new AST::ParenthesisedType(::std::move(released_ptr), left_paren_locus)); } else { // trait object type (one bound) - delete released_ptr; + + // DEBUG: removed as unique_ptr should auto-delete + // delete released_ptr; // get value semantics trait bound AST::TraitBound value_bound(*converted_bound); - delete converted_bound; - return new AST::TraitObjectTypeOneBound(value_bound); + // DEBUG: removed as unique_ptr should auto-delete + // delete converted_bound; + + return ::std::unique_ptr<AST::TraitObjectTypeOneBound>( + new AST::TraitObjectTypeOneBound(value_bound, left_paren_locus)); } + // FIXME: memory safety issues here } } else { - return new AST::TupleType(::std::move(types)); + return ::std::unique_ptr<AST::TupleType>( + new AST::TupleType(::std::move(types), left_paren_locus)); } // TODO: ensure that this ensures that dynamic dispatch for traits is not lost somehow } /* Parses a literal pattern or range pattern. Assumes that literals passed in are valid range * pattern bounds. Do not pass in paths in expressions, for instance. */ - AST::Pattern* Parser::parse_literal_or_range_pattern() { + ::std::unique_ptr<AST::Pattern> Parser::parse_literal_or_range_pattern() { const_TokenPtr range_lower = lexer.peek_token(); AST::Literal::LitType type = AST::Literal::STRING; bool has_minus = false; @@ -7145,58 +7897,69 @@ namespace Rust { if (next->get_id() == DOT_DOT_EQ || next->get_id() == ELLIPSIS) { // range pattern lexer.skip_token(); - AST::RangePatternBound* lower = new AST::RangePatternBoundLiteral( - AST::Literal(range_lower->get_str(), type), has_minus); + ::std::unique_ptr<AST::RangePatternBound> lower(new AST::RangePatternBoundLiteral( + AST::Literal(range_lower->get_str(), type), range_lower->get_locus(), has_minus)); - AST::RangePatternBound* upper = parse_range_pattern_bound(); + ::std::unique_ptr<AST::RangePatternBound> upper = parse_range_pattern_bound(); if (upper == NULL) { error_at(next->get_locus(), "failed to parse range pattern bound in range pattern"); return NULL; } - return new AST::RangePattern(lower, upper); + return ::std::unique_ptr<AST::RangePattern>(new AST::RangePattern( + ::std::move(lower), ::std::move(upper), range_lower->get_locus())); } else { // literal pattern - return new AST::LiteralPattern(range_lower->get_str(), type, has_minus); + return ::std::unique_ptr<AST::LiteralPattern>(new AST::LiteralPattern( + range_lower->get_str(), type, range_lower->get_locus(), has_minus)); } } // Parses a range pattern bound (value only). - AST::RangePatternBound* Parser::parse_range_pattern_bound() { + ::std::unique_ptr<AST::RangePatternBound> Parser::parse_range_pattern_bound() { const_TokenPtr range_lower = lexer.peek_token(); + location_t range_lower_locus = range_lower->get_locus(); // get lit type switch (range_lower->get_id()) { case CHAR_LITERAL: lexer.skip_token(); - return new AST::RangePatternBoundLiteral( - AST::Literal(range_lower->get_str(), AST::Literal::CHAR)); + return ::std::unique_ptr<AST::RangePatternBoundLiteral>( + new AST::RangePatternBoundLiteral( + AST::Literal(range_lower->get_str(), AST::Literal::CHAR), range_lower_locus)); case BYTE_CHAR_LITERAL: lexer.skip_token(); - return new AST::RangePatternBoundLiteral( - AST::Literal(range_lower->get_str(), AST::Literal::BYTE)); + return ::std::unique_ptr<AST::RangePatternBoundLiteral>( + new AST::RangePatternBoundLiteral( + AST::Literal(range_lower->get_str(), AST::Literal::BYTE), range_lower_locus)); case INT_LITERAL: lexer.skip_token(); - return new AST::RangePatternBoundLiteral( - AST::Literal(range_lower->get_str(), AST::Literal::INT)); + return ::std::unique_ptr<AST::RangePatternBoundLiteral>( + new AST::RangePatternBoundLiteral( + AST::Literal(range_lower->get_str(), AST::Literal::INT), range_lower_locus)); case FLOAT_LITERAL: lexer.skip_token(); fprintf(stderr, "warning: used deprecated float range pattern bound"); - return new AST::RangePatternBoundLiteral( - AST::Literal(range_lower->get_str(), AST::Literal::FLOAT)); + return ::std::unique_ptr<AST::RangePatternBoundLiteral>( + new AST::RangePatternBoundLiteral( + AST::Literal(range_lower->get_str(), AST::Literal::FLOAT), range_lower_locus)); case MINUS: // branch on next token range_lower = lexer.peek_token(1); switch (range_lower->get_id()) { case INT_LITERAL: lexer.skip_token(1); - return new AST::RangePatternBoundLiteral( - AST::Literal(range_lower->get_str(), AST::Literal::INT), true); + return ::std::unique_ptr<AST::RangePatternBoundLiteral>( + new AST::RangePatternBoundLiteral( + AST::Literal(range_lower->get_str(), AST::Literal::INT), + range_lower_locus, true)); case FLOAT_LITERAL: lexer.skip_token(1); fprintf(stderr, "warning: used deprecated float range pattern bound"); - return new AST::RangePatternBoundLiteral( - AST::Literal(range_lower->get_str(), AST::Literal::FLOAT), true); + return ::std::unique_ptr<AST::RangePatternBoundLiteral>( + new AST::RangePatternBoundLiteral( + AST::Literal(range_lower->get_str(), AST::Literal::FLOAT), + range_lower_locus, true)); default: error_at(range_lower->get_locus(), "token type '%s' cannot be parsed as range pattern bound after minus " @@ -7218,7 +7981,8 @@ namespace Rust { "failed to parse path in expression range pattern bound"); return NULL; } - return new AST::RangePatternBoundPath(::std::move(path)); + return ::std::unique_ptr<AST::RangePatternBoundPath>( + new AST::RangePatternBoundPath(::std::move(path))); } case LEFT_ANGLE: { // qualified path in expression @@ -7228,7 +7992,8 @@ namespace Rust { "failed to parse qualified path in expression range pattern bound"); return NULL; } - return new AST::RangePatternBoundQualPath(::std::move(path)); + return ::std::unique_ptr<AST::RangePatternBoundQualPath>( + new AST::RangePatternBoundQualPath(::std::move(path))); } default: error_at(range_lower->get_locus(), @@ -7239,15 +8004,17 @@ namespace Rust { } // Parses a pattern (will further disambiguate any pattern). - AST::Pattern* Parser::parse_pattern() { + ::std::unique_ptr<AST::Pattern> Parser::parse_pattern() { const_TokenPtr t = lexer.peek_token(); switch (t->get_id()) { case TRUE_LITERAL: lexer.skip_token(); - return new AST::LiteralPattern("true", AST::Literal::BOOL); + return ::std::unique_ptr<AST::LiteralPattern>( + new AST::LiteralPattern("true", AST::Literal::BOOL, t->get_locus())); case FALSE_LITERAL: lexer.skip_token(); - return new AST::LiteralPattern("false", AST::Literal::BOOL); + return ::std::unique_ptr<AST::LiteralPattern>( + new AST::LiteralPattern("false", AST::Literal::BOOL, t->get_locus())); case CHAR_LITERAL: case BYTE_CHAR_LITERAL: case INT_LITERAL: @@ -7255,10 +8022,12 @@ namespace Rust { return parse_literal_or_range_pattern(); case STRING_LITERAL: lexer.skip_token(); - return new AST::LiteralPattern(t->get_str(), AST::Literal::STRING); + return ::std::unique_ptr<AST::LiteralPattern>( + new AST::LiteralPattern(t->get_str(), AST::Literal::STRING, t->get_locus())); case BYTE_STRING_LITERAL: lexer.skip_token(); - return new AST::LiteralPattern(t->get_str(), AST::Literal::BYTE_STRING); + return ::std::unique_ptr<AST::LiteralPattern>( + new AST::LiteralPattern(t->get_str(), AST::Literal::BYTE_STRING, t->get_locus())); // raw string and raw byte string literals too if they are readded to lexer case MINUS: if (lexer.peek_token(1)->get_id() == INT_LITERAL) { @@ -7272,7 +8041,8 @@ namespace Rust { } case UNDERSCORE: lexer.skip_token(); - return new AST::WildcardPattern(); + return ::std::unique_ptr<AST::WildcardPattern>( + new AST::WildcardPattern(t->get_locus())); case REF: case MUT: return parse_identifier_pattern(); @@ -7301,14 +8071,18 @@ namespace Rust { bool has_ellipsis_syntax = lexer.peek_token()->get_id() == ELLIPSIS; lexer.skip_token(); - AST::RangePatternBoundQualPath* lower_bound - = new AST::RangePatternBoundQualPath(::std::move(path)); - AST::RangePatternBound* upper_bound = parse_range_pattern_bound(); + ::std::unique_ptr<AST::RangePatternBoundQualPath> lower_bound( + new AST::RangePatternBoundQualPath(::std::move(path))); + ::std::unique_ptr<AST::RangePatternBound> upper_bound + = parse_range_pattern_bound(); - return new AST::RangePattern(lower_bound, upper_bound, has_ellipsis_syntax); + return ::std::unique_ptr<AST::RangePattern>( + new AST::RangePattern(::std::move(lower_bound), ::std::move(upper_bound), + t->get_locus(), has_ellipsis_syntax)); } else { // just qualified path in expression - return new AST::QualifiedPathInExpression(::std::move(path)); + return ::std::unique_ptr<AST::QualifiedPathInExpression>( + new AST::QualifiedPathInExpression(::std::move(path))); } } case SUPER: @@ -7328,35 +8102,23 @@ namespace Rust { bool has_ellipsis_syntax = lexer.peek_token()->get_id() == ELLIPSIS; lexer.skip_token(); - AST::RangePatternBoundPath* lower_bound - = new AST::RangePatternBoundPath(::std::move(path)); - AST::RangePatternBound* upper_bound = parse_range_pattern_bound(); - - return new AST::RangePattern(lower_bound, upper_bound, has_ellipsis_syntax); - } - case EXCLAM: { - // macro invocation - lexer.skip_token(); - - // convert PathInExpression to SimplePath - if this isn't possible, error - AST::SimplePath converted_path = path.as_simple_path(); - if (converted_path.is_empty()) { - error_at( - t->get_locus(), "failed to parse simple path to macro invocation"); - return NULL; - } - - AST::DelimTokenTree tok_tree = parse_delim_token_tree(); + ::std::unique_ptr<AST::RangePatternBoundPath> lower_bound( + new AST::RangePatternBoundPath(::std::move(path))); + ::std::unique_ptr<AST::RangePatternBound> upper_bound + = parse_range_pattern_bound(); - return new AST::MacroInvocation(::std::move(converted_path), - ::std::move(tok_tree), ::std::vector<AST::Attribute>()); + return ::std::unique_ptr<AST::RangePattern>(new AST::RangePattern( + ::std::move(lower_bound), ::std::move(upper_bound), has_ellipsis_syntax)); } + case EXCLAM: + return parse_macro_invocation_partial( + ::std::move(path), ::std::vector<AST::Attribute>()); case LEFT_PAREN: { // tuple struct lexer.skip_token(); // parse items - AST::TupleStructItems* items = parse_tuple_struct_items(); + ::std::unique_ptr<AST::TupleStructItems> items = parse_tuple_struct_items(); if (items == NULL) { error_at( lexer.peek_token()->get_locus(), "failed to parse tuple struct items"); @@ -7367,7 +8129,8 @@ namespace Rust { return NULL; } - return new AST::TupleStructPattern(::std::move(path), items); + return ::std::unique_ptr<AST::TupleStructPattern>( + new AST::TupleStructPattern(::std::move(path), ::std::move(items))); } case LEFT_CURLY: { // struct @@ -7376,15 +8139,17 @@ namespace Rust { // parse elements (optional) AST::StructPatternElements elems = parse_struct_pattern_elems(); - if (!skip_token(RIGHT_PAREN)) { + if (!skip_token(RIGHT_CURLY)) { return NULL; } - return new AST::StructPattern(::std::move(path), elems); + return ::std::unique_ptr<AST::StructPattern>( + new AST::StructPattern(::std::move(path), ::std::move(elems))); } default: // assume path in expression - return new AST::PathInExpression(::std::move(path)); + return ::std::unique_ptr<AST::PathInExpression>( + new AST::PathInExpression(::std::move(path))); } } default: @@ -7395,7 +8160,7 @@ namespace Rust { } // Parses a single or double reference pattern. - AST::ReferencePattern* Parser::parse_reference_pattern() { + ::std::unique_ptr<AST::ReferencePattern> Parser::parse_reference_pattern() { // parse double or single ref bool is_double_ref = false; const_TokenPtr t = lexer.peek_token(); @@ -7422,19 +8187,21 @@ namespace Rust { } // parse pattern to get reference of (required) - AST::Pattern* pattern = parse_pattern(); + ::std::unique_ptr<AST::Pattern> pattern = parse_pattern(); if (pattern == NULL) { error_at(lexer.peek_token()->get_locus(), "failed to parse pattern in reference pattern"); // skip somewhere? return NULL; } - return new AST::ReferencePattern(pattern, is_mut, is_double_ref); + return ::std::unique_ptr<AST::ReferencePattern>( + new AST::ReferencePattern(::std::move(pattern), is_mut, is_double_ref, t->get_locus())); } /* Parses a grouped pattern or tuple pattern. Prefers grouped over tuple if only a single element * with no commas. */ - AST::Pattern* Parser::parse_grouped_or_tuple_pattern() { + ::std::unique_ptr<AST::Pattern> Parser::parse_grouped_or_tuple_pattern() { + location_t paren_locus = lexer.peek_token()->get_locus(); skip_token(LEFT_PAREN); // detect '..' token (ranged with no lower range) @@ -7454,14 +8221,14 @@ namespace Rust { } // parse pattern, which is required - AST::Pattern* pattern = parse_pattern(); + ::std::unique_ptr<AST::Pattern> pattern = parse_pattern(); if (pattern == NULL) { error_at(lexer.peek_token()->get_locus(), "failed to parse pattern inside ranged tuple pattern"); // skip somewhere? return NULL; } - patterns.push_back(::std::unique_ptr<AST::Pattern>(pattern)); + patterns.push_back(::std::move(pattern)); t = lexer.peek_token(); } @@ -7472,13 +8239,14 @@ namespace Rust { } // create ranged tuple pattern items with only upper items - AST::TuplePatternItemsRanged* items = new AST::TuplePatternItemsRanged( - ::std::vector< ::std::unique_ptr<AST::Pattern> >(), ::std::move(patterns)); - return new AST::TuplePattern(items); + ::std::unique_ptr<AST::TuplePatternItemsRanged> items(new AST::TuplePatternItemsRanged( + ::std::vector< ::std::unique_ptr<AST::Pattern> >(), ::std::move(patterns))); + return ::std::unique_ptr<AST::TuplePattern>( + new AST::TuplePattern(::std::move(items), paren_locus)); } // parse initial pattern (required) - AST::Pattern* initial_pattern = parse_pattern(); + ::std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern(); if (initial_pattern == NULL) { error_at( lexer.peek_token()->get_locus(), "failed to parse pattern in grouped or tuple pattern"); @@ -7492,24 +8260,25 @@ namespace Rust { // grouped pattern lexer.skip_token(); - return new AST::GroupedPattern(initial_pattern); + return ::std::unique_ptr<AST::GroupedPattern>( + new AST::GroupedPattern(::std::move(initial_pattern), paren_locus)); case COMMA: { // tuple pattern lexer.skip_token(); // create vector of patterns ::std::vector< ::std::unique_ptr<AST::Pattern> > patterns; - patterns.push_back(::std::unique_ptr<AST::Pattern>(initial_pattern)); + patterns.push_back(::std::move(initial_pattern)); t = lexer.peek_token(); while (t->get_id() != RIGHT_PAREN && t->get_id() != DOT_DOT) { // parse pattern (required) - AST::Pattern* pattern = parse_pattern(); + ::std::unique_ptr<AST::Pattern> pattern = parse_pattern(); if (pattern == NULL) { error_at(t->get_locus(), "failed to parse pattern in tuple pattern"); return NULL; } - patterns.push_back(::std::unique_ptr<AST::Pattern>(pattern)); + patterns.push_back(::std::move(pattern)); if (lexer.peek_token()->get_id() != COMMA) { break; @@ -7519,13 +8288,15 @@ namespace Rust { t = lexer.peek_token(); } + t = lexer.peek_token(); if (t->get_id() == RIGHT_PAREN) { // non-ranged tuple pattern lexer.skip_token(); - AST::TuplePatternItemsMultiple* items - = new AST::TuplePatternItemsMultiple(::std::move(patterns)); - return new AST::TuplePattern(items); + ::std::unique_ptr<AST::TuplePatternItemsMultiple> items( + new AST::TuplePatternItemsMultiple(::std::move(patterns))); + return ::std::unique_ptr<AST::TuplePattern>( + new AST::TuplePattern(::std::move(items), paren_locus)); } else if (t->get_id() == DOT_DOT) { // ranged tuple pattern lexer.skip_token(); @@ -7542,13 +8313,13 @@ namespace Rust { } // parse pattern (required) - AST::Pattern* pattern = parse_pattern(); + ::std::unique_ptr<AST::Pattern> pattern = parse_pattern(); if (pattern == NULL) { error_at(lexer.peek_token()->get_locus(), "failed to parse pattern in tuple pattern"); return NULL; } - upper_patterns.push_back(::std::unique_ptr<AST::Pattern>(pattern)); + upper_patterns.push_back(::std::move(pattern)); t = lexer.peek_token(); } @@ -7557,9 +8328,11 @@ namespace Rust { return NULL; } - AST::TuplePatternItemsRanged* items = new AST::TuplePatternItemsRanged( - ::std::move(patterns), ::std::move(upper_patterns)); - return new AST::TuplePattern(items); + ::std::unique_ptr<AST::TuplePatternItemsRanged> items( + new AST::TuplePatternItemsRanged( + ::std::move(patterns), ::std::move(upper_patterns))); + return ::std::unique_ptr<AST::TuplePattern>( + new AST::TuplePattern(::std::move(items), paren_locus)); } else { // some kind of error error_at(t->get_locus(), @@ -7577,11 +8350,12 @@ namespace Rust { } // Parses a slice pattern that can match arrays or slices. Parses the square brackets too. - AST::SlicePattern* Parser::parse_slice_pattern() { + ::std::unique_ptr<AST::SlicePattern> Parser::parse_slice_pattern() { + location_t square_locus = lexer.peek_token()->get_locus(); skip_token(LEFT_SQUARE); // parse initial pattern (required) - AST::Pattern* initial_pattern = parse_pattern(); + ::std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern(); if (initial_pattern == NULL) { error_at( lexer.peek_token()->get_locus(), "failed to parse initial pattern in slice pattern"); @@ -7589,7 +8363,7 @@ namespace Rust { } ::std::vector< ::std::unique_ptr<AST::Pattern> > patterns; - patterns.push_back(::std::unique_ptr<AST::Pattern>(initial_pattern)); + patterns.push_back(::std::move(initial_pattern)); const_TokenPtr t = lexer.peek_token(); while (t->get_id() == COMMA) { @@ -7601,12 +8375,12 @@ namespace Rust { } // parse pattern (required) - AST::Pattern* pattern = parse_pattern(); + ::std::unique_ptr<AST::Pattern> pattern = parse_pattern(); if (pattern == NULL) { error_at(lexer.peek_token()->get_locus(), "failed to parse pattern in slice pattern"); return NULL; } - patterns.push_back(::std::unique_ptr<AST::Pattern>(pattern)); + patterns.push_back(::std::move(pattern)); t = lexer.peek_token(); } @@ -7615,15 +8389,21 @@ namespace Rust { return NULL; } - return new AST::SlicePattern(::std::move(patterns)); + return ::std::unique_ptr<AST::SlicePattern>( + new AST::SlicePattern(::std::move(patterns), square_locus)); } // Parses an identifier pattern (pattern that binds a value matched to a variable). - AST::IdentifierPattern* Parser::parse_identifier_pattern() { + ::std::unique_ptr<AST::IdentifierPattern> Parser::parse_identifier_pattern() { + location_t locus = lexer.peek_token()->get_locus(); + bool has_ref = false; if (lexer.peek_token()->get_id() == REF) { has_ref = true; lexer.skip_token(); + + // DEBUG + fprintf(stderr, "parsed ref in identifier pattern\n"); } bool has_mut = false; @@ -7640,8 +8420,11 @@ namespace Rust { } Identifier ident = ident_tok->get_str(); + // DEBUG + fprintf(stderr, "parsed identifier in identifier pattern\n"); + // parse optional pattern binding thing - AST::Pattern* bind_pattern = NULL; + ::std::unique_ptr<AST::Pattern> bind_pattern = NULL; if (lexer.peek_token()->get_id() == PATTERN_BIND) { lexer.skip_token(); @@ -7649,18 +8432,22 @@ namespace Rust { bind_pattern = parse_pattern(); if (bind_pattern == NULL) { error_at(lexer.peek_token()->get_locus(), - "failed to parse pattern to bind in identifier pattern"); + "failed to parse pattern to bind in identifier pattern\n"); return NULL; } } - return new AST::IdentifierPattern(::std::move(ident), has_ref, has_mut, bind_pattern); + // DEBUG + fprintf(stderr, "about to return identifier pattern\n"); + + return ::std::unique_ptr<AST::IdentifierPattern>(new AST::IdentifierPattern( + ::std::move(ident), locus, has_ref, has_mut, ::std::move(bind_pattern))); } /* Parses a pattern that opens with an identifier. This includes identifier patterns, path * patterns (and derivatives such as struct patterns, tuple struct patterns, and macro * invocations), and ranges. */ - AST::Pattern* Parser::parse_ident_leading_pattern() { + ::std::unique_ptr<AST::Pattern> Parser::parse_ident_leading_pattern() { // ensure first token is actually identifier const_TokenPtr initial_tok = lexer.peek_token(); if (initial_tok->get_id() != IDENTIFIER) { @@ -7676,38 +8463,35 @@ namespace Rust { // branch on next token const_TokenPtr t = lexer.peek_token(); switch (t->get_id()) { - case EXCLAM: { - // macro invocation - lexer.skip_token(); - - // convert PathInExpression to SimplePath - if this isn't possible, error - AST::SimplePath converted_path = path.as_simple_path(); - if (converted_path.is_empty()) { - error_at(t->get_locus(), "failed to parse simple path to macro invocation"); - return NULL; - } - - AST::DelimTokenTree tok_tree = parse_delim_token_tree(); - - return new AST::MacroInvocation(::std::move(converted_path), ::std::move(tok_tree), - ::std::vector<AST::Attribute>()); - } + case EXCLAM: + return parse_macro_invocation_partial( + ::std::move(path), ::std::vector<AST::Attribute>()); case LEFT_PAREN: { // tuple struct lexer.skip_token(); + // DEBUG + fprintf(stderr, "parsing tuple struct pattern\n"); + // parse items - AST::TupleStructItems* items = parse_tuple_struct_items(); + ::std::unique_ptr<AST::TupleStructItems> items = parse_tuple_struct_items(); if (items == NULL) { error_at(lexer.peek_token()->get_locus(), "failed to parse tuple struct items"); return NULL; } + // DEBUG + fprintf(stderr, "successfully parsed tuple struct items\n"); + if (!skip_token(RIGHT_PAREN)) { return NULL; } - return new AST::TupleStructPattern(::std::move(path), items); + // DEBUG + fprintf(stderr, "successfully parsed tuple struct pattern\n"); + + return ::std::unique_ptr<AST::TupleStructPattern>( + new AST::TupleStructPattern(::std::move(path), ::std::move(items))); } case LEFT_CURLY: { // struct @@ -7716,11 +8500,15 @@ namespace Rust { // parse elements (optional) AST::StructPatternElements elems = parse_struct_pattern_elems(); - if (!skip_token(RIGHT_PAREN)) { + if (!skip_token(RIGHT_CURLY)) { return NULL; } - return new AST::StructPattern(::std::move(path), elems); + // DEBUG + fprintf(stderr, "successfully parsed struct pattern\n"); + + return ::std::unique_ptr<AST::StructPattern>( + new AST::StructPattern(::std::move(path), ::std::move(elems))); } case DOT_DOT_EQ: case ELLIPSIS: { @@ -7729,11 +8517,12 @@ namespace Rust { lexer.skip_token(); - AST::RangePatternBoundPath* lower_bound - = new AST::RangePatternBoundPath(::std::move(path)); - AST::RangePatternBound* upper_bound = parse_range_pattern_bound(); + ::std::unique_ptr<AST::RangePatternBoundPath> lower_bound( + new AST::RangePatternBoundPath(::std::move(path))); + ::std::unique_ptr<AST::RangePatternBound> upper_bound = parse_range_pattern_bound(); - return new AST::RangePattern(lower_bound, upper_bound, has_ellipsis_syntax); + return ::std::unique_ptr<AST::RangePattern>(new AST::RangePattern( + ::std::move(lower_bound), ::std::move(upper_bound), has_ellipsis_syntax)); } case PATTERN_BIND: { // only allow on single-segment paths @@ -7741,14 +8530,15 @@ namespace Rust { // identifier with pattern bind lexer.skip_token(); - AST::Pattern* bind_pattern = parse_pattern(); + ::std::unique_ptr<AST::Pattern> bind_pattern = parse_pattern(); if (bind_pattern == NULL) { error_at( t->get_locus(), "failed to parse pattern to bind to identifier pattern"); return NULL; } - return new AST::IdentifierPattern( - ::std::move(initial_ident), false, false, bind_pattern); + return ::std::unique_ptr<AST::IdentifierPattern>( + new AST::IdentifierPattern(::std::move(initial_ident), initial_tok->get_locus(), + false, false, ::std::move(bind_pattern))); } error_at(t->get_locus(), "failed to parse pattern bind to a path, not an identifier"); return NULL; @@ -7756,22 +8546,30 @@ namespace Rust { default: // assume identifier if single segment if (path.is_single_segment()) { - return new AST::IdentifierPattern(::std::move(initial_ident)); + return ::std::unique_ptr<AST::IdentifierPattern>(new AST::IdentifierPattern( + ::std::move(initial_ident), initial_tok->get_locus())); } // return path otherwise - return new AST::PathInExpression(::std::move(path)); + return ::std::unique_ptr<AST::PathInExpression>( + new AST::PathInExpression(::std::move(path))); } } // Parses tuple struct items if they exist. Does not parse parentheses. - AST::TupleStructItems* Parser::parse_tuple_struct_items() { + ::std::unique_ptr<AST::TupleStructItems> Parser::parse_tuple_struct_items() { ::std::vector< ::std::unique_ptr<AST::Pattern> > lower_patterns; + // DEBUG + fprintf(stderr, "started parsing tuple struct items\n"); + // check for '..' at front if (lexer.peek_token()->get_id() == DOT_DOT) { // only parse upper patterns lexer.skip_token(); + // DEBUG + fprintf(stderr, "'..' at front in tuple struct items detected\n"); + ::std::vector< ::std::unique_ptr<AST::Pattern> > upper_patterns; const_TokenPtr t = lexer.peek_token(); @@ -7784,33 +8582,46 @@ namespace Rust { } // parse pattern, which is now required - AST::Pattern* pattern = parse_pattern(); + ::std::unique_ptr<AST::Pattern> pattern = parse_pattern(); if (pattern == NULL) { error_at(lexer.peek_token()->get_locus(), "failed to parse pattern in tuple struct items"); return NULL; } - upper_patterns.push_back(::std::unique_ptr<AST::Pattern>(pattern)); + upper_patterns.push_back(::std::move(pattern)); t = lexer.peek_token(); } - return new AST::TupleStructItemsRange( - ::std::move(lower_patterns), ::std::move(upper_patterns)); + // DEBUG + fprintf(stderr, "finished parsing tuple struct items ranged (upper/none only)\n"); + + return ::std::unique_ptr<AST::TupleStructItemsRange>(new AST::TupleStructItemsRange( + ::std::move(lower_patterns), ::std::move(upper_patterns))); } // has at least some lower patterns const_TokenPtr t = lexer.peek_token(); while (t->get_id() != RIGHT_PAREN && t->get_id() != DOT_DOT) { + + // DEBUG + fprintf(stderr, "about to parse pattern in tuple struct items\n"); + // parse pattern, which is required - AST::Pattern* pattern = parse_pattern(); + ::std::unique_ptr<AST::Pattern> pattern = parse_pattern(); if (pattern == NULL) { error_at(t->get_locus(), "failed to parse pattern in tuple struct items"); return NULL; } - lower_patterns.push_back(::std::unique_ptr<AST::Pattern>(pattern)); + lower_patterns.push_back(::std::move(pattern)); + + // DEBUG + fprintf(stderr, "successfully parsed pattern in tuple struct items\n"); if (lexer.peek_token()->get_id() != COMMA) { + // DEBUG + fprintf(stderr, "broke out of parsing patterns in tuple struct items as no comma \n"); + break; } lexer.skip_token(); @@ -7819,9 +8630,11 @@ namespace Rust { } // branch on next token + t = lexer.peek_token(); switch (t->get_id()) { case RIGHT_PAREN: - return new AST::TupleStructItemsNoRange(::std::move(lower_patterns)); + return ::std::unique_ptr<AST::TupleStructItemsNoRange>( + new AST::TupleStructItemsNoRange(::std::move(lower_patterns))); case DOT_DOT: { // has an upper range that must be parsed separately lexer.skip_token(); @@ -7838,19 +8651,19 @@ namespace Rust { } // parse pattern, which is required - AST::Pattern* pattern = parse_pattern(); + ::std::unique_ptr<AST::Pattern> pattern = parse_pattern(); if (pattern == NULL) { error_at(lexer.peek_token()->get_locus(), "failed to parse pattern in tuple struct items"); return NULL; } - upper_patterns.push_back(::std::unique_ptr<AST::Pattern>(pattern)); + upper_patterns.push_back(::std::move(pattern)); t = lexer.peek_token(); } - return new AST::TupleStructItemsRange( - ::std::move(lower_patterns), ::std::move(upper_patterns)); + return ::std::unique_ptr<AST::TupleStructItemsRange>(new AST::TupleStructItemsRange( + ::std::move(lower_patterns), ::std::move(upper_patterns))); } default: // error @@ -7867,14 +8680,21 @@ namespace Rust { // try parsing struct pattern fields const_TokenPtr t = lexer.peek_token(); while (t->get_id() != RIGHT_CURLY && t->get_id() != DOT_DOT) { - AST::StructPatternField* field = parse_struct_pattern_field(); + ::std::unique_ptr<AST::StructPatternField> field = parse_struct_pattern_field(); if (field == NULL) { // TODO: should this be an error? // assuming that this means that it is a struct pattern etc instead + + // DEBUG + fprintf(stderr, "failed to parse struct pattern field - breaking from loop\n"); + break; } - fields.push_back(::std::unique_ptr<AST::StructPatternField>(field)); + fields.push_back(::std::move(field)); + + // DEBUG + fprintf(stderr, "successfully pushed back a struct pattern field\n"); if (lexer.peek_token()->get_id() != COMMA) { break; @@ -7885,7 +8705,8 @@ namespace Rust { } // FIXME: this method of parsing prevents parsing any outer attributes on the .. - if (t->get_id() == DOT_DOT) { + // also there seems to be no distinction between having etc and not having etc. + if (lexer.peek_token()->get_id() == DOT_DOT) { lexer.skip_token(); // as no outer attributes @@ -7898,7 +8719,7 @@ namespace Rust { } // Parses a struct pattern field (tuple index/pattern, identifier/pattern, or identifier). - AST::StructPatternField* Parser::parse_struct_pattern_field() { + ::std::unique_ptr<AST::StructPatternField> Parser::parse_struct_pattern_field() { // parse outer attributes (if they exist) ::std::vector<AST::Attribute> outer_attrs = parse_outer_attributes(); @@ -7915,14 +8736,16 @@ namespace Rust { } // parse required pattern - AST::Pattern* pattern = parse_pattern(); + ::std::unique_ptr<AST::Pattern> pattern = parse_pattern(); if (pattern == NULL) { error_at( t->get_locus(), "failed to parse pattern in tuple index struct pattern field"); return NULL; } - return new AST::StructPatternFieldTuplePat(index, pattern, ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::StructPatternFieldTuplePat>( + new AST::StructPatternFieldTuplePat( + index, ::std::move(pattern), ::std::move(outer_attrs), t->get_locus())); } case IDENTIFIER: // identifier-pattern OR only identifier @@ -7936,15 +8759,16 @@ namespace Rust { skip_token(COLON); // parse required pattern - AST::Pattern* pattern = parse_pattern(); + ::std::unique_ptr<AST::Pattern> pattern = parse_pattern(); if (pattern == NULL) { error_at( t->get_locus(), "failed to parse pattern in struct pattern field"); return NULL; } - return new AST::StructPatternFieldIdentPat( - ::std::move(ident), pattern, ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::StructPatternFieldIdentPat>( + new AST::StructPatternFieldIdentPat(::std::move(ident), + ::std::move(pattern), ::std::move(outer_attrs), t->get_locus())); } case COMMA: case RIGHT_CURLY: { @@ -7952,8 +8776,9 @@ namespace Rust { Identifier ident = t->get_str(); lexer.skip_token(); - return new AST::StructPatternFieldIdent( - ::std::move(ident), false, false, ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::StructPatternFieldIdent>( + new AST::StructPatternFieldIdent(::std::move(ident), false, false, + ::std::move(outer_attrs), t->get_locus())); } default: // error @@ -7982,8 +8807,9 @@ namespace Rust { } Identifier ident = ident_tok->get_str(); - return new AST::StructPatternFieldIdent( - ::std::move(ident), has_ref, has_mut, ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::StructPatternFieldIdent>( + new AST::StructPatternFieldIdent( + ::std::move(ident), has_ref, has_mut, ::std::move(outer_attrs), t->get_locus())); } default: // not necessarily an error @@ -7991,142 +8817,592 @@ namespace Rust { } } - // TODO: rename to "parse_module_body"? - /*AST::Module Parser::parse_module() { - // const_TokenPtr t = lexer.peek_token(); - AST::Module module; + /* Parses a statement or expression (depending on whether a trailing semicolon exists). Useful for + * block expressions where it cannot be determined through lookahead whether it is a statement or + * expression to be parsed. */ + ExprOrStmt Parser::parse_stmt_or_expr_without_block() { + // quick exit for empty statement + const_TokenPtr t = lexer.peek_token(); + if (t->get_id() == SEMICOLON) { + lexer.skip_token(); + ::std::unique_ptr<AST::EmptyStmt> stmt(new AST::EmptyStmt(t->get_locus())); + return ExprOrStmt(::std::move(stmt)); + } - while (true) { - // check end of module - switch (lexer.peek_token()->get_id()) { - case RIGHT_CURLY: - case END_OF_FILE: - return module; - default: - break; + // parse outer attributes + ::std::vector<AST::Attribute> outer_attrs = parse_outer_attributes(); + + // parsing this will be annoying because of the many different possibilities + /* best may be just to copy paste in parse_item switch, and failing that try to parse outer + * attributes, and then pass them in to either a let statement or (fallback) expression + * statement. */ + // FIXME: think of a way to do this without such a large switch? + + /* FIXME: for expressions at least, the only way that they can really be parsed properly in + * this way is if they don't support operators on them. They must be pratt-parsed otherwise. + * As such due to composability, only explicit statements will have special cases here. This + * should roughly correspond to "expr-with-block", but this warning is here in case it isn't + * the case. */ + t = lexer.peek_token(); + switch (t->get_id()) { + case LET: { + // let statement + ::std::unique_ptr<AST::LetStmt> stmt(parse_let_stmt(::std::move(outer_attrs))); + return ExprOrStmt(::std::move(stmt)); + } + case PUB: + case MOD: + case EXTERN_TOK: + case USE: + case FN_TOK: + case TYPE: + case STRUCT_TOK: + case ENUM_TOK: + case CONST: + case STATIC_TOK: + case TRAIT: + case IMPL: { + ::std::unique_ptr<AST::VisItem> item(parse_vis_item(::std::move(outer_attrs))); + return ExprOrStmt(::std::move(item)); } + /* TODO: implement union keyword but not really because of context-dependence + * crappy hack way to parse a union written below to separate it from the good code. */ + // case UNION: + case UNSAFE: { // maybe - unsafe traits are a thing + // if any of these (should be all possible VisItem prefixes), parse a VisItem + // can't parse item because would require reparsing outer attributes + const_TokenPtr t2 = lexer.peek_token(1); + switch (t2->get_id()) { + case LEFT_CURLY: { + // unsafe block + ::std::unique_ptr<AST::ExprStmtWithBlock> stmt( + parse_expr_stmt_with_block(::std::move(outer_attrs))); + return ExprOrStmt(::std::move(stmt)); + } + case TRAIT: { + // unsafe trait + ::std::unique_ptr<AST::VisItem> item( + parse_vis_item(::std::move(outer_attrs))); + return ExprOrStmt(::std::move(item)); + } + case EXTERN_TOK: + case FN_TOK: { + // unsafe function + ::std::unique_ptr<AST::VisItem> item( + parse_vis_item(::std::move(outer_attrs))); + return ExprOrStmt(::std::move(item)); + } + case IMPL: { + // unsafe trait impl + ::std::unique_ptr<AST::VisItem> item( + parse_vis_item(::std::move(outer_attrs))); + return ExprOrStmt(::std::move(item)); + } + default: + error_at(t2->get_locus(), + "unrecognised token '%s' after parsing unsafe - expected beginning of " + "expression or statement", + t->get_token_description()); + // skip somewhere? + return ExprOrStmt::create_error(); + } + } + case SUPER: + case SELF: + case CRATE: + case DOLLAR_SIGN: { + /* path-based thing so struct/enum or path or macro invocation of a kind. however, the + * expressions are composable (i think) */ - // parse item attributes here - AST::AttributeList attrs; + ::std::unique_ptr<AST::ExprWithoutBlock> expr = parse_expr_without_block(); - parse_module_item(module, attrs); - } + if (lexer.peek_token()->get_id() == SEMICOLON) { + // must be expression statement + lexer.skip_token(); - return module; - }*/ + ::std::unique_ptr<AST::ExprStmtWithoutBlock> stmt( + new AST::ExprStmtWithoutBlock(::std::move(expr), t->get_locus())); + return ExprOrStmt(::std::move(stmt)); + } + + // return expression + return ExprOrStmt(::std::move(expr)); + } + /* FIXME: this is either a macro invocation or macro invocation semi. start parsing to + * determine which one it is. */ + // FIXME: or this is another path-based thing - struct/enum or path itself + // return parse_path_based_stmt_or_expr(::std::move(outer_attrs)); + // FIXME: old code there + case LOOP: + case WHILE: + case FOR: + case IF: + case MATCH_TOK: + case LEFT_CURLY: + case ASYNC: { + // all expressions with block, so cannot be final expr without block in function + ::std::unique_ptr<AST::ExprStmtWithBlock> stmt( + parse_expr_stmt_with_block(::std::move(outer_attrs))); + return ExprOrStmt(::std::move(stmt)); + } + case LIFETIME: { + /* FIXME: are there any expressions without blocks that can have lifetime as their + * first token? Or is loop expr the only one? */ + // safe side for now: + const_TokenPtr t2 = lexer.peek_token(2); + if (lexer.peek_token(1)->get_id() == COLON + && (t2->get_id() == LOOP || t2->get_id() == WHILE || t2->get_id() == FOR)) { + ::std::unique_ptr<AST::ExprStmtWithBlock> stmt( + parse_expr_stmt_with_block(::std::move(outer_attrs))); + return ExprOrStmt(::std::move(stmt)); + } else { + // should be expr without block + ::std::unique_ptr<AST::ExprWithoutBlock> expr = parse_expr_without_block(); + + if (lexer.peek_token()->get_id() == SEMICOLON) { + // must be expression statement + lexer.skip_token(); + + ::std::unique_ptr<AST::ExprStmtWithoutBlock> stmt( + new AST::ExprStmtWithoutBlock(::std::move(expr), t->get_locus())); + return ExprOrStmt(::std::move(stmt)); + } + + // return expression + return ExprOrStmt(::std::move(expr)); + } + } + // crappy hack to do union "keyword" + case IDENTIFIER: + // TODO: ensure std::string and literal comparison works + if (t->get_str() == "union") { + ::std::unique_ptr<AST::VisItem> item(parse_vis_item(::std::move(outer_attrs))); + return ExprOrStmt(::std::move(item)); + // or should this go straight to parsing union? + } else if (t->get_str() == "macro_rules") { + // macro_rules! macro item + ::std::unique_ptr<AST::MacroItem> item( + parse_macro_item(::std::move(outer_attrs))); + return ExprOrStmt(::std::move(item)); + } else if (lexer.peek_token(1)->get_id() == SCOPE_RESOLUTION + || lexer.peek_token(1)->get_id() == EXCLAM + || lexer.peek_token(1)->get_id() == LEFT_CURLY) { + // path (probably) or macro invocation or struct or enum, so probably a macro + // invocation semi decide how to parse - probably parse path and then get macro + // from it + + // FIXME: old code was good until composability was required + // return parse_path_based_stmt_or_expr(::std::move(outer_attrs)); + ::std::unique_ptr<AST::ExprWithoutBlock> expr = parse_expr_without_block(); + + if (lexer.peek_token()->get_id() == SEMICOLON) { + // must be expression statement + lexer.skip_token(); + + ::std::unique_ptr<AST::ExprStmtWithoutBlock> stmt( + new AST::ExprStmtWithoutBlock(::std::move(expr), t->get_locus())); + return ExprOrStmt(::std::move(stmt)); + } + + // return expression + return ExprOrStmt(::std::move(expr)); + } + gcc_fallthrough(); + // TODO: find out how to disable gcc "implicit fallthrough" warning + default: { + // expression statement (without block) or expression itself - parse expression then + // make it statement if semi afterwards + + ::std::unique_ptr<AST::ExprWithoutBlock> expr = parse_expr_without_block(); - /*void Parser::parse_module_item( - AST::Module module_for_items, AST::AttributeList item_outer_attrs) { - AST::Visibility visibility = parse_visibility(); + if (lexer.peek_token()->get_id() == SEMICOLON) { + // must be expression statement + lexer.skip_token(); + + ::std::unique_ptr<AST::ExprStmtWithoutBlock> stmt( + new AST::ExprStmtWithoutBlock(::std::move(expr), t->get_locus())); + return ExprOrStmt(::std::move(stmt)); + } + + // return expression + return ExprOrStmt(::std::move(expr)); + } + } + } - switch (lexer.peek_token()->get_id()) { - case MOD: { - // TODO: function call to eventually move all this stuff into: - // parse_module(); - // Note that this is not the current "parse_module" function. + // Parses a statement or expression beginning with a path (i.e. macro, struct/enum, or path expr) + ExprOrStmt Parser::parse_path_based_stmt_or_expr(::std::vector<AST::Attribute> outer_attrs) { + // attempt to parse path + location_t stmt_or_expr_loc = lexer.peek_token()->get_locus(); + AST::PathInExpression path = parse_path_in_expression(); + + // branch on next token + const_TokenPtr t2 = lexer.peek_token(); + switch (t2->get_id()) { + case EXCLAM: { + // macro invocation or macro invocation semi - depends on whether there is + // a final ';' convert path in expr to simple path (as that is used in + // macros) + AST::SimplePath macro_path = path.as_simple_path(); + if (macro_path.is_empty()) { + error_at(t2->get_locus(), "failed to convert parsed path to simple " + "path (for macro invocation or semi)"); + return ExprOrStmt::create_error(); + } - // skip "mod" token + // skip exclamation mark lexer.skip_token(); - // next token should be module name - const_TokenPtr identifier = expect_token(IDENTIFIER); + const_TokenPtr t3 = lexer.peek_token(); + location_t tok_tree_loc = t3->get_locus(); - switch (lexer.peek_token()->get_id()) { - case SEMICOLON: - // parse module without body - from referenced file + AST::DelimType type = AST::PARENS; + switch (t3->get_id()) { + case LEFT_PAREN: + type = AST::PARENS; + break; + case LEFT_SQUARE: + type = AST::SQUARE; + break; case LEFT_CURLY: - // parse module with body + type = AST::CURLY; + break; default: - error_at(identifier->get_locus(), - "invalid module definition syntax; unexpected token '%s'", - lexer.peek_token()->get_str().c_str()); - skip_after_end(); + error_at(t3->get_locus(), + "unrecognised token '%s' in macro invocation - (opening) " + "delimiter expected", + t3->get_token_description()); + return ExprOrStmt::create_error(); } - } break; - case USE: - // TODO: parse "use" declaration - break; - case EXTERN_TOK: - // TODO: parse "extern" statement - extern crate and extern block - break; - case FN_TOK: - // TODO: parse function declaration - break; - case STRUCT_TOK: - // TODO: parse function declaration - break; - case IMPL: - // TODO: parse struct impl - break; - // TODO: type alias? - case ENUM_TOK: - // TODO: parse enum - break; - case TRAIT: - // TODO: parse trait decl - break; - // TODO: parse "union"? This is the context-aware one, I think - // TODO: parse "constant item" - // TODO: parse "static item" - // etc: add more - all module-level allowed constructs should be represented here + lexer.skip_token(); + + // parse actual token trees + ::std::vector< ::std::unique_ptr<AST::TokenTree> > token_trees; + + t3 = lexer.peek_token(); + // parse token trees until the initial delimiter token is found again + while (!token_id_matches_delims(t3->get_id(), type)) { + ::std::unique_ptr<AST::TokenTree> tree = parse_token_tree(); + + if (tree == NULL) { + error_at(t3->get_locus(), + "failed to parse token tree for macro invocation (or semi) - " + "found " + "'%s'", + t3->get_token_description()); + return ExprOrStmt::create_error(); + } + + token_trees.push_back(::std::move(tree)); + + t3 = lexer.peek_token(); + } + + // parse end delimiters + t3 = lexer.peek_token(); + if (token_id_matches_delims(t3->get_id(), type)) { + // tokens match opening delimiter, so skip. + lexer.skip_token(); + + /* with curly bracketed macros, assume it is a macro invocation unless + * a semicolon is explicitly put at the end. this is not necessarily + * true (i.e. context-dependence) and so may have to be fixed up via + * HACKs in semantic + * analysis (by checking whether it is the last elem in the vector). + */ + + if (lexer.peek_token()->get_id() == SEMICOLON) { + lexer.skip_token(); + + ::std::unique_ptr<AST::MacroInvocationSemi> stmt( + new AST::MacroInvocationSemi(::std::move(macro_path), type, + ::std::move(token_trees), ::std::move(outer_attrs), stmt_or_expr_loc)); + return ExprOrStmt(::std::move(stmt)); + } + + // otherwise, create macro invocation + AST::DelimTokenTree delim_tok_tree(type, ::std::move(token_trees), tok_tree_loc); + + ::std::unique_ptr<AST::MacroInvocation> expr( + new AST::MacroInvocation(::std::move(macro_path), ::std::move(delim_tok_tree), + ::std::move(outer_attrs), stmt_or_expr_loc)); + return ExprOrStmt(::std::move(expr)); + } else { + // tokens don't match opening delimiters, so produce error + error_at(t2->get_locus(), + "unexpected token '%s' - expecting closing delimiter '%s' (for a " + "macro invocation)", + t2->get_token_description(), + (type == AST::PARENS ? ")" : (type == AST::SQUARE ? "]" : "}"))); + return ExprOrStmt::create_error(); + } + } + case LEFT_CURLY: { + /* definitely not a block: + * path '{' ident ',' + * path '{' ident ':' [anything] ',' + * path '{' ident ':' [not a type] + * otherwise, assume block expr and thus path */ + bool not_a_block + = lexer.peek_token(1)->get_id() == IDENTIFIER + && (lexer.peek_token(2)->get_id() == COMMA + || (lexer.peek_token(2)->get_id() == COLON + && (lexer.peek_token(4)->get_id() == COMMA + || !can_tok_start_type(lexer.peek_token(3)->get_id())))); + ::std::unique_ptr<AST::ExprWithoutBlock> expr = NULL; + + if (not_a_block) { + // assume struct expr struct (as struct-enum disambiguation requires name + // lookup) again, make statement if final ';' + expr + = parse_struct_expr_struct_partial(::std::move(path), ::std::move(outer_attrs)); + if (expr == NULL) { + error_at(t2->get_locus(), "failed to parse struct expr struct"); + return ExprOrStmt::create_error(); + } + } else { + // assume path - make statement if final ';' + // lexer.skip_token(); + + // HACK: add outer attrs to path + path.replace_outer_attrs(::std::move(outer_attrs)); + expr = ::std::unique_ptr<AST::PathInExpression>( + new AST::PathInExpression(::std::move(path))); + } + + // determine if statement if ends with semicolon + if (lexer.peek_token()->get_id() == SEMICOLON) { + // statement + lexer.skip_token(); + ::std::unique_ptr<AST::ExprStmtWithoutBlock> stmt( + new AST::ExprStmtWithoutBlock(::std::move(expr), stmt_or_expr_loc)); + return ExprOrStmt(::std::move(stmt)); + } + + // otherwise, expression + return ExprOrStmt(::std::move(expr)); + } + case LEFT_PAREN: { + // assume struct expr tuple (as struct-enum disambiguation requires name + // lookup) again, make statement if final ';' + ::std::unique_ptr<AST::StructExprTuple> struct_expr + = parse_struct_expr_tuple_partial(::std::move(path), ::std::move(outer_attrs)); + if (struct_expr == NULL) { + error_at(t2->get_locus(), "failed to parse struct expr tuple"); + return ExprOrStmt::create_error(); + } + + // determine if statement if ends with semicolon + if (lexer.peek_token()->get_id() == SEMICOLON) { + // statement + lexer.skip_token(); + ::std::unique_ptr<AST::ExprStmtWithoutBlock> stmt( + new AST::ExprStmtWithoutBlock(::std::move(struct_expr), stmt_or_expr_loc)); + return ExprOrStmt(::std::move(stmt)); + } + + // otherwise, expression + return ExprOrStmt(::std::move(struct_expr)); + } + default: { + // assume path - make statement if final ';' + // lexer.skip_token(); + + // HACK: replace outer attributes in path + path.replace_outer_attrs(::std::move(outer_attrs)); + ::std::unique_ptr<AST::PathInExpression> expr( + new AST::PathInExpression(::std::move(path))); + + if (lexer.peek_token()->get_id() == SEMICOLON) { + lexer.skip_token(); + + ::std::unique_ptr<AST::ExprStmtWithoutBlock> stmt( + new AST::ExprStmtWithoutBlock(::std::move(expr), stmt_or_expr_loc)); + return ExprOrStmt(::std::move(stmt)); + } + + return ExprOrStmt(::std::move(expr)); + } } - }*/ + } - // Parses a statement. Selects how to parse based on token id. - Tree Parser::parse_statement() { - /* - statement -> ; - | item - | let_statement - | expression_statement - | macro_invocation_semi - */ - // peek current token - const_TokenPtr t = lexer.peek_token(); + // Parses a struct expression field. + ::std::unique_ptr<AST::StructExprField> Parser::parse_struct_expr_field() { + // DEBUG: + fprintf(stderr, "beginning struct/enum expr field parsing \n"); - // call method to parse statement if recognised + const_TokenPtr t = lexer.peek_token(); switch (t->get_id()) { - // is item declaration only for nested functions? - case FN_TOK: - // TODO: fix - rust reference gives nested function as an example? - // return parse_item_declaration(); - break; - /*case VAR: - return parse_variable_declaration(); - break;*/ - case LET: - // return parse_let_statement(); - break; - // parse expression statement somehow? any expression with ending semicolon - /*case TYPE: - return parse_type_declaration(); - break;*/ - /*case IF: - return parse_if_statement(); + case IDENTIFIER: + if (lexer.peek_token(1)->get_id() == COLON) { + // struct expr field with identifier and expr + Identifier ident = t->get_str(); + lexer.skip_token(1); + + // parse expression (required) + ::std::unique_ptr<AST::Expr> expr = parse_expr(); + if (expr == NULL) { + error_at(t->get_locus(), + "failed to parse struct expression field with identifier and expression"); + return NULL; + } + + // DEBUG: + fprintf(stderr, "struct/enum expr field parsing field identifier value done \n"); + + return ::std::unique_ptr<AST::StructExprFieldIdentifierValue>( + new AST::StructExprFieldIdentifierValue(::std::move(ident), ::std::move(expr))); + } else { + // struct expr field with identifier only + Identifier ident = t->get_str(); + lexer.skip_token(); + + // DEBUG: + fprintf(stderr, "struct/enum expr field parsing field identifier done \n"); + + return ::std::unique_ptr<AST::StructExprFieldIdentifier>( + new AST::StructExprFieldIdentifier(::std::move(ident))); + } + case INT_LITERAL: { + // parse tuple index field + int index = atoi(t->get_str().c_str()); + lexer.skip_token(); + + if (!skip_token(COLON)) { + // skip somewhere? + return NULL; + } + + // parse field expression (required) + ::std::unique_ptr<AST::Expr> expr = parse_expr(); + if (expr == NULL) { + error_at(t->get_locus(), + "failed to parse expr in struct (or enum) expr field with tuple index"); + return NULL; + } + + // DEBUG: + fprintf(stderr, "struct/enum expr field parsing field index value done \n"); + + return ::std::unique_ptr<AST::StructExprFieldIndexValue>( + new AST::StructExprFieldIndexValue(index, ::std::move(expr))); + } + case DOT_DOT: + // this is a struct base and can't be parsed here, so just return nothing without + // erroring + + // DEBUG: + fprintf(stderr, "struct/enum expr field parsing failed - '..' \n"); + + return NULL; + default: + // DEBUG: + fprintf(stderr, "struct/enum expr field parsing failed - unrecognised char \n"); + + error_at(t->get_locus(), + "unrecognised token '%s' as first token of struct expr field - expected identifier " + "or int literal", + t->get_token_description()); + return NULL; + } + } + + // Parses a macro invocation or macro invocation semi. + ExprOrStmt Parser::parse_macro_invocation_maybe_semi(::std::vector<AST::Attribute> outer_attrs) { + location_t macro_locus = lexer.peek_token()->get_locus(); + AST::SimplePath macro_path = parse_simple_path(); + if (macro_path.is_empty()) { + error_at(lexer.peek_token()->get_locus(), + "failed to parse simple path in macro invocation or semi"); + return ExprOrStmt::create_error(); + } + + if (!skip_token(EXCLAM)) { + return ExprOrStmt::create_error(); + } + + const_TokenPtr t3 = lexer.peek_token(); + location_t tok_tree_loc = t3->get_locus(); + + AST::DelimType type = AST::PARENS; + switch (t3->get_id()) { + case LEFT_PAREN: + type = AST::PARENS; break; - case WHILE: - return parse_while_statement(); + case LEFT_SQUARE: + type = AST::SQUARE; break; - case FOR: - return parse_for_statement(); - break;*/ - /*case READ: - return parse_read_statement(); + case LEFT_CURLY: + type = AST::CURLY; break; - case WRITE: - return parse_write_statement(); - break;*/ - /*case IDENTIFIER: - return parse_assignment_statement(); - break;*/ default: - // if not recognised, error with unexpected token and attempt resume - unexpected_token(t); - skip_after_semicolon(); - return Tree::error(); - break; + error_at(t3->get_locus(), + "unrecognised token '%s' in macro invocation - (opening) " + "delimiter expected", + t3->get_token_description()); + return ExprOrStmt::create_error(); + } + lexer.skip_token(); + + // parse actual token trees + ::std::vector< ::std::unique_ptr<AST::TokenTree> > token_trees; + + t3 = lexer.peek_token(); + // parse token trees until the initial delimiter token is found again + while (!token_id_matches_delims(t3->get_id(), type)) { + ::std::unique_ptr<AST::TokenTree> tree = parse_token_tree(); + + if (tree == NULL) { + error_at(t3->get_locus(), + "failed to parse token tree for macro invocation (or semi) - found '%s'", + t3->get_token_description()); + return ExprOrStmt::create_error(); + } + + token_trees.push_back(::std::move(tree)); + + t3 = lexer.peek_token(); + } + + // parse end delimiters + t3 = lexer.peek_token(); + if (token_id_matches_delims(t3->get_id(), type)) { + // tokens match opening delimiter, so skip. + lexer.skip_token(); + + /* with curly bracketed macros, assume it is a macro invocation unless + * a semicolon is explicitly put at the end. this is not necessarily + * true (i.e. context-dependence) and so may have to be fixed up via + * HACKs in semantic + * analysis (by checking whether it is the last elem in the vector). + */ + + if (lexer.peek_token()->get_id() == SEMICOLON) { + lexer.skip_token(); + + ::std::unique_ptr<AST::MacroInvocationSemi> stmt( + new AST::MacroInvocationSemi(::std::move(macro_path), type, + ::std::move(token_trees), ::std::move(outer_attrs), macro_locus)); + return ExprOrStmt(::std::move(stmt)); + } + + // otherwise, create macro invocation + AST::DelimTokenTree delim_tok_tree(type, ::std::move(token_trees), tok_tree_loc); + + ::std::unique_ptr<AST::MacroInvocation> expr( + new AST::MacroInvocation(::std::move(macro_path), ::std::move(delim_tok_tree), + ::std::move(outer_attrs), macro_locus)); + return ExprOrStmt(::std::move(expr)); + } else { + const_TokenPtr t = lexer.peek_token(); + // tokens don't match opening delimiters, so produce error + error_at(t->get_locus(), + "unexpected token '%s' - expecting closing delimiter '%s' (for a " + "macro invocation)", + t->get_token_description(), + (type == AST::PARENS ? ")" : (type == AST::SQUARE ? "]" : "}"))); + return ExprOrStmt::create_error(); } - return Tree::error(); } // "Unexpected token" panic mode - flags gcc error at unexpected token @@ -8148,29 +9424,6 @@ namespace Rust { } #if 0 - // Parses a "let" statement (variable declaration). - Tree Parser::parse_let_statement() { - /* - let_statement: -> outer_attribute* "let" pattern (":" type)? ("=" expression)? ";" */ - - // TODO: parse "outer attribute"? - // auto t = peek_token() - // while (t.get_id() == LEFT_SQUARE) { - // OuterAttribute attributes = parse_outer_attribute(); - //} - // etc. - - // ensure "let" token actually exists - if (!skip_token(LET)) { - skip_after_semicolon(); - return Tree::error(); - } - - - } -#endif - -#if 0 // Parses a variable declaration statement. Tree Parser::parse_variable_declaration() { // skip initial var keyword - TODO: fix @@ -8495,37 +9748,48 @@ namespace Rust { } /* A slightly more aware error-handler that skips all tokens until it reaches the end of the - * block scope (i.e. when left curly brackets = right curly brackets). */ + * block scope (i.e. when left curly brackets = right curly brackets). Note: assumes currently in + * the middle of a block. Use skip_after_next_block to skip based on the assumption that the block + * has not been entered yet. */ void Parser::skip_after_end_block() { const_TokenPtr t = lexer.peek_token(); - int curly_count = 0; + int curly_count = 1; - // initial loop before any curly braces - while (t->get_id() != END_OF_FILE && t->get_id() != LEFT_CURLY) { + while (curly_count > 0 && t->get_id() != END_OF_FILE) { + switch (t->get_id()) { + case LEFT_CURLY: + curly_count++; + break; + case RIGHT_CURLY: + curly_count--; + break; + default: + break; + } lexer.skip_token(); t = lexer.peek_token(); } + } - // start curly_count thing if curly braces found - if (t->get_id() == LEFT_CURLY) { - lexer.skip_token(); - curly_count++; - } - - // repeat until curly_count = 0 - while (t->get_id() != END_OF_FILE && /*t->get_id() != RIGHT_CURLY*/ curly_count > 0) { - if (t->get_id() == LEFT_CURLY) - curly_count++; - if (t->get_id() == RIGHT_CURLY) - curly_count--; + /* Skips tokens until the end of the next block. i.e. assumes that the block has not been entered + * yet. */ + void Parser::skip_after_next_block() { + const_TokenPtr t = lexer.peek_token(); + // initial loop - skip until EOF if no left curlies encountered + while (t->get_id() != END_OF_FILE && t->get_id() != LEFT_CURLY) { lexer.skip_token(); + t = lexer.peek_token(); } - /*if (t->get_id() == RIGHT_CURLY) { + // if next token is left, skip it and then skip after the block ends + if (t->get_id() == LEFT_CURLY) { lexer.skip_token(); - }*/ + + skip_after_end_block(); + } + // otherwise, do nothing as EOF } // Skips all tokens until ] (the end of an attribute) - does not skip the ] (as designed for @@ -8547,37 +9811,66 @@ namespace Rust { /* Pratt parser impl of parse_expr. FIXME: this is only provisional and probably will be changed. * FIXME: this may only parse expressions without blocks as they are the only expressions to have * precedence? */ - AST::Expr* Parser::parse_expr( - int right_binding_power, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::Expr> Parser::parse_expr(int right_binding_power, + ::std::vector<AST::Attribute> outer_attrs, ParseRestrictions restrictions) { const_TokenPtr current_token = lexer.peek_token(); lexer.skip_token(); // parse null denotation (unary part of expression) - AST::Expr* expr = null_denotation_NEW(current_token, ::std::move(outer_attrs)); + ::std::unique_ptr<AST::Expr> expr + = null_denotation_NEW(current_token, ::std::move(outer_attrs), restrictions); + + // DEBUG + fprintf(stderr, "finished parsing null denotation\n"); if (expr == NULL) { + // DEBUG + fprintf(stderr, "null denotation is null; returning null for parse_expr\n"); return NULL; } + // DEBUG + fprintf(stderr, "null denotation is not null - going on to left denotation\n"); + + // DEBUG + fprintf(stderr, "initial rbp: '%i', initial lbp: '%i' (for '%s')\n", right_binding_power, + left_binding_power(lexer.peek_token()), lexer.peek_token()->get_token_description()); + // stop parsing if find lower priority token - parse higher priority first while (right_binding_power < left_binding_power(lexer.peek_token())) { current_token = lexer.peek_token(); lexer.skip_token(); - expr = left_denotation(current_token, expr); + expr = left_denotation( + current_token, ::std::move(expr), ::std::vector<AST::Attribute>(), restrictions); + + // DEBUG + fprintf(stderr, "successfully got left_denotation in parse_expr \n"); + if (expr == NULL) { + + // DEBUG + fprintf(stderr, "left denotation is null; returning null for parse_expr\n"); + return NULL; } + + // DEBUG + fprintf(stderr, "left denotation is not null - going to next iteration \n"); } + // DEBUG + fprintf(stderr, "successfully parsed expr in parse_expr - returning \n"); + return expr; } /* Parse expression with lowest left binding power. FIXME: this may only apply to expressions * without blocks as they are the only ones to have precedence? */ - AST::Expr* Parser::parse_expr(::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::Expr> Parser::parse_expr( + ::std::vector<AST::Attribute> outer_attrs, ParseRestrictions restrictions) { // HACK: only call parse_expr(LBP_LOWEST) after ensuring it is not an expression with block? - return parse_expr(LBP_LOWEST, outer_attrs); + return parse_expr(LBP_LOWEST, ::std::move(outer_attrs), restrictions); } // Pratt parser impl of parse_expression. @@ -8642,8 +9935,8 @@ namespace Rust { /* Determines action to take when finding token at beginning of expression. * FIXME: this may only apply to precedence-capable expressions (which are all expressions without * blocks), so make return type ExprWithoutBlock? It would simplify stuff. */ - AST::Expr* Parser::null_denotation_NEW( - const_TokenPtr tok, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::Expr> Parser::null_denotation_NEW( + const_TokenPtr tok, ::std::vector<AST::Attribute> outer_attrs, ParseRestrictions restrictions) { // note: tok is previous character in input stream, not current one, as parse_expr // skips it before passing it in @@ -8665,24 +9958,129 @@ namespace Rust { return Tree(s->get_tree_decl(), tok->get_locus()); }*/ // symbol table must be created in semantic analysis pass, so can't use this - case IDENTIFIER: - // have to return an identifier expression or something, idk - // HACK: may have to become permanent, but this is my current identifier expression - return new AST::IdentifierExpr(tok->get_str()); + case IDENTIFIER: { + // DEBUG + fprintf(stderr, "beginning null denotation identifier handling\n"); + + // best option: parse as path, then extract identifier, macro, struct/enum, or just + // path info from it + AST::PathInExpression path = parse_path_in_expression_pratt(tok); + + // DEBUG: + fprintf( + stderr, "finished null denotation identifier path parsing - next is branching \n"); + + // branch on next token + const_TokenPtr t = lexer.peek_token(); + switch (t->get_id()) { + case EXCLAM: + // macro + return parse_macro_invocation_partial( + ::std::move(path), ::std::move(outer_attrs)); + case LEFT_CURLY: { + bool not_a_block + = lexer.peek_token(1)->get_id() == IDENTIFIER + && (lexer.peek_token(2)->get_id() == COMMA + || (lexer.peek_token(2)->get_id() == COLON + && (lexer.peek_token(4)->get_id() == COMMA + || !can_tok_start_type(lexer.peek_token(3)->get_id())))); + + /* definitely not a block: + * path '{' ident ',' + * path '{' ident ':' [anything] ',' + * path '{' ident ':' [not a type] + * otherwise, assume block expr and thus path */ + // DEBUG + fprintf(stderr, "values of lookahead: '%s' '%s' '%s' '%s' \n", + lexer.peek_token(1)->get_token_description(), + lexer.peek_token(2)->get_token_description(), + lexer.peek_token(3)->get_token_description(), + lexer.peek_token(4)->get_token_description()); + + fprintf(stderr, "can be struct expr: '%s', not a block: '%s'\n", + restrictions.can_be_struct_expr ? "true" : "false", + not_a_block ? "true" : "false"); + + // struct/enum expr struct + if (!restrictions.can_be_struct_expr && !not_a_block) { + // assume path is returned if not single segment + if (path.is_single_segment()) { + // have to return an identifier expression or something, idk + // HACK: may have to become permanent, but this is my current + // identifier expression + return ::std::unique_ptr<AST::IdentifierExpr>( + new AST::IdentifierExpr(tok->get_str(), tok->get_locus())); + } + // HACK: add outer attrs to path + path.replace_outer_attrs(::std::move(outer_attrs)); + return ::std::unique_ptr<AST::PathInExpression>( + new AST::PathInExpression(::std::move(path))); + } + return parse_struct_expr_struct_partial( + ::std::move(path), ::std::move(outer_attrs)); + } + case LEFT_PAREN: + // struct/enum expr tuple + if (!restrictions.can_be_struct_expr) { + // assume path is returned if not single segment + if (path.is_single_segment()) { + // have to return an identifier expression or something, idk + // HACK: may have to become permanent, but this is my current + // identifier expression + return ::std::unique_ptr<AST::IdentifierExpr>( + new AST::IdentifierExpr(tok->get_str(), tok->get_locus())); + } + // HACK: add outer attrs to path + path.replace_outer_attrs(::std::move(outer_attrs)); + return ::std::unique_ptr<AST::PathInExpression>( + new AST::PathInExpression(::std::move(path))); + } + return parse_struct_expr_tuple_partial( + ::std::move(path), ::std::move(outer_attrs)); + default: + // assume path is returned if not single segment + if (path.is_single_segment()) { + // have to return an identifier expression or something, idk + // HACK: may have to become permanent, but this is my current identifier + // expression + return ::std::unique_ptr<AST::IdentifierExpr>( + new AST::IdentifierExpr(tok->get_str(), tok->get_locus())); + } + // HACK: add outer attrs to path + path.replace_outer_attrs(::std::move(outer_attrs)); + return ::std::unique_ptr<AST::PathInExpression>( + new AST::PathInExpression(::std::move(path))); + } + gcc_unreachable(); + } // FIXME: delegate to parse_literal_expr instead? would have to rejig tokens and whatever. + // FIXME: could also be path expression (and hence macro expression, struct/enum expr) + case LEFT_ANGLE: { + // qualified path + // HACK: add outer attrs to path + AST::QualifiedPathInExpression path = parse_qualified_path_in_expression(true); + path.replace_outer_attrs(::std::move(outer_attrs)); + return ::std::unique_ptr<AST::QualifiedPathInExpression>( + new AST::QualifiedPathInExpression(::std::move(path))); + } case INT_LITERAL: // we should check the range, but ignore for now // encode as int? - return new AST::LiteralExpr(tok->get_str(), AST::Literal::INT); + return ::std::unique_ptr<AST::LiteralExpr>( + new AST::LiteralExpr(tok->get_str(), AST::Literal::INT, tok->get_locus())); case FLOAT_LITERAL: // encode as float? - return new AST::LiteralExpr(tok->get_str(), AST::Literal::FLOAT); + return ::std::unique_ptr<AST::LiteralExpr>( + new AST::LiteralExpr(tok->get_str(), AST::Literal::FLOAT, tok->get_locus())); case STRING_LITERAL: - return new AST::LiteralExpr(tok->get_str(), AST::Literal::STRING); + return ::std::unique_ptr<AST::LiteralExpr>( + new AST::LiteralExpr(tok->get_str(), AST::Literal::STRING, tok->get_locus())); case TRUE_LITERAL: - return new AST::LiteralExpr("true", AST::Literal::BOOL); + return ::std::unique_ptr<AST::LiteralExpr>( + new AST::LiteralExpr("true", AST::Literal::BOOL, tok->get_locus())); case FALSE_LITERAL: - return new AST::LiteralExpr("false", AST::Literal::BOOL); + return ::std::unique_ptr<AST::LiteralExpr>( + new AST::LiteralExpr("false", AST::Literal::BOOL, tok->get_locus())); case LEFT_PAREN: { // have to parse whole expression if inside brackets /* recursively invoke parse_expression with lowest priority possible as it it were * a top-level expression. */ @@ -8700,7 +10098,7 @@ namespace Rust { // FIXME: this assumes grouped expression - could be tuple expression if commas inside*/ - return parse_grouped_or_tuple_expr(::std::vector<AST::Attribute>(), true); + return parse_grouped_or_tuple_expr(::std::move(outer_attrs), true); } /*case PLUS: { // unary plus operator // invoke parse_expr recursively with appropriate priority, etc. for below @@ -8720,7 +10118,10 @@ namespace Rust { }*/ // Rust has no unary plus operator case MINUS: { // unary minus - AST::Expr* expr = parse_expr(LBP_UNARY_MINUS); + ParseRestrictions entered_from_unary; + entered_from_unary.entered_from_unary = true; + ::std::unique_ptr<AST::Expr> expr + = parse_expr(LBP_UNARY_MINUS, ::std::vector<AST::Attribute>(), entered_from_unary); if (expr == NULL) return NULL; @@ -8737,11 +10138,14 @@ namespace Rust { /* FIXME: allow outer attributes on these expressions by having an outer attrs * parameter in function*/ - return new AST::NegationExpr( - expr, AST::NegationExpr::NEGATE, ::std::vector<AST::Attribute>()); + return ::std::unique_ptr<AST::NegationExpr>(new AST::NegationExpr(::std::move(expr), + AST::NegationExpr::NEGATE, ::std::move(outer_attrs), tok->get_locus())); } case EXCLAM: { // logical or bitwise not - AST::Expr* expr = parse_expr(LBP_UNARY_EXCLAM); + ParseRestrictions entered_from_unary; + entered_from_unary.entered_from_unary = true; + ::std::unique_ptr<AST::Expr> expr + = parse_expr(LBP_UNARY_EXCLAM, ::std::vector<AST::Attribute>(), entered_from_unary); if (expr == NULL) return NULL; @@ -8755,48 +10159,67 @@ namespace Rust { // FIXME: type checking for boolean or integer expressions in semantic analysis // FIXME: allow outer attributes on these expressions - return new AST::NegationExpr( - expr, AST::NegationExpr::NOT, ::std::vector<AST::Attribute>()); + return ::std::unique_ptr<AST::NegationExpr>(new AST::NegationExpr(::std::move(expr), + AST::NegationExpr::NOT, ::std::move(outer_attrs), tok->get_locus())); } case ASTERISK: { - // pointer dereference only - TODO: ensure that it is - AST::Expr* expr = parse_expr(LBP_UNARY_ASTERISK); + // pointer dereference only - HACK: as struct expressions should always be value + // expressions, cannot be dereferenced + ParseRestrictions entered_from_unary; + entered_from_unary.entered_from_unary = true; + entered_from_unary.can_be_struct_expr = false; + ::std::unique_ptr<AST::Expr> expr = parse_expr( + LBP_UNARY_ASTERISK, ::std::vector<AST::Attribute>(), entered_from_unary); // FIXME: allow outer attributes on expression - return new AST::DereferenceExpr(expr, ::std::vector<AST::Attribute>()); + return ::std::unique_ptr<AST::DereferenceExpr>(new AST::DereferenceExpr( + ::std::move(expr), ::std::move(outer_attrs), tok->get_locus())); } case AMP: { // (single) "borrow" expression - shared (mutable) or immutable - AST::Expr* expr = NULL; + ::std::unique_ptr<AST::Expr> expr = NULL; bool is_mut_borrow = false; + // HACK: as struct expressions should always be value expressions, cannot be + // referenced + ParseRestrictions entered_from_unary; + entered_from_unary.entered_from_unary = true; + entered_from_unary.can_be_struct_expr = false; + if (lexer.peek_token()->get_id() == MUT) { lexer.skip_token(); - expr = parse_expr(LBP_UNARY_AMP_MUT); + expr = parse_expr( + LBP_UNARY_AMP_MUT, ::std::vector<AST::Attribute>(), entered_from_unary); is_mut_borrow = true; } else { - expr = parse_expr(LBP_UNARY_AMP); + expr = parse_expr( + LBP_UNARY_AMP, ::std::vector<AST::Attribute>(), entered_from_unary); } // FIXME: allow outer attributes on expression - return new AST::BorrowExpr( - expr, is_mut_borrow, false, ::std::vector<AST::Attribute>()); + return ::std::unique_ptr<AST::BorrowExpr>(new AST::BorrowExpr(::std::move(expr), + is_mut_borrow, false, ::std::move(outer_attrs), tok->get_locus())); } case LOGICAL_AND: { // (double) "borrow" expression - shared (mutable) or immutable - AST::Expr* expr = NULL; + ::std::unique_ptr<AST::Expr> expr = NULL; bool is_mut_borrow = false; + ParseRestrictions entered_from_unary; + entered_from_unary.entered_from_unary = true; + if (lexer.peek_token()->get_id() == MUT) { lexer.skip_token(); - expr = parse_expr(LBP_UNARY_AMP_MUT); + expr = parse_expr( + LBP_UNARY_AMP_MUT, ::std::vector<AST::Attribute>(), entered_from_unary); is_mut_borrow = true; } else { - expr = parse_expr(LBP_UNARY_AMP); + expr = parse_expr( + LBP_UNARY_AMP, ::std::vector<AST::Attribute>(), entered_from_unary); } // FIXME: allow outer attributes on expression - return new AST::BorrowExpr( - expr, is_mut_borrow, true, ::std::vector<AST::Attribute>()); + return ::std::unique_ptr<AST::BorrowExpr>(new AST::BorrowExpr(::std::move(expr), + is_mut_borrow, true, ::std::move(outer_attrs), tok->get_locus())); } case SCOPE_RESOLUTION: { // TODO: fix: this is for global paths, i.e. ::std::string::whatever @@ -8804,25 +10227,109 @@ namespace Rust { "haven't written handling for it."); return NULL; } + case SELF: + case SELF_ALIAS: + case DOLLAR_SIGN: + case CRATE: + case SUPER: { + // DEBUG + fprintf( + stderr, "beginning null denotation self/self-alias/dollar/crate/super handling\n"); + + // best option: parse as path, then extract identifier, macro, struct/enum, or just + // path info from it + AST::PathInExpression path = parse_path_in_expression_pratt(tok); + + // DEBUG + fprintf(stderr, + "just finished parsing path (going to disambiguate) - peeked token is '%s'\n", + lexer.peek_token()->get_token_description()); + + // HACK: always make "self" by itself a path (regardless of next tokens) + if (tok->get_id() == SELF && path.is_single_segment()) { + // HACK: add outer attrs to path + path.replace_outer_attrs(::std::move(outer_attrs)); + return ::std::unique_ptr<AST::PathInExpression>( + new AST::PathInExpression(::std::move(path))); + } + + // branch on next token + const_TokenPtr t = lexer.peek_token(); + switch (t->get_id()) { + case EXCLAM: + // macro + return parse_macro_invocation_partial( + ::std::move(path), ::std::move(outer_attrs)); + case LEFT_CURLY: { + // struct/enum expr struct + fprintf(stderr, "can_be_struct_expr: %s\n", + restrictions.can_be_struct_expr ? "true" : "false"); + + bool not_a_block + = lexer.peek_token(1)->get_id() == IDENTIFIER + && (lexer.peek_token(2)->get_id() == COMMA + || (lexer.peek_token(2)->get_id() == COLON + && (lexer.peek_token(4)->get_id() == COMMA + || !can_tok_start_type(lexer.peek_token(3)->get_id())))); + + if (!restrictions.can_be_struct_expr && !not_a_block) { + // assume path is returned + // HACK: add outer attributes to path + path.replace_outer_attrs(::std::move(outer_attrs)); + return ::std::unique_ptr<AST::PathInExpression>( + new AST::PathInExpression(::std::move(path))); + } + return parse_struct_expr_struct_partial( + ::std::move(path), ::std::move(outer_attrs)); + } + case LEFT_PAREN: + // struct/enum expr tuple + if (!restrictions.can_be_struct_expr) { + // assume path is returned + // HACK: add outer attributes to path + path.replace_outer_attrs(::std::move(outer_attrs)); + return ::std::unique_ptr<AST::PathInExpression>( + new AST::PathInExpression(::std::move(path))); + } + return parse_struct_expr_tuple_partial( + ::std::move(path), ::std::move(outer_attrs)); + default: + // assume path is returned + // HACK: add outer attributes to path + path.replace_outer_attrs(::std::move(outer_attrs)); + return ::std::unique_ptr<AST::PathInExpression>( + new AST::PathInExpression(::std::move(path))); + } + gcc_unreachable(); + } case OR: case PIPE: case MOVE: - // TODO: fix: this is for closure expressions - error_at(tok->get_locus(), "found null denotation closure expr initial tokens, and " - "haven't written handling for it."); - return NULL; + // closure expression + return parse_closure_expr_pratt(tok, ::std::move(outer_attrs)); case DOT_DOT: // either "range to" or "range full" expressions - return parse_nud_range_exclusive_expr(tok, ::std::vector<AST::Attribute>()); + return parse_nud_range_exclusive_expr(tok, ::std::move(outer_attrs)); case DOT_DOT_EQ: // range to inclusive expr - return parse_range_to_inclusive_expr(tok, ::std::vector<AST::Attribute>()); + return parse_range_to_inclusive_expr(tok, ::std::move(outer_attrs)); case RETURN_TOK: // FIXME: is this really a null denotation expression? - return parse_return_expr(::std::vector<AST::Attribute>(), true); + return parse_return_expr(::std::move(outer_attrs), true); case BREAK: // FIXME: is this really a null denotation expression? - return parse_break_expr(::std::vector<AST::Attribute>(), true); + return parse_break_expr(::std::move(outer_attrs), true); + case CONTINUE: + return parse_continue_expr(::std::move(outer_attrs), true); + case LEFT_CURLY: + // ok - this is an expression with block for once. + return parse_block_expr(::std::move(outer_attrs), true); + case MATCH_TOK: + // also an expression with block + return parse_match_expr(::std::move(outer_attrs), true); + case LEFT_SQUARE: + // array definition expr (not indexing) + return parse_array_expr(::std::move(outer_attrs), true); default: error_at(tok->get_locus(), "found unexpected token '%s' in null denotation", tok->get_token_description()); @@ -8834,8 +10341,9 @@ namespace Rust { * punctuation. * Returns a function pointer to member function that implements the left denotation for the token * given. */ - AST::Expr* Parser::left_denotation( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::Expr> Parser::left_denotation(const_TokenPtr tok, + ::std::unique_ptr<AST::Expr> left, ::std::vector<AST::Attribute> outer_attrs, + ParseRestrictions restrictions) { // Token passed in has already been skipped, so peek gives "next" token /*BinaryHandler binary_handler = get_binary_handler(tok->get_id()); if (binary_handler == NULL) { @@ -8845,109 +10353,145 @@ namespace Rust { return (this->*binary_handler)(tok, left);*/ // can't do with binary handler because same token used for several operators + switch (tok->get_id()) { // FIXME: allow for outer attributes to be applied - case QUESTION_MARK: + case QUESTION_MARK: { + location_t left_locus = left->get_locus_slow(); // error propagation expression - unary postfix - return new AST::ErrorPropogationExpr(left, ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::ErrorPropagationExpr>(new AST::ErrorPropagationExpr( + ::std::move(left), ::std::move(outer_attrs), left_locus)); + } case PLUS: // sum expression - binary infix - return parse_binary_plus_expr(tok, left, ::std::move(outer_attrs)); + return parse_binary_plus_expr( + tok, ::std::move(left), ::std::move(outer_attrs), restrictions); case MINUS: // difference expression - binary infix - return parse_binary_minus_expr(tok, left, ::std::move(outer_attrs)); + return parse_binary_minus_expr( + tok, ::std::move(left), ::std::move(outer_attrs), restrictions); case ASTERISK: // product expression - binary infix - return parse_binary_mult_expr(tok, left, ::std::move(outer_attrs)); + return parse_binary_mult_expr( + tok, ::std::move(left), ::std::move(outer_attrs), restrictions); case DIV: // quotient expression - binary infix - return parse_binary_div_expr(tok, left, ::std::move(outer_attrs)); + return parse_binary_div_expr( + tok, ::std::move(left), ::std::move(outer_attrs), restrictions); case PERCENT: // modulo expression - binary infix - return parse_binary_mod_expr(tok, left, ::std::move(outer_attrs)); + return parse_binary_mod_expr( + tok, ::std::move(left), ::std::move(outer_attrs), restrictions); case AMP: // logical or bitwise and expression - binary infix - return parse_bitwise_and_expr(tok, left, ::std::move(outer_attrs)); + return parse_bitwise_and_expr( + tok, ::std::move(left), ::std::move(outer_attrs), restrictions); case PIPE: // logical or bitwise or expression - binary infix - return parse_bitwise_or_expr(tok, left, ::std::move(outer_attrs)); + return parse_bitwise_or_expr( + tok, ::std::move(left), ::std::move(outer_attrs), restrictions); case CARET: // logical or bitwise xor expression - binary infix - return parse_bitwise_xor_expr(tok, left, ::std::move(outer_attrs)); + return parse_bitwise_xor_expr( + tok, ::std::move(left), ::std::move(outer_attrs), restrictions); case LEFT_SHIFT: // left shift expression - binary infix - return parse_left_shift_expr(tok, left, ::std::move(outer_attrs)); + return parse_left_shift_expr( + tok, ::std::move(left), ::std::move(outer_attrs), restrictions); case RIGHT_SHIFT: // right shift expression - binary infix - return parse_right_shift_expr(tok, left, ::std::move(outer_attrs)); + return parse_right_shift_expr( + tok, ::std::move(left), ::std::move(outer_attrs), restrictions); case EQUAL_EQUAL: // equal to expression - binary infix (no associativity) - return parse_binary_equal_expr(tok, left, ::std::move(outer_attrs)); + return parse_binary_equal_expr( + tok, ::std::move(left), ::std::move(outer_attrs), restrictions); case NOT_EQUAL: // not equal to expression - binary infix (no associativity) - return parse_binary_not_equal_expr(tok, left, ::std::move(outer_attrs)); + return parse_binary_not_equal_expr( + tok, ::std::move(left), ::std::move(outer_attrs), restrictions); case RIGHT_ANGLE: // greater than expression - binary infix (no associativity) - return parse_binary_greater_than_expr(tok, left, ::std::move(outer_attrs)); + return parse_binary_greater_than_expr( + tok, ::std::move(left), ::std::move(outer_attrs), restrictions); case LEFT_ANGLE: // less than expression - binary infix (no associativity) - return parse_binary_less_than_expr(tok, left, ::std::move(outer_attrs)); + return parse_binary_less_than_expr( + tok, ::std::move(left), ::std::move(outer_attrs), restrictions); case GREATER_OR_EQUAL: // greater than or equal to expression - binary infix (no associativity) - return parse_binary_greater_equal_expr(tok, left, ::std::move(outer_attrs)); + return parse_binary_greater_equal_expr( + tok, ::std::move(left), ::std::move(outer_attrs), restrictions); case LESS_OR_EQUAL: // less than or equal to expression - binary infix (no associativity) - return parse_binary_less_equal_expr(tok, left, ::std::move(outer_attrs)); + return parse_binary_less_equal_expr( + tok, ::std::move(left), ::std::move(outer_attrs), restrictions); case OR: // lazy logical or expression - binary infix - return parse_lazy_or_expr(tok, left, ::std::move(outer_attrs)); + return parse_lazy_or_expr( + tok, ::std::move(left), ::std::move(outer_attrs), restrictions); case LOGICAL_AND: // lazy logical and expression - binary infix - return parse_lazy_and_expr(tok, left, ::std::move(outer_attrs)); + return parse_lazy_and_expr( + tok, ::std::move(left), ::std::move(outer_attrs), restrictions); case AS: // type cast expression - kind of binary infix (RHS is actually a TypeNoBounds) - return parse_type_cast_expr(tok, left, ::std::move(outer_attrs)); + return parse_type_cast_expr( + tok, ::std::move(left), ::std::move(outer_attrs), restrictions); case EQUAL: // assignment expression - binary infix (note right-to-left associativity) - return parse_assig_expr(tok, left, ::std::move(outer_attrs)); + return parse_assig_expr( + tok, ::std::move(left), ::std::move(outer_attrs), restrictions); case PLUS_EQ: // plus-assignment expression - binary infix (note right-to-left associativity) - return parse_plus_assig_expr(tok, left, ::std::move(outer_attrs)); + return parse_plus_assig_expr( + tok, ::std::move(left), ::std::move(outer_attrs), restrictions); case MINUS_EQ: // minus-assignment expression - binary infix (note right-to-left associativity) - return parse_minus_assig_expr(tok, left, ::std::move(outer_attrs)); + return parse_minus_assig_expr( + tok, ::std::move(left), ::std::move(outer_attrs), restrictions); case ASTERISK_EQ: // multiply-assignment expression - binary infix (note right-to-left associativity) - return parse_mult_assig_expr(tok, left, ::std::move(outer_attrs)); + return parse_mult_assig_expr( + tok, ::std::move(left), ::std::move(outer_attrs), restrictions); case DIV_EQ: // division-assignment expression - binary infix (note right-to-left associativity) - return parse_div_assig_expr(tok, left, ::std::move(outer_attrs)); + return parse_div_assig_expr( + tok, ::std::move(left), ::std::move(outer_attrs), restrictions); case PERCENT_EQ: // modulo-assignment expression - binary infix (note right-to-left associativity) - return parse_mod_assig_expr(tok, left, ::std::move(outer_attrs)); + return parse_mod_assig_expr( + tok, ::std::move(left), ::std::move(outer_attrs), restrictions); case AMP_EQ: // bitwise and-assignment expression - binary infix (note right-to-left associativity) - return parse_and_assig_expr(tok, left, ::std::move(outer_attrs)); + return parse_and_assig_expr( + tok, ::std::move(left), ::std::move(outer_attrs), restrictions); case PIPE_EQ: // bitwise or-assignment expression - binary infix (note right-to-left associativity) - return parse_or_assig_expr(tok, left, ::std::move(outer_attrs)); + return parse_or_assig_expr( + tok, ::std::move(left), ::std::move(outer_attrs), restrictions); case CARET_EQ: // bitwise xor-assignment expression - binary infix (note right-to-left associativity) - return parse_xor_assig_expr(tok, left, ::std::move(outer_attrs)); + return parse_xor_assig_expr( + tok, ::std::move(left), ::std::move(outer_attrs), restrictions); case LEFT_SHIFT_EQ: // left shift-assignment expression - binary infix (note right-to-left associativity) - return parse_left_shift_assig_expr(tok, left, ::std::move(outer_attrs)); + return parse_left_shift_assig_expr( + tok, ::std::move(left), ::std::move(outer_attrs), restrictions); case RIGHT_SHIFT_EQ: // right shift-assignment expression - binary infix (note right-to-left associativity) - return parse_right_shift_assig_expr(tok, left, ::std::move(outer_attrs)); + return parse_right_shift_assig_expr( + tok, ::std::move(left), ::std::move(outer_attrs), restrictions); case DOT_DOT: // range exclusive expression - binary infix (no associativity) // either "range" or "range from" - return parse_led_range_exclusive_expr(tok, left, ::std::move(outer_attrs)); + return parse_led_range_exclusive_expr( + tok, ::std::move(left), ::std::move(outer_attrs), restrictions); case DOT_DOT_EQ: // range inclusive expression - binary infix (no associativity) // unambiguously RangeInclusiveExpr - return parse_range_inclusive_expr(tok, left, ::std::move(outer_attrs)); + return parse_range_inclusive_expr( + tok, ::std::move(left), ::std::move(outer_attrs), restrictions); case SCOPE_RESOLUTION: // path expression - binary infix? FIXME should this even be parsed here? error_at(tok->get_locus(), "found scope resolution operator in left denotation " @@ -8961,25 +10505,36 @@ namespace Rust { const_TokenPtr next_tok = lexer.peek_token(); if (next_tok->get_id() == IDENTIFIER && next_tok->get_str() == "await") { // await expression - return parse_await_expr(tok, left, ::std::move(outer_attrs)); + return parse_await_expr(tok, ::std::move(left), ::std::move(outer_attrs)); } else if (next_tok->get_id() == INT_LITERAL) { // tuple index expression - TODO check for decimal int literal - return parse_tuple_index_expr(tok, left, ::std::move(outer_attrs)); + return parse_tuple_index_expr( + tok, ::std::move(left), ::std::move(outer_attrs), restrictions); } else if (next_tok->get_id() == IDENTIFIER - && lexer.peek_token(1)->get_id() != LEFT_PAREN) { - // field expression (or should be) - return parse_field_access_expr(tok, left, ::std::move(outer_attrs)); + && lexer.peek_token(1)->get_id() != LEFT_PAREN + && lexer.peek_token(1)->get_id() != SCOPE_RESOLUTION) { + // field expression (or should be) - FIXME: scope resolution right after + // identifier should always be method, I'm pretty sure + return parse_field_access_expr( + tok, ::std::move(left), ::std::move(outer_attrs), restrictions); } else { // method call (probably) - return parse_method_call_expr(tok, left, ::std::move(outer_attrs)); + return parse_method_call_expr( + tok, ::std::move(left), ::std::move(outer_attrs), restrictions); } } case LEFT_PAREN: // function call - method call is based on dot notation first - return parse_function_call_expr(tok, left, ::std::move(outer_attrs)); + return parse_function_call_expr( + tok, ::std::move(left), ::std::move(outer_attrs), restrictions); case LEFT_SQUARE: // array or slice index expression (pseudo binary infix) - return parse_index_expr(tok, left, ::std::move(outer_attrs)); + return parse_index_expr( + tok, ::std::move(left), ::std::move(outer_attrs), restrictions); + case FLOAT_LITERAL: + // HACK: get around lexer mis-identifying '.0' or '.1' or whatever as a float literal + return parse_tuple_index_expr_float( + tok, ::std::move(left), ::std::move(outer_attrs), restrictions); default: error_at(tok->get_locus(), "found unexpected token '%s' in left denotation", tok->get_token_description()); @@ -8988,415 +10543,530 @@ namespace Rust { } // Parses a binary addition expression (with Pratt parsing). - AST::ArithmeticOrLogicalExpr* Parser::parse_binary_plus_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::ArithmeticOrLogicalExpr> Parser::parse_binary_plus_expr( + const_TokenPtr tok ATTRIBUTE_UNUSED, ::std::unique_ptr<AST::Expr> left, + ::std::vector<AST::Attribute> outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) { // parse RHS (as tok has already been consumed in parse_expression) - AST::Expr* right = parse_expr(LBP_PLUS); + ::std::unique_ptr<AST::Expr> right + = parse_expr(LBP_PLUS, ::std::vector<AST::Attribute>(), restrictions); if (right == NULL) return NULL; // TODO: check types. actually, do so during semantic analysis + location_t locus = left->get_locus_slow(); - return new AST::ArithmeticOrLogicalExpr(left, right, AST::ArithmeticOrLogicalExpr::ADD); + return ::std::unique_ptr<AST::ArithmeticOrLogicalExpr>(new AST::ArithmeticOrLogicalExpr( + ::std::move(left), ::std::move(right), AST::ArithmeticOrLogicalExpr::ADD, locus)); } // Parses a binary subtraction expression (with Pratt parsing). - AST::ArithmeticOrLogicalExpr* Parser::parse_binary_minus_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::ArithmeticOrLogicalExpr> Parser::parse_binary_minus_expr( + const_TokenPtr tok ATTRIBUTE_UNUSED, ::std::unique_ptr<AST::Expr> left, + ::std::vector<AST::Attribute> outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) { // parse RHS (as tok has already been consumed in parse_expression) - AST::Expr* right = parse_expr(LBP_MINUS); + ::std::unique_ptr<AST::Expr> right + = parse_expr(LBP_MINUS, ::std::vector<AST::Attribute>(), restrictions); if (right == NULL) return NULL; // TODO: check types. actually, do so during semantic analysis + location_t locus = left->get_locus_slow(); - return new AST::ArithmeticOrLogicalExpr(left, right, AST::ArithmeticOrLogicalExpr::SUBTRACT); + return ::std::unique_ptr<AST::ArithmeticOrLogicalExpr>(new AST::ArithmeticOrLogicalExpr( + ::std::move(left), ::std::move(right), AST::ArithmeticOrLogicalExpr::SUBTRACT, locus)); } // Parses a binary multiplication expression (with Pratt parsing). - AST::ArithmeticOrLogicalExpr* Parser::parse_binary_mult_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::ArithmeticOrLogicalExpr> Parser::parse_binary_mult_expr( + const_TokenPtr tok ATTRIBUTE_UNUSED, ::std::unique_ptr<AST::Expr> left, + ::std::vector<AST::Attribute> outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) { // parse RHS (as tok has already been consumed in parse_expression) - AST::Expr* right = parse_expr(LBP_MUL); + ::std::unique_ptr<AST::Expr> right + = parse_expr(LBP_MUL, ::std::vector<AST::Attribute>(), restrictions); if (right == NULL) return NULL; // TODO: check types. actually, do so during semantic analysis + location_t locus = left->get_locus_slow(); - return new AST::ArithmeticOrLogicalExpr(left, right, AST::ArithmeticOrLogicalExpr::MULTIPLY); + return ::std::unique_ptr<AST::ArithmeticOrLogicalExpr>(new AST::ArithmeticOrLogicalExpr( + ::std::move(left), ::std::move(right), AST::ArithmeticOrLogicalExpr::MULTIPLY, locus)); } // Parses a binary division expression (with Pratt parsing). - AST::ArithmeticOrLogicalExpr* Parser::parse_binary_div_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::ArithmeticOrLogicalExpr> Parser::parse_binary_div_expr( + const_TokenPtr tok ATTRIBUTE_UNUSED, ::std::unique_ptr<AST::Expr> left, + ::std::vector<AST::Attribute> outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) { // parse RHS (as tok has already been consumed in parse_expression) - AST::Expr* right = parse_expr(LBP_DIV); + ::std::unique_ptr<AST::Expr> right + = parse_expr(LBP_DIV, ::std::vector<AST::Attribute>(), restrictions); if (right == NULL) return NULL; // TODO: check types. actually, do so during semantic analysis + location_t locus = left->get_locus_slow(); - return new AST::ArithmeticOrLogicalExpr(left, right, AST::ArithmeticOrLogicalExpr::DIVIDE); + return ::std::unique_ptr<AST::ArithmeticOrLogicalExpr>(new AST::ArithmeticOrLogicalExpr( + ::std::move(left), ::std::move(right), AST::ArithmeticOrLogicalExpr::DIVIDE, locus)); } // Parses a binary modulo expression (with Pratt parsing). - AST::ArithmeticOrLogicalExpr* Parser::parse_binary_mod_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::ArithmeticOrLogicalExpr> Parser::parse_binary_mod_expr( + const_TokenPtr tok ATTRIBUTE_UNUSED, ::std::unique_ptr<AST::Expr> left, + ::std::vector<AST::Attribute> outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) { // parse RHS (as tok has already been consumed in parse_expression) - AST::Expr* right = parse_expr(LBP_MOD); + ::std::unique_ptr<AST::Expr> right + = parse_expr(LBP_MOD, ::std::vector<AST::Attribute>(), restrictions); if (right == NULL) return NULL; // TODO: check types. actually, do so during semantic analysis + location_t locus = left->get_locus_slow(); - return new AST::ArithmeticOrLogicalExpr(left, right, AST::ArithmeticOrLogicalExpr::MODULUS); + return ::std::unique_ptr<AST::ArithmeticOrLogicalExpr>(new AST::ArithmeticOrLogicalExpr( + ::std::move(left), ::std::move(right), AST::ArithmeticOrLogicalExpr::MODULUS, locus)); } // Parses a binary bitwise (or eager logical) and expression (with Pratt parsing). - AST::ArithmeticOrLogicalExpr* Parser::parse_bitwise_and_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::ArithmeticOrLogicalExpr> Parser::parse_bitwise_and_expr( + const_TokenPtr tok ATTRIBUTE_UNUSED, ::std::unique_ptr<AST::Expr> left, + ::std::vector<AST::Attribute> outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) { // parse RHS (as tok has already been consumed in parse_expression) - AST::Expr* right = parse_expr(LBP_AMP); + ::std::unique_ptr<AST::Expr> right + = parse_expr(LBP_AMP, ::std::vector<AST::Attribute>(), restrictions); if (right == NULL) return NULL; // TODO: check types. actually, do so during semantic analysis + location_t locus = left->get_locus_slow(); - return new AST::ArithmeticOrLogicalExpr( - left, right, AST::ArithmeticOrLogicalExpr::BITWISE_AND); + return ::std::unique_ptr<AST::ArithmeticOrLogicalExpr>(new AST::ArithmeticOrLogicalExpr( + ::std::move(left), ::std::move(right), AST::ArithmeticOrLogicalExpr::BITWISE_AND, locus)); } // Parses a binary bitwise (or eager logical) or expression (with Pratt parsing). - AST::ArithmeticOrLogicalExpr* Parser::parse_bitwise_or_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::ArithmeticOrLogicalExpr> Parser::parse_bitwise_or_expr( + const_TokenPtr tok ATTRIBUTE_UNUSED, ::std::unique_ptr<AST::Expr> left, + ::std::vector<AST::Attribute> outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) { // parse RHS (as tok has already been consumed in parse_expression) - AST::Expr* right = parse_expr(LBP_PIPE); + ::std::unique_ptr<AST::Expr> right + = parse_expr(LBP_PIPE, ::std::vector<AST::Attribute>(), restrictions); if (right == NULL) return NULL; // TODO: check types. actually, do so during semantic analysis + location_t locus = left->get_locus_slow(); - return new AST::ArithmeticOrLogicalExpr( - left, right, AST::ArithmeticOrLogicalExpr::BITWISE_OR); + return ::std::unique_ptr<AST::ArithmeticOrLogicalExpr>(new AST::ArithmeticOrLogicalExpr( + ::std::move(left), ::std::move(right), AST::ArithmeticOrLogicalExpr::BITWISE_OR, locus)); } // Parses a binary bitwise (or eager logical) xor expression (with Pratt parsing). - AST::ArithmeticOrLogicalExpr* Parser::parse_bitwise_xor_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::ArithmeticOrLogicalExpr> Parser::parse_bitwise_xor_expr( + const_TokenPtr tok ATTRIBUTE_UNUSED, ::std::unique_ptr<AST::Expr> left, + ::std::vector<AST::Attribute> outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) { // parse RHS (as tok has already been consumed in parse_expression) - AST::Expr* right = parse_expr(LBP_CARET); + ::std::unique_ptr<AST::Expr> right + = parse_expr(LBP_CARET, ::std::vector<AST::Attribute>(), restrictions); if (right == NULL) return NULL; // TODO: check types. actually, do so during semantic analysis + location_t locus = left->get_locus_slow(); - return new AST::ArithmeticOrLogicalExpr( - left, right, AST::ArithmeticOrLogicalExpr::BITWISE_XOR); + return ::std::unique_ptr<AST::ArithmeticOrLogicalExpr>(new AST::ArithmeticOrLogicalExpr( + ::std::move(left), ::std::move(right), AST::ArithmeticOrLogicalExpr::BITWISE_XOR, locus)); } // Parses a binary left shift expression (with Pratt parsing). - AST::ArithmeticOrLogicalExpr* Parser::parse_left_shift_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::ArithmeticOrLogicalExpr> Parser::parse_left_shift_expr( + const_TokenPtr tok ATTRIBUTE_UNUSED, ::std::unique_ptr<AST::Expr> left, + ::std::vector<AST::Attribute> outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) { // parse RHS (as tok has already been consumed in parse_expression) - AST::Expr* right = parse_expr(LBP_L_SHIFT); + ::std::unique_ptr<AST::Expr> right + = parse_expr(LBP_L_SHIFT, ::std::vector<AST::Attribute>(), restrictions); if (right == NULL) return NULL; // TODO: check types. actually, do so during semantic analysis + location_t locus = left->get_locus_slow(); - return new AST::ArithmeticOrLogicalExpr( - left, right, AST::ArithmeticOrLogicalExpr::LEFT_SHIFT); + return ::std::unique_ptr<AST::ArithmeticOrLogicalExpr>(new AST::ArithmeticOrLogicalExpr( + ::std::move(left), ::std::move(right), AST::ArithmeticOrLogicalExpr::LEFT_SHIFT, locus)); } // Parses a binary right shift expression (with Pratt parsing). - AST::ArithmeticOrLogicalExpr* Parser::parse_right_shift_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::ArithmeticOrLogicalExpr> Parser::parse_right_shift_expr( + const_TokenPtr tok ATTRIBUTE_UNUSED, ::std::unique_ptr<AST::Expr> left, + ::std::vector<AST::Attribute> outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) { // parse RHS (as tok has already been consumed in parse_expression) - AST::Expr* right = parse_expr(LBP_R_SHIFT); + ::std::unique_ptr<AST::Expr> right + = parse_expr(LBP_R_SHIFT, ::std::vector<AST::Attribute>(), restrictions); if (right == NULL) return NULL; // TODO: check types. actually, do so during semantic analysis + location_t locus = left->get_locus_slow(); - return new AST::ArithmeticOrLogicalExpr( - left, right, AST::ArithmeticOrLogicalExpr::RIGHT_SHIFT); + return ::std::unique_ptr<AST::ArithmeticOrLogicalExpr>(new AST::ArithmeticOrLogicalExpr( + ::std::move(left), ::std::move(right), AST::ArithmeticOrLogicalExpr::RIGHT_SHIFT, locus)); } // Parses a binary equal to expression (with Pratt parsing). - AST::ComparisonExpr* Parser::parse_binary_equal_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::ComparisonExpr> Parser::parse_binary_equal_expr( + const_TokenPtr tok ATTRIBUTE_UNUSED, ::std::unique_ptr<AST::Expr> left, + ::std::vector<AST::Attribute> outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) { // parse RHS (as tok has already been consumed in parse_expression) - AST::Expr* right = parse_expr(LBP_EQUAL); + ::std::unique_ptr<AST::Expr> right + = parse_expr(LBP_EQUAL, ::std::vector<AST::Attribute>(), restrictions); if (right == NULL) return NULL; // TODO: check types. actually, do so during semantic analysis + location_t locus = left->get_locus_slow(); - return new AST::ComparisonExpr(left, right, AST::ComparisonExpr::EQUAL); + return ::std::unique_ptr<AST::ComparisonExpr>(new AST::ComparisonExpr( + ::std::move(left), ::std::move(right), AST::ComparisonExpr::EQUAL, locus)); } // Parses a binary not equal to expression (with Pratt parsing). - AST::ComparisonExpr* Parser::parse_binary_not_equal_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::ComparisonExpr> Parser::parse_binary_not_equal_expr( + const_TokenPtr tok ATTRIBUTE_UNUSED, ::std::unique_ptr<AST::Expr> left, + ::std::vector<AST::Attribute> outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) { // parse RHS (as tok has already been consumed in parse_expression) - AST::Expr* right = parse_expr(LBP_NOT_EQUAL); + ::std::unique_ptr<AST::Expr> right + = parse_expr(LBP_NOT_EQUAL, ::std::vector<AST::Attribute>(), restrictions); if (right == NULL) return NULL; // TODO: check types. actually, do so during semantic analysis + location_t locus = left->get_locus_slow(); - return new AST::ComparisonExpr(left, right, AST::ComparisonExpr::NOT_EQUAL); + return ::std::unique_ptr<AST::ComparisonExpr>(new AST::ComparisonExpr( + ::std::move(left), ::std::move(right), AST::ComparisonExpr::NOT_EQUAL, locus)); } // Parses a binary greater than expression (with Pratt parsing). - AST::ComparisonExpr* Parser::parse_binary_greater_than_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::ComparisonExpr> Parser::parse_binary_greater_than_expr( + const_TokenPtr tok ATTRIBUTE_UNUSED, ::std::unique_ptr<AST::Expr> left, + ::std::vector<AST::Attribute> outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) { // parse RHS (as tok has already been consumed in parse_expression) - AST::Expr* right = parse_expr(LBP_GREATER_THAN); + ::std::unique_ptr<AST::Expr> right + = parse_expr(LBP_GREATER_THAN, ::std::vector<AST::Attribute>(), restrictions); if (right == NULL) return NULL; // TODO: check types. actually, do so during semantic analysis + location_t locus = left->get_locus_slow(); - return new AST::ComparisonExpr(left, right, AST::ComparisonExpr::GREATER_THAN); + return ::std::unique_ptr<AST::ComparisonExpr>(new AST::ComparisonExpr( + ::std::move(left), ::std::move(right), AST::ComparisonExpr::GREATER_THAN, locus)); } // Parses a binary less than expression (with Pratt parsing). - AST::ComparisonExpr* Parser::parse_binary_less_than_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::ComparisonExpr> Parser::parse_binary_less_than_expr( + const_TokenPtr tok ATTRIBUTE_UNUSED, ::std::unique_ptr<AST::Expr> left, + ::std::vector<AST::Attribute> outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) { // parse RHS (as tok has already been consumed in parse_expression) - AST::Expr* right = parse_expr(LBP_SMALLER_THAN); + ::std::unique_ptr<AST::Expr> right + = parse_expr(LBP_SMALLER_THAN, ::std::vector<AST::Attribute>(), restrictions); if (right == NULL) return NULL; // TODO: check types. actually, do so during semantic analysis + location_t locus = left->get_locus_slow(); - return new AST::ComparisonExpr(left, right, AST::ComparisonExpr::LESS_THAN); + return ::std::unique_ptr<AST::ComparisonExpr>(new AST::ComparisonExpr( + ::std::move(left), ::std::move(right), AST::ComparisonExpr::LESS_THAN, locus)); } // Parses a binary greater than or equal to expression (with Pratt parsing). - AST::ComparisonExpr* Parser::parse_binary_greater_equal_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::ComparisonExpr> Parser::parse_binary_greater_equal_expr( + const_TokenPtr tok ATTRIBUTE_UNUSED, ::std::unique_ptr<AST::Expr> left, + ::std::vector<AST::Attribute> outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) { // parse RHS (as tok has already been consumed in parse_expression) - AST::Expr* right = parse_expr(LBP_GREATER_EQUAL); + ::std::unique_ptr<AST::Expr> right + = parse_expr(LBP_GREATER_EQUAL, ::std::vector<AST::Attribute>(), restrictions); if (right == NULL) return NULL; // TODO: check types. actually, do so during semantic analysis + location_t locus = left->get_locus_slow(); - return new AST::ComparisonExpr(left, right, AST::ComparisonExpr::GREATER_OR_EQUAL); + return ::std::unique_ptr<AST::ComparisonExpr>(new AST::ComparisonExpr( + ::std::move(left), ::std::move(right), AST::ComparisonExpr::GREATER_OR_EQUAL, locus)); } // Parses a binary less than or equal to expression (with Pratt parsing). - AST::ComparisonExpr* Parser::parse_binary_less_equal_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::ComparisonExpr> Parser::parse_binary_less_equal_expr( + const_TokenPtr tok ATTRIBUTE_UNUSED, ::std::unique_ptr<AST::Expr> left, + ::std::vector<AST::Attribute> outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) { // parse RHS (as tok has already been consumed in parse_expression) - AST::Expr* right = parse_expr(LBP_SMALLER_EQUAL); + ::std::unique_ptr<AST::Expr> right + = parse_expr(LBP_SMALLER_EQUAL, ::std::vector<AST::Attribute>(), restrictions); if (right == NULL) return NULL; // TODO: check types. actually, do so during semantic analysis + location_t locus = left->get_locus_slow(); - return new AST::ComparisonExpr(left, right, AST::ComparisonExpr::LESS_OR_EQUAL); + return ::std::unique_ptr<AST::ComparisonExpr>(new AST::ComparisonExpr( + ::std::move(left), ::std::move(right), AST::ComparisonExpr::LESS_OR_EQUAL, locus)); } // Parses a binary lazy boolean or expression (with Pratt parsing). - AST::LazyBooleanExpr* Parser::parse_lazy_or_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::LazyBooleanExpr> Parser::parse_lazy_or_expr( + const_TokenPtr tok ATTRIBUTE_UNUSED, ::std::unique_ptr<AST::Expr> left, + ::std::vector<AST::Attribute> outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) { // parse RHS (as tok has already been consumed in parse_expression) - AST::Expr* right = parse_expr(LBP_LOGICAL_OR); + ::std::unique_ptr<AST::Expr> right + = parse_expr(LBP_LOGICAL_OR, ::std::vector<AST::Attribute>(), restrictions); if (right == NULL) return NULL; // TODO: check types. actually, do so during semantic analysis + location_t locus = left->get_locus_slow(); - return new AST::LazyBooleanExpr(left, right, AST::LazyBooleanExpr::LOGICAL_OR); + return ::std::unique_ptr<AST::LazyBooleanExpr>(new AST::LazyBooleanExpr( + ::std::move(left), ::std::move(right), AST::LazyBooleanExpr::LOGICAL_OR, locus)); } // Parses a binary lazy boolean and expression (with Pratt parsing). - AST::LazyBooleanExpr* Parser::parse_lazy_and_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::LazyBooleanExpr> Parser::parse_lazy_and_expr( + const_TokenPtr tok ATTRIBUTE_UNUSED, ::std::unique_ptr<AST::Expr> left, + ::std::vector<AST::Attribute> outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) { // parse RHS (as tok has already been consumed in parse_expression) - AST::Expr* right = parse_expr(LBP_LOGICAL_AND); + ::std::unique_ptr<AST::Expr> right + = parse_expr(LBP_LOGICAL_AND, ::std::vector<AST::Attribute>(), restrictions); if (right == NULL) return NULL; // TODO: check types. actually, do so during semantic analysis + location_t locus = left->get_locus_slow(); - return new AST::LazyBooleanExpr(left, right, AST::LazyBooleanExpr::LOGICAL_AND); + return ::std::unique_ptr<AST::LazyBooleanExpr>(new AST::LazyBooleanExpr( + ::std::move(left), ::std::move(right), AST::LazyBooleanExpr::LOGICAL_AND, locus)); } // Parses a pseudo-binary infix type cast expression (with Pratt parsing). - AST::TypeCastExpr* Parser::parse_type_cast_expr( - const_TokenPtr tok, AST::Expr* expr_to_cast, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::TypeCastExpr> Parser::parse_type_cast_expr( + const_TokenPtr tok ATTRIBUTE_UNUSED, ::std::unique_ptr<AST::Expr> expr_to_cast, + ::std::vector<AST::Attribute> outer_attrs ATTRIBUTE_UNUSED, + ParseRestrictions restrictions ATTRIBUTE_UNUSED) { // parse RHS (as tok has already been consumed in parse_expression) - AST::TypeNoBounds* type = parse_type_no_bounds(); + ::std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds(); if (type == NULL) return NULL; // FIXME: how do I get precedence put in here? // TODO: check types. actually, do so during semantic analysis + location_t locus = expr_to_cast->get_locus_slow(); - return new AST::TypeCastExpr(expr_to_cast, type); + return ::std::unique_ptr<AST::TypeCastExpr>( + new AST::TypeCastExpr(::std::move(expr_to_cast), ::std::move(type), locus)); } // Parses a binary assignment expression (with Pratt parsing). - AST::AssignmentExpr* Parser::parse_assig_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::AssignmentExpr> Parser::parse_assig_expr( + const_TokenPtr tok ATTRIBUTE_UNUSED, ::std::unique_ptr<AST::Expr> left, + ::std::vector<AST::Attribute> outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) { // parse RHS (as tok has already been consumed in parse_expression) - AST::Expr* right = parse_expr(LBP_ASSIG - 1); + ::std::unique_ptr<AST::Expr> right + = parse_expr(LBP_ASSIG - 1, ::std::vector<AST::Attribute>(), restrictions); if (right == NULL) return NULL; // FIXME: ensure right-associativity for this - 'LBP - 1' may do this? // TODO: check types. actually, do so during semantic analysis + location_t locus = left->get_locus_slow(); - return new AST::AssignmentExpr(left, right); + return ::std::unique_ptr<AST::AssignmentExpr>( + new AST::AssignmentExpr(::std::move(left), ::std::move(right), locus)); } // Parses a binary add-assignment expression (with Pratt parsing). - AST::CompoundAssignmentExpr* Parser::parse_plus_assig_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::CompoundAssignmentExpr> Parser::parse_plus_assig_expr( + const_TokenPtr tok ATTRIBUTE_UNUSED, ::std::unique_ptr<AST::Expr> left, + ::std::vector<AST::Attribute> outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) { // parse RHS (as tok has already been consumed in parse_expression) - AST::Expr* right = parse_expr(LBP_PLUS_ASSIG - 1); + ::std::unique_ptr<AST::Expr> right + = parse_expr(LBP_PLUS_ASSIG - 1, ::std::vector<AST::Attribute>(), restrictions); if (right == NULL) return NULL; // FIXME: ensure right-associativity for this - 'LBP - 1' may do this? // TODO: check types. actually, do so during semantic analysis + location_t locus = left->get_locus_slow(); - return new AST::CompoundAssignmentExpr(left, right, AST::CompoundAssignmentExpr::ADD); + return ::std::unique_ptr<AST::CompoundAssignmentExpr>(new AST::CompoundAssignmentExpr( + ::std::move(left), ::std::move(right), AST::CompoundAssignmentExpr::ADD, locus)); } // Parses a binary minus-assignment expression (with Pratt parsing). - AST::CompoundAssignmentExpr* Parser::parse_minus_assig_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::CompoundAssignmentExpr> Parser::parse_minus_assig_expr( + const_TokenPtr tok ATTRIBUTE_UNUSED, ::std::unique_ptr<AST::Expr> left, + ::std::vector<AST::Attribute> outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) { // parse RHS (as tok has already been consumed in parse_expression) - AST::Expr* right = parse_expr(LBP_MINUS_ASSIG - 1); + ::std::unique_ptr<AST::Expr> right + = parse_expr(LBP_MINUS_ASSIG - 1, ::std::vector<AST::Attribute>(), restrictions); if (right == NULL) return NULL; // FIXME: ensure right-associativity for this - 'LBP - 1' may do this? // TODO: check types. actually, do so during semantic analysis + location_t locus = left->get_locus_slow(); - return new AST::CompoundAssignmentExpr(left, right, AST::CompoundAssignmentExpr::SUBTRACT); + return ::std::unique_ptr<AST::CompoundAssignmentExpr>(new AST::CompoundAssignmentExpr( + ::std::move(left), ::std::move(right), AST::CompoundAssignmentExpr::SUBTRACT, locus)); } // Parses a binary multiplication-assignment expression (with Pratt parsing). - AST::CompoundAssignmentExpr* Parser::parse_mult_assig_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::CompoundAssignmentExpr> Parser::parse_mult_assig_expr( + const_TokenPtr tok ATTRIBUTE_UNUSED, ::std::unique_ptr<AST::Expr> left, + ::std::vector<AST::Attribute> outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) { // parse RHS (as tok has already been consumed in parse_expression) - AST::Expr* right = parse_expr(LBP_MULT_ASSIG - 1); + ::std::unique_ptr<AST::Expr> right + = parse_expr(LBP_MULT_ASSIG - 1, ::std::vector<AST::Attribute>(), restrictions); if (right == NULL) return NULL; // FIXME: ensure right-associativity for this - 'LBP - 1' may do this? // TODO: check types. actually, do so during semantic analysis + location_t locus = left->get_locus_slow(); - return new AST::CompoundAssignmentExpr(left, right, AST::CompoundAssignmentExpr::MULTIPLY); + return ::std::unique_ptr<AST::CompoundAssignmentExpr>(new AST::CompoundAssignmentExpr( + ::std::move(left), ::std::move(right), AST::CompoundAssignmentExpr::MULTIPLY, locus)); } // Parses a binary division-assignment expression (with Pratt parsing). - AST::CompoundAssignmentExpr* Parser::parse_div_assig_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::CompoundAssignmentExpr> Parser::parse_div_assig_expr( + const_TokenPtr tok ATTRIBUTE_UNUSED, ::std::unique_ptr<AST::Expr> left, + ::std::vector<AST::Attribute> outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) { // parse RHS (as tok has already been consumed in parse_expression) - AST::Expr* right = parse_expr(LBP_DIV_ASSIG - 1); + ::std::unique_ptr<AST::Expr> right + = parse_expr(LBP_DIV_ASSIG - 1, ::std::vector<AST::Attribute>(), restrictions); if (right == NULL) return NULL; // FIXME: ensure right-associativity for this - 'LBP - 1' may do this? // TODO: check types. actually, do so during semantic analysis + location_t locus = left->get_locus_slow(); - return new AST::CompoundAssignmentExpr(left, right, AST::CompoundAssignmentExpr::DIVIDE); + return ::std::unique_ptr<AST::CompoundAssignmentExpr>(new AST::CompoundAssignmentExpr( + ::std::move(left), ::std::move(right), AST::CompoundAssignmentExpr::DIVIDE, locus)); } // Parses a binary modulo-assignment expression (with Pratt parsing). - AST::CompoundAssignmentExpr* Parser::parse_mod_assig_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::CompoundAssignmentExpr> Parser::parse_mod_assig_expr( + const_TokenPtr tok ATTRIBUTE_UNUSED, ::std::unique_ptr<AST::Expr> left, + ::std::vector<AST::Attribute> outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) { // parse RHS (as tok has already been consumed in parse_expression) - AST::Expr* right = parse_expr(LBP_MOD_ASSIG - 1); + ::std::unique_ptr<AST::Expr> right + = parse_expr(LBP_MOD_ASSIG - 1, ::std::vector<AST::Attribute>(), restrictions); if (right == NULL) return NULL; // FIXME: ensure right-associativity for this - 'LBP - 1' may do this? // TODO: check types. actually, do so during semantic analysis + location_t locus = left->get_locus_slow(); - return new AST::CompoundAssignmentExpr(left, right, AST::CompoundAssignmentExpr::MODULUS); + return ::std::unique_ptr<AST::CompoundAssignmentExpr>(new AST::CompoundAssignmentExpr( + ::std::move(left), ::std::move(right), AST::CompoundAssignmentExpr::MODULUS, locus)); } // Parses a binary and-assignment expression (with Pratt parsing). - AST::CompoundAssignmentExpr* Parser::parse_and_assig_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::CompoundAssignmentExpr> Parser::parse_and_assig_expr( + const_TokenPtr tok ATTRIBUTE_UNUSED, ::std::unique_ptr<AST::Expr> left, + ::std::vector<AST::Attribute> outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) { // parse RHS (as tok has already been consumed in parse_expression) - AST::Expr* right = parse_expr(LBP_AMP_ASSIG - 1); + ::std::unique_ptr<AST::Expr> right + = parse_expr(LBP_AMP_ASSIG - 1, ::std::vector<AST::Attribute>(), restrictions); if (right == NULL) return NULL; // FIXME: ensure right-associativity for this - 'LBP - 1' may do this? // TODO: check types. actually, do so during semantic analysis + location_t locus = left->get_locus_slow(); - return new AST::CompoundAssignmentExpr(left, right, AST::CompoundAssignmentExpr::BITWISE_AND); + return ::std::unique_ptr<AST::CompoundAssignmentExpr>(new AST::CompoundAssignmentExpr( + ::std::move(left), ::std::move(right), AST::CompoundAssignmentExpr::BITWISE_AND, locus)); } // Parses a binary or-assignment expression (with Pratt parsing). - AST::CompoundAssignmentExpr* Parser::parse_or_assig_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::CompoundAssignmentExpr> Parser::parse_or_assig_expr( + const_TokenPtr tok ATTRIBUTE_UNUSED, ::std::unique_ptr<AST::Expr> left, + ::std::vector<AST::Attribute> outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) { // parse RHS (as tok has already been consumed in parse_expression) - AST::Expr* right = parse_expr(LBP_PIPE_ASSIG - 1); + ::std::unique_ptr<AST::Expr> right + = parse_expr(LBP_PIPE_ASSIG - 1, ::std::vector<AST::Attribute>(), restrictions); if (right == NULL) return NULL; // FIXME: ensure right-associativity for this - 'LBP - 1' may do this? // TODO: check types. actually, do so during semantic analysis + location_t locus = left->get_locus_slow(); - return new AST::CompoundAssignmentExpr(left, right, AST::CompoundAssignmentExpr::BITWISE_OR); + return ::std::unique_ptr<AST::CompoundAssignmentExpr>(new AST::CompoundAssignmentExpr( + ::std::move(left), ::std::move(right), AST::CompoundAssignmentExpr::BITWISE_OR, locus)); } // Parses a binary xor-assignment expression (with Pratt parsing). - AST::CompoundAssignmentExpr* Parser::parse_xor_assig_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::CompoundAssignmentExpr> Parser::parse_xor_assig_expr( + const_TokenPtr tok ATTRIBUTE_UNUSED, ::std::unique_ptr<AST::Expr> left, + ::std::vector<AST::Attribute> outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) { // parse RHS (as tok has already been consumed in parse_expression) - AST::Expr* right = parse_expr(LBP_CARET_ASSIG - 1); + ::std::unique_ptr<AST::Expr> right + = parse_expr(LBP_CARET_ASSIG - 1, ::std::vector<AST::Attribute>(), restrictions); if (right == NULL) return NULL; // FIXME: ensure right-associativity for this - 'LBP - 1' may do this? // TODO: check types. actually, do so during semantic analysis + location_t locus = left->get_locus_slow(); - return new AST::CompoundAssignmentExpr(left, right, AST::CompoundAssignmentExpr::BITWISE_XOR); + return ::std::unique_ptr<AST::CompoundAssignmentExpr>(new AST::CompoundAssignmentExpr( + ::std::move(left), ::std::move(right), AST::CompoundAssignmentExpr::BITWISE_XOR, locus)); } // Parses a binary left shift-assignment expression (with Pratt parsing). - AST::CompoundAssignmentExpr* Parser::parse_left_shift_assig_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::CompoundAssignmentExpr> Parser::parse_left_shift_assig_expr( + const_TokenPtr tok ATTRIBUTE_UNUSED, ::std::unique_ptr<AST::Expr> left, + ::std::vector<AST::Attribute> outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) { // parse RHS (as tok has already been consumed in parse_expression) - AST::Expr* right = parse_expr(LBP_L_SHIFT_ASSIG - 1); + ::std::unique_ptr<AST::Expr> right + = parse_expr(LBP_L_SHIFT_ASSIG - 1, ::std::vector<AST::Attribute>(), restrictions); if (right == NULL) return NULL; // FIXME: ensure right-associativity for this - 'LBP - 1' may do this? // TODO: check types. actually, do so during semantic analysis + location_t locus = left->get_locus_slow(); - return new AST::CompoundAssignmentExpr(left, right, AST::CompoundAssignmentExpr::LEFT_SHIFT); + return ::std::unique_ptr<AST::CompoundAssignmentExpr>(new AST::CompoundAssignmentExpr( + ::std::move(left), ::std::move(right), AST::CompoundAssignmentExpr::LEFT_SHIFT, locus)); } // Parses a binary right shift-assignment expression (with Pratt parsing). - AST::CompoundAssignmentExpr* Parser::parse_right_shift_assig_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::CompoundAssignmentExpr> Parser::parse_right_shift_assig_expr( + const_TokenPtr tok ATTRIBUTE_UNUSED, ::std::unique_ptr<AST::Expr> left, + ::std::vector<AST::Attribute> outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) { // parse RHS (as tok has already been consumed in parse_expression) - AST::Expr* right = parse_expr(LBP_R_SHIFT_ASSIG - 1); + ::std::unique_ptr<AST::Expr> right + = parse_expr(LBP_R_SHIFT_ASSIG - 1, ::std::vector<AST::Attribute>(), restrictions); if (right == NULL) return NULL; // FIXME: ensure right-associativity for this - 'LBP - 1' may do this? // TODO: check types. actually, do so during semantic analysis + location_t locus = left->get_locus_slow(); - return new AST::CompoundAssignmentExpr(left, right, AST::CompoundAssignmentExpr::RIGHT_SHIFT); + return ::std::unique_ptr<AST::CompoundAssignmentExpr>(new AST::CompoundAssignmentExpr( + ::std::move(left), ::std::move(right), AST::CompoundAssignmentExpr::RIGHT_SHIFT, locus)); } // Parses a postfix unary await expression (with Pratt parsing). - AST::AwaitExpr* Parser::parse_await_expr( - const_TokenPtr tok, AST::Expr* expr_to_await, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::AwaitExpr> Parser::parse_await_expr(const_TokenPtr tok, + ::std::unique_ptr<AST::Expr> expr_to_await, ::std::vector<AST::Attribute> outer_attrs) { // skip "await" identifier (as "." has already been consumed in parse_expression) // this assumes that the identifier was already identified as await if (!skip_token(IDENTIFIER)) { @@ -9407,88 +11077,115 @@ namespace Rust { } // TODO: check inside async block in semantic analysis + location_t locus = expr_to_await->get_locus_slow(); - return new AST::AwaitExpr(expr_to_await, ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::AwaitExpr>( + new AST::AwaitExpr(::std::move(expr_to_await), ::std::move(outer_attrs), locus)); } /* Parses an exclusive range ('..') in left denotation position (i.e. RangeFromExpr or * RangeFromToExpr). */ - AST::RangeExpr* Parser::parse_led_range_exclusive_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::RangeExpr> Parser::parse_led_range_exclusive_expr( + const_TokenPtr tok ATTRIBUTE_UNUSED, ::std::unique_ptr<AST::Expr> left, + ::std::vector<AST::Attribute> outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) { // FIXME: this probably parses expressions accidently or whatever // try parsing RHS (as tok has already been consumed in parse_expression) - AST::Expr* right = parse_expr(LBP_DOT_DOT); + ::std::unique_ptr<AST::Expr> right + = parse_expr(LBP_DOT_DOT, ::std::vector<AST::Attribute>(), restrictions); + + location_t locus = left->get_locus_slow(); + if (right == NULL) { // range from expr - return new AST::RangeFromExpr(left); + return ::std::unique_ptr<AST::RangeFromExpr>( + new AST::RangeFromExpr(::std::move(left), locus)); } else { - return new AST::RangeFromToExpr(left, right); + return ::std::unique_ptr<AST::RangeFromToExpr>( + new AST::RangeFromToExpr(::std::move(left), ::std::move(right), locus)); } // FIXME: make non-associative } /* Parses an exclusive range ('..') in null denotation position (i.e. RangeToExpr or * RangeFullExpr). */ - AST::RangeExpr* Parser::parse_nud_range_exclusive_expr( - const_TokenPtr tok, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::RangeExpr> Parser::parse_nud_range_exclusive_expr( + const_TokenPtr tok, ::std::vector<AST::Attribute> outer_attrs ATTRIBUTE_UNUSED) { // FIXME: this probably parses expressions accidently or whatever // try parsing RHS (as tok has already been consumed in parse_expression) - AST::Expr* right = parse_expr(LBP_DOT_DOT); + ::std::unique_ptr<AST::Expr> right = parse_expr(LBP_DOT_DOT, ::std::vector<AST::Attribute>()); + + location_t locus = tok->get_locus(); + if (right == NULL) { // range from expr - return new AST::RangeFullExpr(); + return ::std::unique_ptr<AST::RangeFullExpr>(new AST::RangeFullExpr(locus)); } else { - return new AST::RangeToExpr(right); + return ::std::unique_ptr<AST::RangeToExpr>( + new AST::RangeToExpr(::std::move(right), locus)); } // FIXME: make non-associative } // Parses a full binary range inclusive expression. - AST::RangeFromToInclExpr* Parser::parse_range_inclusive_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::RangeFromToInclExpr> Parser::parse_range_inclusive_expr( + const_TokenPtr tok ATTRIBUTE_UNUSED, ::std::unique_ptr<AST::Expr> left, + ::std::vector<AST::Attribute> outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) { // parse RHS (as tok has already been consumed in parse_expression) - AST::Expr* right = parse_expr(LBP_DOT_DOT_EQ); + ::std::unique_ptr<AST::Expr> right + = parse_expr(LBP_DOT_DOT_EQ, ::std::vector<AST::Attribute>(), restrictions); if (right == NULL) return NULL; // FIXME: make non-associative // TODO: check types. actually, do so during semantic analysis + location_t locus = left->get_locus_slow(); - return new AST::RangeFromToInclExpr(left, right); + return ::std::unique_ptr<AST::RangeFromToInclExpr>( + new AST::RangeFromToInclExpr(::std::move(left), ::std::move(right), locus)); } // Parses an inclusive range-to prefix unary expression. - AST::RangeToInclExpr* Parser::parse_range_to_inclusive_expr( - const_TokenPtr tok, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::RangeToInclExpr> Parser::parse_range_to_inclusive_expr( + const_TokenPtr tok, ::std::vector<AST::Attribute> outer_attrs ATTRIBUTE_UNUSED) { // parse RHS (as tok has already been consumed in parse_expression) - AST::Expr* right = parse_expr(LBP_DOT_DOT_EQ); + ::std::unique_ptr<AST::Expr> right = parse_expr(LBP_DOT_DOT_EQ); if (right == NULL) return NULL; // FIXME: make non-associative // TODO: check types. actually, do so during semantic analysis - return new AST::RangeToInclExpr(right); + return ::std::unique_ptr<AST::RangeToInclExpr>( + new AST::RangeToInclExpr(::std::move(right), tok->get_locus())); } // Parses a pseudo-binary infix tuple index expression. - AST::TupleIndexExpr* Parser::parse_tuple_index_expr( - const_TokenPtr tok, AST::Expr* tuple_expr, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::TupleIndexExpr> Parser::parse_tuple_index_expr( + const_TokenPtr tok ATTRIBUTE_UNUSED, ::std::unique_ptr<AST::Expr> tuple_expr, + ::std::vector<AST::Attribute> outer_attrs, ParseRestrictions restrictions ATTRIBUTE_UNUSED) { // parse int literal (as token already skipped) const_TokenPtr index_tok = expect_token(INT_LITERAL); + if (index_tok == NULL) { + return NULL; + } ::std::string index = index_tok->get_str(); // convert to integer int index_int = atoi(index.c_str()); - return new AST::TupleIndexExpr(tuple_expr, index_int, ::std::move(outer_attrs)); + location_t locus = tuple_expr->get_locus_slow(); + + return ::std::unique_ptr<AST::TupleIndexExpr>(new AST::TupleIndexExpr( + ::std::move(tuple_expr), index_int, ::std::move(outer_attrs), locus)); } // Parses a pseudo-binary infix array (or slice) index expression. - AST::ArrayIndexExpr* Parser::parse_index_expr( - const_TokenPtr tok, AST::Expr* array_expr, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::ArrayIndexExpr> Parser::parse_index_expr( + const_TokenPtr tok ATTRIBUTE_UNUSED, ::std::unique_ptr<AST::Expr> array_expr, + ::std::vector<AST::Attribute> outer_attrs, ParseRestrictions restrictions) { // parse RHS (as tok has already been consumed in parse_expression) - AST::Expr* index_expr = parse_expr(LBP_ARRAY_REF); + ::std::unique_ptr<AST::Expr> index_expr + = parse_expr(LBP_ARRAY_REF, ::std::vector<AST::Attribute>(), restrictions); if (index_expr == NULL) return NULL; @@ -9499,24 +11196,31 @@ namespace Rust { } // TODO: check types. actually, do so during semantic analysis + location_t locus = array_expr->get_locus_slow(); - return new AST::ArrayIndexExpr(array_expr, index_expr, ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::ArrayIndexExpr>(new AST::ArrayIndexExpr( + ::std::move(array_expr), ::std::move(index_expr), ::std::move(outer_attrs), locus)); } // Parses a pseudo-binary infix struct field access expression. - AST::FieldAccessExpr* Parser::parse_field_access_expr( - const_TokenPtr tok, AST::Expr* struct_expr, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::FieldAccessExpr> Parser::parse_field_access_expr( + const_TokenPtr tok ATTRIBUTE_UNUSED, ::std::unique_ptr<AST::Expr> struct_expr, + ::std::vector<AST::Attribute> outer_attrs, ParseRestrictions restrictions ATTRIBUTE_UNUSED) { // get field name identifier (assume that this is a field access expr and not say await) const_TokenPtr ident_tok = expect_token(IDENTIFIER); Identifier ident = ident_tok->get_str(); + location_t locus = struct_expr->get_locus_slow(); + // TODO: check types. actually, do so during semantic analysis - return new AST::FieldAccessExpr(struct_expr, ident, ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::FieldAccessExpr>(new AST::FieldAccessExpr( + ::std::move(struct_expr), ::std::move(ident), ::std::move(outer_attrs), locus)); } // Parses a pseudo-binary infix method call expression. - AST::MethodCallExpr* Parser::parse_method_call_expr( - const_TokenPtr tok, AST::Expr* receiver_expr, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::MethodCallExpr> Parser::parse_method_call_expr(const_TokenPtr tok, + ::std::unique_ptr<AST::Expr> receiver_expr, ::std::vector<AST::Attribute> outer_attrs, + ParseRestrictions restrictions ATTRIBUTE_UNUSED) { // parse path expr segment AST::PathExprSegment segment = parse_path_expr_segment(); if (segment.is_error()) { @@ -9534,12 +11238,12 @@ namespace Rust { const_TokenPtr t = lexer.peek_token(); while (t->get_id() != RIGHT_PAREN) { - AST::Expr* param = parse_expr(); + ::std::unique_ptr<AST::Expr> param = parse_expr(); if (param == NULL) { error_at(t->get_locus(), "failed to parse method param in method call"); return NULL; } - params.push_back(::std::unique_ptr<AST::Expr>(param)); + params.push_back(::std::move(param)); if (lexer.peek_token()->get_id() != COMMA) { break; @@ -9555,25 +11259,28 @@ namespace Rust { } // TODO: check types. actually do so in semantic analysis pass. + location_t locus = receiver_expr->get_locus_slow(); - return new AST::MethodCallExpr( - receiver_expr, ::std::move(segment), ::std::move(params), ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::MethodCallExpr>( + new AST::MethodCallExpr(::std::move(receiver_expr), ::std::move(segment), + ::std::move(params), ::std::move(outer_attrs), locus)); } // Parses a pseudo-binary infix function call expression. - AST::CallExpr* Parser::parse_function_call_expr( - const_TokenPtr tok, AST::Expr* function_expr, ::std::vector<AST::Attribute> outer_attrs) { + ::std::unique_ptr<AST::CallExpr> Parser::parse_function_call_expr( + const_TokenPtr tok ATTRIBUTE_UNUSED, ::std::unique_ptr<AST::Expr> function_expr, + ::std::vector<AST::Attribute> outer_attrs, ParseRestrictions restrictions ATTRIBUTE_UNUSED) { // parse function params (if they exist) ::std::vector< ::std::unique_ptr<AST::Expr> > params; const_TokenPtr t = lexer.peek_token(); while (t->get_id() != RIGHT_PAREN) { - AST::Expr* param = parse_expr(); + ::std::unique_ptr<AST::Expr> param = parse_expr(); if (param == NULL) { error_at(t->get_locus(), "failed to parse function param in function call"); return NULL; } - params.push_back(::std::unique_ptr<AST::Expr>(param)); + params.push_back(::std::move(param)); if (lexer.peek_token()->get_id() != COMMA) { break; @@ -9590,8 +11297,404 @@ namespace Rust { } // TODO: check types. actually, do so during semantic analysis + location_t locus = function_expr->get_locus_slow(); + + return ::std::unique_ptr<AST::CallExpr>(new AST::CallExpr( + ::std::move(function_expr), ::std::move(params), ::std::move(outer_attrs), locus)); + } + + // Parses a macro invocation with a path in expression already parsed (but not '!' token). + ::std::unique_ptr<AST::MacroInvocation> Parser::parse_macro_invocation_partial( + AST::PathInExpression path, ::std::vector<AST::Attribute> outer_attrs) { + // macro invocation + if (!skip_token(EXCLAM)) { + return NULL; + } + + // convert PathInExpression to SimplePath - if this isn't possible, error + AST::SimplePath converted_path = path.as_simple_path(); + if (converted_path.is_empty()) { + error_at( + lexer.peek_token()->get_locus(), "failed to parse simple path in macro invocation"); + return NULL; + } + + AST::DelimTokenTree tok_tree = parse_delim_token_tree(); + + fprintf(stderr, "successfully parsed macro invocation (via partial)\n"); + + location_t macro_locus = converted_path.get_locus(); + + return ::std::unique_ptr<AST::MacroInvocation>(new AST::MacroInvocation( + ::std::move(converted_path), ::std::move(tok_tree), ::std::move(outer_attrs), macro_locus)); + } + + // Parses a struct expr struct with a path in expression already parsed (but not '{' token). + ::std::unique_ptr<AST::StructExprStruct> Parser::parse_struct_expr_struct_partial( + AST::PathInExpression path, ::std::vector<AST::Attribute> outer_attrs) { + // assume struct expr struct (as struct-enum disambiguation requires name + // lookup) again, make statement if final ';' + if (!skip_token(LEFT_CURLY)) { + return NULL; + } + + // parse inner attributes + ::std::vector<AST::Attribute> inner_attrs = parse_inner_attributes(); + + // branch based on next token + const_TokenPtr t = lexer.peek_token(); + location_t path_locus = path.get_locus(); + switch (t->get_id()) { + case RIGHT_CURLY: + // struct with no body + lexer.skip_token(); + + return ::std::unique_ptr<AST::StructExprStruct>(new AST::StructExprStruct( + ::std::move(path), ::std::move(inner_attrs), ::std::move(outer_attrs), path_locus)); + case DOT_DOT: + /* technically this would give a struct base-only struct, but this + * algorithm should work too. As such, AST type not happening. */ + case IDENTIFIER: + case INT_LITERAL: { + // struct with struct expr fields + + // parse struct expr fields + ::std::vector< ::std::unique_ptr<AST::StructExprField> > fields; + + while (t->get_id() != RIGHT_CURLY && t->get_id() != DOT_DOT) { + ::std::unique_ptr<AST::StructExprField> field = parse_struct_expr_field(); + if (field == NULL) { + error_at(t->get_locus(), "failed to parse struct (or enum) expr field"); + return NULL; + } + + // DEBUG: + fprintf(stderr, "struct/enum expr field validated to not be null \n"); + + fields.push_back(::std::move(field)); + + // DEBUG: + fprintf(stderr, "struct/enum expr field pushed back \n"); + + if (lexer.peek_token()->get_id() != COMMA) { + // DEBUG: + fprintf( + stderr, "lack of comma detected in struct/enum expr fields - break \n"); + break; + } + lexer.skip_token(); + + // DEBUG: + fprintf(stderr, "struct/enum expr fields comma skipped \n"); + + t = lexer.peek_token(); + } + + // DEBUG: + fprintf(stderr, "struct/enum expr about to parse struct base \n"); + + // parse struct base if it exists + AST::StructBase struct_base = AST::StructBase::error(); + if (lexer.peek_token()->get_id() == DOT_DOT) { + lexer.skip_token(); + + // parse required struct base expr + ::std::unique_ptr<AST::Expr> base_expr = parse_expr(); + if (base_expr == NULL) { + error_at(lexer.peek_token()->get_locus(), + "failed to parse struct base expression in struct " + "expression"); + return NULL; + } + + // DEBUG: + fprintf(stderr, "struct/enum expr - parsed and validated base expr \n"); + + struct_base = AST::StructBase(::std::move(base_expr)); + + // DEBUG: + fprintf(stderr, "assigned struct base to new struct base \n"); + } + + if (!skip_token(RIGHT_CURLY)) { + return NULL; + } + + // DEBUG: + fprintf(stderr, "struct/enum expr skipped right curly - done and ready to return \n"); + + return ::std::unique_ptr<AST::StructExprStructFields>( + new AST::StructExprStructFields(::std::move(path), ::std::move(fields), path_locus, + ::std::move(struct_base), ::std::move(inner_attrs), ::std::move(outer_attrs))); + } + default: + error_at(t->get_locus(), + "unrecognised token '%s' in struct (or enum) expression - " + "expected '}', identifier, int literal, or '..'", + t->get_token_description()); + return NULL; + } + } + + // Parses a struct expr tuple with a path in expression already parsed (but not '(' token). + ::std::unique_ptr<AST::StructExprTuple> Parser::parse_struct_expr_tuple_partial( + AST::PathInExpression path, ::std::vector<AST::Attribute> outer_attrs) { + if (!skip_token(LEFT_PAREN)) { + return NULL; + } + + ::std::vector<AST::Attribute> inner_attrs = parse_inner_attributes(); + + ::std::vector< ::std::unique_ptr<AST::Expr> > exprs; + + const_TokenPtr t = lexer.peek_token(); + while (t->get_id() != RIGHT_PAREN) { + // parse expression (required) + ::std::unique_ptr<AST::Expr> expr = parse_expr(); + if (expr == NULL) { + error_at(t->get_locus(), "failed to parse expression in struct " + "(or enum) expression tuple"); + return NULL; + } + exprs.push_back(::std::move(expr)); + + if (lexer.peek_token()->get_id() != COMMA) { + break; + } + lexer.skip_token(); + + t = lexer.peek_token(); + } + + if (!skip_token(RIGHT_PAREN)) { + return NULL; + } + + location_t path_locus = path.get_locus(); + + return ::std::unique_ptr<AST::StructExprTuple>(new AST::StructExprTuple(::std::move(path), + ::std::move(exprs), ::std::move(inner_attrs), ::std::move(outer_attrs), path_locus)); + } + + /* Parses a path in expression with the first token passed as a parameter (as it is skipped in + * token stream). Note that this only parses segment-first paths, not global ones. */ + AST::PathInExpression Parser::parse_path_in_expression_pratt(const_TokenPtr tok) { + // HACK-y way of making up for pratt-parsing consuming first token + + // DEBUG + fprintf(stderr, "current peek token when starting path pratt parse: '%s'\n", + lexer.peek_token()->get_token_description()); + + // create segment vector + ::std::vector<AST::PathExprSegment> segments; + + ::std::string initial_str; + + switch (tok->get_id()) { + case IDENTIFIER: + initial_str = tok->get_str(); + break; + case SUPER: + initial_str = "super"; + break; + case SELF: + initial_str = "self"; + break; + case SELF_ALIAS: + initial_str = "Self"; + break; + case CRATE: + initial_str = "crate"; + break; + case DOLLAR_SIGN: + if (lexer.peek_token()->get_id() == CRATE) { + initial_str = "$crate"; + break; + } + gcc_fallthrough(); + default: + error_at(tok->get_locus(), "unrecognised token '%s' in path in expression", + tok->get_token_description()); + return AST::PathInExpression::create_error(); + } + + // parse required initial segment + AST::PathExprSegment initial_segment(initial_str, tok->get_locus()); + // parse generic args (and turbofish), if they exist + /* use lookahead to determine if they actually exist (don't want to accidently parse + * over next ident segment) */ + if (lexer.peek_token()->get_id() == SCOPE_RESOLUTION + && lexer.peek_token(1)->get_id() == LEFT_ANGLE) { + // skip scope resolution + lexer.skip_token(); + + AST::GenericArgs generic_args = parse_path_generic_args(); + + initial_segment + = AST::PathExprSegment(initial_str, tok->get_locus(), ::std::move(generic_args)); + } + if (initial_segment.is_error()) { + // skip after somewhere? + // don't necessarily throw error but yeah + + // DEBUG + fprintf(stderr, "initial segment is error - returning null\n"); + + return AST::PathInExpression::create_error(); + } + segments.push_back(::std::move(initial_segment)); + + // parse optional segments (as long as scope resolution operator exists) + const_TokenPtr t = lexer.peek_token(); + while (t->get_id() == SCOPE_RESOLUTION) { + // skip scope resolution operator + lexer.skip_token(); + + // parse the actual segment - it is an error if it doesn't exist now + AST::PathExprSegment segment = parse_path_expr_segment(); + if (segment.is_error()) { + // skip after somewhere? + error_at(t->get_locus(), "could not parse path expression segment"); + return AST::PathInExpression::create_error(); + } + + segments.push_back(::std::move(segment)); + + t = lexer.peek_token(); + } + + // DEBUG: + fprintf(stderr, "current token (just about to return path to null denotation): '%s'\n", + lexer.peek_token()->get_token_description()); + + return AST::PathInExpression(::std::move(segments), tok->get_locus(), false); + } + + // Parses a closure expression with pratt parsing (from null denotation). + ::std::unique_ptr<AST::ClosureExpr> Parser::parse_closure_expr_pratt( + const_TokenPtr tok, ::std::vector<AST::Attribute> outer_attrs) { + // TODO: does this need pratt parsing (for precedence)? probably not, but idk + location_t locus = tok->get_locus(); + bool has_move = false; + if (tok->get_id() == MOVE) { + has_move = true; + tok = lexer.peek_token(); + lexer.skip_token(); + // skip token and reassign + } + + // handle parameter list + ::std::vector<AST::ClosureParam> params; + + switch (tok->get_id()) { + case OR: + // no parameters, don't skip token + break; + case PIPE: { + // actually may have parameters + // don't skip token + const_TokenPtr t = lexer.peek_token(); + while (t->get_id() != PIPE) { + AST::ClosureParam param = parse_closure_param(); + if (param.is_error()) { + // TODO is this really an error? + error_at(t->get_locus(), "could not parse closure param"); + return NULL; + } + params.push_back(::std::move(param)); + + if (lexer.peek_token()->get_id() != COMMA) { + // not an error but means param list is done + break; + } + // skip comma + lexer.skip_token(); + + t = lexer.peek_token(); + } + + if (!skip_token(PIPE)) { + return NULL; + } + break; + } + default: + error_at(tok->get_locus(), + "unexpected token '%s' in closure expression - expected '|' or '||'", + tok->get_token_description()); + // skip somewhere? + return NULL; + } + + // again branch based on next token + tok = lexer.peek_token(); + if (tok->get_id() == RETURN_TYPE) { + // must be return type closure with block expr + + // skip "return type" token + lexer.skip_token(); + + // parse actual type, which is required + ::std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds(); + if (type == NULL) { + // error + error_at(tok->get_locus(), "failed to parse type for closure"); + // skip somewhere? + return NULL; + } + + // parse block expr, which is required + ::std::unique_ptr<AST::BlockExpr> block = parse_block_expr(); + if (block == NULL) { + // error + error_at(lexer.peek_token()->get_locus(), "failed to parse block expr in closure"); + // skip somewhere? + return NULL; + } + + return ::std::unique_ptr<AST::ClosureExprInnerTyped>( + new AST::ClosureExprInnerTyped(::std::move(type), ::std::move(block), + ::std::move(params), locus, has_move, ::std::move(outer_attrs))); + } else { + // must be expr-only closure + + // parse expr, which is required + ::std::unique_ptr<AST::Expr> expr = parse_expr(); + if (expr == NULL) { + error_at(tok->get_locus(), "failed to parse expression in closure"); + // skip somewhere? + return NULL; + } + + return ::std::unique_ptr<AST::ClosureExprInner>(new AST::ClosureExprInner( + ::std::move(expr), ::std::move(params), locus, has_move, ::std::move(outer_attrs))); + } + } + + /* Parses a tuple index expression (pratt-parsed) from a 'float' token as a result of lexer + * misidentification. */ + ::std::unique_ptr<AST::TupleIndexExpr> Parser::parse_tuple_index_expr_float(const_TokenPtr tok, + ::std::unique_ptr<AST::Expr> tuple_expr, ::std::vector<AST::Attribute> outer_attrs, + ParseRestrictions restrictions ATTRIBUTE_UNUSED) { + // only works on float literals + if (tok->get_id() != FLOAT_LITERAL) { + return NULL; + } + + // DEBUG: + fprintf(stderr, "exact string form of float: '%s'\n", tok->get_str().c_str()); + + // get float string and remove dot and initial 0 + ::std::string index_str = tok->get_str(); + index_str.erase(index_str.begin()); + + // get int from string + int index = atoi(index_str.c_str()); + + location_t locus = tuple_expr->get_locus_slow(); - return new AST::CallExpr(function_expr, ::std::move(params), ::std::move(outer_attrs)); + return ::std::unique_ptr<AST::TupleIndexExpr>( + new AST::TupleIndexExpr(::std::move(tuple_expr), index, ::std::move(outer_attrs), locus)); } // Determines action to take when finding token at beginning of expression. diff --git a/gcc/rust/test3/parse/rust-parse.h b/gcc/rust/test3/parse/rust-parse.h index caf13d6..94d1eab 100644 --- a/gcc/rust/test3/parse/rust-parse.h +++ b/gcc/rust/test3/parse/rust-parse.h @@ -10,17 +10,73 @@ #include "rust-ast-full.h" namespace Rust { + /* HACK: used to resolve the expression-or-statement problem at the end of a block by allowing + * either to be returned (technically). Tagged union would probably take up the same amount of + * space. */ + struct ExprOrStmt { + ::std::unique_ptr<AST::ExprWithoutBlock> expr; + ::std::unique_ptr<AST::Stmt> stmt; + + /* I was going to resist the urge to make this a real class and make it POD, but construction + * in steps is too difficult. So it'll just also have a constructor. */ + + // expression constructor + ExprOrStmt(::std::unique_ptr<AST::ExprWithoutBlock> expr) : expr(::std::move(expr)) {} + + // statement constructor + ExprOrStmt(::std::unique_ptr<AST::Stmt> stmt) : stmt(::std::move(stmt)) {} + + // Returns whether this object is in an error state. + inline bool is_error() const { + return (expr == NULL && stmt == NULL) || (expr != NULL && stmt != NULL); + } + + // Returns an error state object. + static ExprOrStmt create_error() { + return ExprOrStmt(NULL, NULL); + } + + ~ExprOrStmt() = default; + + // no copy constructors/assignment copy as simple object like this shouldn't require it + + // move constructors + ExprOrStmt(ExprOrStmt&& other) = default; + ExprOrStmt& operator=(ExprOrStmt&& other) = default; + + private: + // private constructor only used for creating error state expr or stmt objects + ExprOrStmt(AST::ExprWithoutBlock* expr, AST::Stmt* stmt) : expr(expr), stmt(stmt) {} + + // make this work: have a disambiguation specifically for known statements (i.e. ';' and + // 'let'). then, have a special "parse expr or stmt" function that returns this type. inside + // it, it parses an expression, and then determines whether to return expr or stmt via whether + // the next token is a semicolon. should be able to disambiguate inside that function between + // stmts with blocks and without blocks. + }; + + /* Restrictions on parsing used to signal that certain ambiguous grammar features should be parsed + * in a certain way.*/ + struct ParseRestrictions { + bool can_be_struct_expr = true; + /* Whether the expression was entered from a unary expression - prevents stuff like struct + * exprs being parsed from a dereference. */ + bool entered_from_unary = false; + }; + // Parser implementation for gccrs. class Parser { private: void skip_after_semicolon(); void skip_after_end(); void skip_after_end_block(); + void skip_after_next_block(); void skip_after_end_attribute(); bool skip_token(TokenId t); const_TokenPtr expect_token(TokenId t); void unexpected_token(const_TokenPtr t); + bool skip_generics_right_angle(); // expression parsing int left_binding_power(const_TokenPtr tok); @@ -63,57 +119,60 @@ namespace Rust { void parse_statement_seq(bool (Parser::*done)()); // AST-related stuff - maybe move or something? - AST::Crate parse_crate(); ::std::vector<AST::Attribute> parse_inner_attributes(); AST::Attribute parse_inner_attribute(); ::std::vector<AST::Attribute> parse_outer_attributes(); AST::Attribute parse_outer_attribute(); AST::Attribute parse_attribute_body(); - AST::AttrInput* parse_attr_input(); + ::std::unique_ptr<AST::AttrInput> parse_attr_input(); // Path-related AST::SimplePath parse_simple_path(); AST::SimplePathSegment parse_simple_path_segment(); AST::TypePath parse_type_path(); - AST::TypePathSegment* parse_type_path_segment(); + ::std::unique_ptr<AST::TypePathSegment> parse_type_path_segment(); AST::PathIdentSegment parse_path_ident_segment(); AST::GenericArgs parse_path_generic_args(); AST::GenericArgsBinding parse_generic_args_binding(); AST::TypePathFunction parse_type_path_function(); AST::PathInExpression parse_path_in_expression(); AST::PathExprSegment parse_path_expr_segment(); - AST::QualifiedPathInExpression parse_qualified_path_in_expression(); - AST::QualifiedPathType parse_qualified_path_type(); + AST::QualifiedPathInExpression parse_qualified_path_in_expression(bool pratt_parse = false); + AST::QualifiedPathType parse_qualified_path_type(bool pratt_parse = false); AST::QualifiedPathInType parse_qualified_path_in_type(); // Token tree or macro related AST::DelimTokenTree parse_delim_token_tree(); - AST::TokenTree* parse_token_tree(); - AST::MacroRulesDefinition* parse_macro_rules_def(::std::vector<AST::Attribute> outer_attrs); - AST::MacroInvocationSemi* parse_macro_invocation_semi( + ::std::unique_ptr<AST::TokenTree> parse_token_tree(); + ::std::unique_ptr<AST::MacroRulesDefinition> parse_macro_rules_def( + ::std::vector<AST::Attribute> outer_attrs); + ::std::unique_ptr<AST::MacroInvocationSemi> parse_macro_invocation_semi( + ::std::vector<AST::Attribute> outer_attrs); + ::std::unique_ptr<AST::MacroInvocation> parse_macro_invocation( ::std::vector<AST::Attribute> outer_attrs); - AST::MacroInvocation* parse_macro_invocation(::std::vector<AST::Attribute> outer_attrs); AST::MacroRule parse_macro_rule(); AST::MacroMatcher parse_macro_matcher(); - AST::MacroMatch* parse_macro_match(); - AST::MacroMatchFragment* parse_macro_match_fragment(); - AST::MacroMatchRepetition* parse_macro_match_repetition(); + ::std::unique_ptr<AST::MacroMatch> parse_macro_match(); + ::std::unique_ptr<AST::MacroMatchFragment> parse_macro_match_fragment(); + ::std::unique_ptr<AST::MacroMatchRepetition> parse_macro_match_repetition(); // Top-level item-related ::std::vector< ::std::unique_ptr<AST::Item> > parse_items(); - AST::Item* parse_item(bool called_from_statement); - AST::VisItem* parse_vis_item(::std::vector<AST::Attribute> outer_attrs); - AST::MacroItem* parse_macro_item(::std::vector<AST::Attribute> outer_attrs); + ::std::unique_ptr<AST::Item> parse_item(bool called_from_statement); + ::std::unique_ptr<AST::VisItem> parse_vis_item(::std::vector<AST::Attribute> outer_attrs); + ::std::unique_ptr<AST::MacroItem> parse_macro_item(::std::vector<AST::Attribute> outer_attrs); AST::Visibility parse_visibility(); // VisItem subclass-related - AST::Module* parse_module(AST::Visibility vis, ::std::vector<AST::Attribute> outer_attrs); - AST::ExternCrate* parse_extern_crate( + ::std::unique_ptr<AST::Module> parse_module( + AST::Visibility vis, ::std::vector<AST::Attribute> outer_attrs); + ::std::unique_ptr<AST::ExternCrate> parse_extern_crate( AST::Visibility vis, ::std::vector<AST::Attribute> outer_attrs); - AST::UseDeclaration* parse_use_decl( + ::std::unique_ptr<AST::UseDeclaration> parse_use_decl( + AST::Visibility vis, ::std::vector<AST::Attribute> outer_attrs); + ::std::unique_ptr<AST::UseTree> parse_use_tree(); + ::std::unique_ptr<AST::Function> parse_function( AST::Visibility vis, ::std::vector<AST::Attribute> outer_attrs); - AST::UseTree* parse_use_tree(); - AST::Function* parse_function(AST::Visibility vis, ::std::vector<AST::Attribute> outer_attrs); AST::FunctionQualifiers parse_function_qualifiers(); ::std::vector< ::std::unique_ptr<AST::GenericParam> > parse_generic_params_in_angles(); ::std::vector< ::std::unique_ptr<AST::GenericParam> > parse_generic_params(); @@ -121,221 +180,301 @@ namespace Rust { ::std::vector<AST::LifetimeParam> parse_lifetime_params_objs(); AST::LifetimeParam parse_lifetime_param(); ::std::vector< ::std::unique_ptr<AST::TypeParam> > parse_type_params(); - AST::TypeParam* parse_type_param(); + ::std::unique_ptr<AST::TypeParam> parse_type_param(); ::std::vector<AST::FunctionParam> parse_function_params(); AST::FunctionParam parse_function_param(); - AST::Type* parse_function_return_type(); + ::std::unique_ptr<AST::Type> parse_function_return_type(); AST::WhereClause parse_where_clause(); - AST::WhereClauseItem* parse_where_clause_item(); - AST::LifetimeWhereClauseItem* parse_lifetime_where_clause_item(); - AST::TypeBoundWhereClauseItem* parse_type_bound_where_clause_item(); + ::std::unique_ptr<AST::WhereClauseItem> parse_where_clause_item(); + ::std::unique_ptr<AST::LifetimeWhereClauseItem> parse_lifetime_where_clause_item(); + ::std::unique_ptr<AST::TypeBoundWhereClauseItem> parse_type_bound_where_clause_item(); ::std::vector<AST::LifetimeParam> parse_for_lifetimes(); ::std::vector< ::std::unique_ptr<AST::TypeParamBound> > parse_type_param_bounds(); - AST::TypeParamBound* parse_type_param_bound(); - AST::TraitBound* parse_trait_bound(); + ::std::unique_ptr<AST::TypeParamBound> parse_type_param_bound(); + ::std::unique_ptr<AST::TraitBound> parse_trait_bound(); ::std::vector<AST::Lifetime> parse_lifetime_bounds(); AST::Lifetime parse_lifetime(); - AST::TypeAlias* parse_type_alias( + ::std::unique_ptr<AST::TypeAlias> parse_type_alias( + AST::Visibility vis, ::std::vector<AST::Attribute> outer_attrs); + ::std::unique_ptr<AST::Struct> parse_struct( AST::Visibility vis, ::std::vector<AST::Attribute> outer_attrs); - AST::Struct* parse_struct(AST::Visibility vis, ::std::vector<AST::Attribute> outer_attrs); ::std::vector<AST::StructField> parse_struct_fields(); AST::StructField parse_struct_field(); ::std::vector<AST::TupleField> parse_tuple_fields(); AST::TupleField parse_tuple_field(); - AST::Enum* parse_enum(AST::Visibility vis, ::std::vector<AST::Attribute> outer_attrs); + ::std::unique_ptr<AST::Enum> parse_enum( + AST::Visibility vis, ::std::vector<AST::Attribute> outer_attrs); ::std::vector< ::std::unique_ptr<AST::EnumItem> > parse_enum_items(); - AST::EnumItem* parse_enum_item(); - AST::Union* parse_union(AST::Visibility vis, ::std::vector<AST::Attribute> outer_attrs); - AST::ConstantItem* parse_const_item( + ::std::unique_ptr<AST::EnumItem> parse_enum_item(); + ::std::unique_ptr<AST::Union> parse_union( AST::Visibility vis, ::std::vector<AST::Attribute> outer_attrs); - AST::StaticItem* parse_static_item( + ::std::unique_ptr<AST::ConstantItem> parse_const_item( AST::Visibility vis, ::std::vector<AST::Attribute> outer_attrs); - AST::Trait* parse_trait(AST::Visibility vis, ::std::vector<AST::Attribute> outer_attrs); - AST::TraitItem* parse_trait_item(); - AST::TraitItemType* parse_trait_type(::std::vector<AST::Attribute> outer_attrs); - AST::TraitItemConst* parse_trait_const(::std::vector<AST::Attribute> outer_attrs); + ::std::unique_ptr<AST::StaticItem> parse_static_item( + AST::Visibility vis, ::std::vector<AST::Attribute> outer_attrs); + ::std::unique_ptr<AST::Trait> parse_trait( + AST::Visibility vis, ::std::vector<AST::Attribute> outer_attrs); + ::std::unique_ptr<AST::TraitItem> parse_trait_item(); + ::std::unique_ptr<AST::TraitItemType> parse_trait_type( + ::std::vector<AST::Attribute> outer_attrs); + ::std::unique_ptr<AST::TraitItemConst> parse_trait_const( + ::std::vector<AST::Attribute> outer_attrs); AST::SelfParam parse_self_param(); - AST::Impl* parse_impl(AST::Visibility vis, ::std::vector<AST::Attribute> outer_attrs); - AST::InherentImplItem* parse_inherent_impl_item(); - AST::InherentImplItem* parse_inherent_impl_function_or_method( + ::std::unique_ptr<AST::Impl> parse_impl( + AST::Visibility vis, ::std::vector<AST::Attribute> outer_attrs); + ::std::unique_ptr<AST::InherentImplItem> parse_inherent_impl_item(); + ::std::unique_ptr<AST::InherentImplItem> parse_inherent_impl_function_or_method( AST::Visibility vis, ::std::vector<AST::Attribute> outer_attrs); - AST::TraitImplItem* parse_trait_impl_item(); - AST::TraitImplItem* parse_trait_impl_function_or_method( + ::std::unique_ptr<AST::TraitImplItem> parse_trait_impl_item(); + ::std::unique_ptr<AST::TraitImplItem> parse_trait_impl_function_or_method( AST::Visibility vis, ::std::vector<AST::Attribute> outer_attrs); - AST::ExternBlock* parse_extern_block( + ::std::unique_ptr<AST::ExternBlock> parse_extern_block( AST::Visibility vis, ::std::vector<AST::Attribute> outer_attrs); - AST::ExternalItem* parse_external_item(); + ::std::unique_ptr<AST::ExternalItem> parse_external_item(); AST::NamedFunctionParam parse_named_function_param(); AST::Method parse_method(); // Expression-related (Pratt parsed) - AST::Expr* parse_expr(::std::vector<AST::Attribute> outer_attrs = ::std::vector<AST::Attribute>()); - AST::Expr* parse_expr(int right_binding_power, ::std::vector<AST::Attribute> outer_attrs = ::std::vector<AST::Attribute>()); - AST::Expr* null_denotation_NEW(const_TokenPtr t, ::std::vector<AST::Attribute> outer_attrs = ::std::vector<AST::Attribute>()); - AST::Expr* left_denotation(const_TokenPtr t, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs = ::std::vector<AST::Attribute>()); - AST::ArithmeticOrLogicalExpr* parse_binary_plus_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs); - AST::ArithmeticOrLogicalExpr* parse_binary_minus_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs); - AST::ArithmeticOrLogicalExpr* parse_binary_mult_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs); - AST::ArithmeticOrLogicalExpr* parse_binary_div_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs); - AST::ArithmeticOrLogicalExpr* parse_binary_mod_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs); - AST::ArithmeticOrLogicalExpr* parse_bitwise_and_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs); - AST::ArithmeticOrLogicalExpr* parse_bitwise_or_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs); - AST::ArithmeticOrLogicalExpr* parse_bitwise_xor_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs); - AST::ArithmeticOrLogicalExpr* parse_left_shift_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs); - AST::ArithmeticOrLogicalExpr* parse_right_shift_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs); - AST::ComparisonExpr* parse_binary_equal_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs); - AST::ComparisonExpr* parse_binary_not_equal_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs); - AST::ComparisonExpr* parse_binary_greater_than_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs); - AST::ComparisonExpr* parse_binary_less_than_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs); - AST::ComparisonExpr* parse_binary_greater_equal_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs); - AST::ComparisonExpr* parse_binary_less_equal_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs); - AST::LazyBooleanExpr* parse_lazy_or_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs); - AST::LazyBooleanExpr* parse_lazy_and_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs); - AST::TypeCastExpr* parse_type_cast_expr( - const_TokenPtr tok, AST::Expr* expr_to_cast, ::std::vector<AST::Attribute> outer_attrs); - AST::AssignmentExpr* parse_assig_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs); - AST::CompoundAssignmentExpr* parse_plus_assig_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs); - AST::CompoundAssignmentExpr* parse_minus_assig_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs); - AST::CompoundAssignmentExpr* parse_mult_assig_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs); - AST::CompoundAssignmentExpr* parse_div_assig_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs); - AST::CompoundAssignmentExpr* parse_mod_assig_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs); - AST::CompoundAssignmentExpr* parse_and_assig_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs); - AST::CompoundAssignmentExpr* parse_or_assig_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs); - AST::CompoundAssignmentExpr* parse_xor_assig_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs); - AST::CompoundAssignmentExpr* parse_left_shift_assig_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs); - AST::CompoundAssignmentExpr* parse_right_shift_assig_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs); - AST::AwaitExpr* parse_await_expr( - const_TokenPtr tok, AST::Expr* expr_to_await, ::std::vector<AST::Attribute> outer_attrs); - AST::MethodCallExpr* parse_method_call_expr( - const_TokenPtr tok, AST::Expr* receiver_expr, ::std::vector<AST::Attribute> outer_attrs); - AST::CallExpr* parse_function_call_expr( - const_TokenPtr tok, AST::Expr* function_expr, ::std::vector<AST::Attribute> outer_attrs); - AST::RangeExpr* parse_led_range_exclusive_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs); - AST::RangeExpr* parse_nud_range_exclusive_expr( + ::std::unique_ptr<AST::Expr> parse_expr( + ::std::vector<AST::Attribute> outer_attrs = ::std::vector<AST::Attribute>(), + ParseRestrictions restrictions = ParseRestrictions()); + ::std::unique_ptr<AST::Expr> parse_expr(int right_binding_power, + ::std::vector<AST::Attribute> outer_attrs = ::std::vector<AST::Attribute>(), + ParseRestrictions restrictions = ParseRestrictions()); + ::std::unique_ptr<AST::Expr> null_denotation_NEW(const_TokenPtr t, + ::std::vector<AST::Attribute> outer_attrs = ::std::vector<AST::Attribute>(), + ParseRestrictions restrictions = ParseRestrictions()); + ::std::unique_ptr<AST::Expr> left_denotation(const_TokenPtr t, + ::std::unique_ptr<AST::Expr> left, + ::std::vector<AST::Attribute> outer_attrs = ::std::vector<AST::Attribute>(), + ParseRestrictions restrictions = ParseRestrictions()); + ::std::unique_ptr<AST::ArithmeticOrLogicalExpr> parse_binary_plus_expr(const_TokenPtr tok, + ::std::unique_ptr<AST::Expr> left, ::std::vector<AST::Attribute> outer_attrs, + ParseRestrictions restrictions = ParseRestrictions()); + ::std::unique_ptr<AST::ArithmeticOrLogicalExpr> parse_binary_minus_expr(const_TokenPtr tok, + ::std::unique_ptr<AST::Expr> left, ::std::vector<AST::Attribute> outer_attrs, + ParseRestrictions restrictions = ParseRestrictions()); + ::std::unique_ptr<AST::ArithmeticOrLogicalExpr> parse_binary_mult_expr(const_TokenPtr tok, + ::std::unique_ptr<AST::Expr> left, ::std::vector<AST::Attribute> outer_attrs, + ParseRestrictions restrictions = ParseRestrictions()); + ::std::unique_ptr<AST::ArithmeticOrLogicalExpr> parse_binary_div_expr(const_TokenPtr tok, + ::std::unique_ptr<AST::Expr> left, ::std::vector<AST::Attribute> outer_attrs, + ParseRestrictions restrictions = ParseRestrictions()); + ::std::unique_ptr<AST::ArithmeticOrLogicalExpr> parse_binary_mod_expr(const_TokenPtr tok, + ::std::unique_ptr<AST::Expr> left, ::std::vector<AST::Attribute> outer_attrs, + ParseRestrictions restrictions = ParseRestrictions()); + ::std::unique_ptr<AST::ArithmeticOrLogicalExpr> parse_bitwise_and_expr(const_TokenPtr tok, + ::std::unique_ptr<AST::Expr> left, ::std::vector<AST::Attribute> outer_attrs, + ParseRestrictions restrictions = ParseRestrictions()); + ::std::unique_ptr<AST::ArithmeticOrLogicalExpr> parse_bitwise_or_expr(const_TokenPtr tok, + ::std::unique_ptr<AST::Expr> left, ::std::vector<AST::Attribute> outer_attrs, + ParseRestrictions restrictions = ParseRestrictions()); + ::std::unique_ptr<AST::ArithmeticOrLogicalExpr> parse_bitwise_xor_expr(const_TokenPtr tok, + ::std::unique_ptr<AST::Expr> left, ::std::vector<AST::Attribute> outer_attrs, + ParseRestrictions restrictions = ParseRestrictions()); + ::std::unique_ptr<AST::ArithmeticOrLogicalExpr> parse_left_shift_expr(const_TokenPtr tok, + ::std::unique_ptr<AST::Expr> left, ::std::vector<AST::Attribute> outer_attrs, + ParseRestrictions restrictions = ParseRestrictions()); + ::std::unique_ptr<AST::ArithmeticOrLogicalExpr> parse_right_shift_expr(const_TokenPtr tok, + ::std::unique_ptr<AST::Expr> left, ::std::vector<AST::Attribute> outer_attrs, + ParseRestrictions restrictions = ParseRestrictions()); + ::std::unique_ptr<AST::ComparisonExpr> parse_binary_equal_expr(const_TokenPtr tok, + ::std::unique_ptr<AST::Expr> left, ::std::vector<AST::Attribute> outer_attrs, + ParseRestrictions restrictions = ParseRestrictions()); + ::std::unique_ptr<AST::ComparisonExpr> parse_binary_not_equal_expr(const_TokenPtr tok, + ::std::unique_ptr<AST::Expr> left, ::std::vector<AST::Attribute> outer_attrs, + ParseRestrictions restrictions = ParseRestrictions()); + ::std::unique_ptr<AST::ComparisonExpr> parse_binary_greater_than_expr(const_TokenPtr tok, + ::std::unique_ptr<AST::Expr> left, ::std::vector<AST::Attribute> outer_attrs, + ParseRestrictions restrictions = ParseRestrictions()); + ::std::unique_ptr<AST::ComparisonExpr> parse_binary_less_than_expr(const_TokenPtr tok, + ::std::unique_ptr<AST::Expr> left, ::std::vector<AST::Attribute> outer_attrs, + ParseRestrictions restrictions = ParseRestrictions()); + ::std::unique_ptr<AST::ComparisonExpr> parse_binary_greater_equal_expr(const_TokenPtr tok, + ::std::unique_ptr<AST::Expr> left, ::std::vector<AST::Attribute> outer_attrs, + ParseRestrictions restrictions = ParseRestrictions()); + ::std::unique_ptr<AST::ComparisonExpr> parse_binary_less_equal_expr(const_TokenPtr tok, + ::std::unique_ptr<AST::Expr> left, ::std::vector<AST::Attribute> outer_attrs, + ParseRestrictions restrictions = ParseRestrictions()); + ::std::unique_ptr<AST::LazyBooleanExpr> parse_lazy_or_expr(const_TokenPtr tok, + ::std::unique_ptr<AST::Expr> left, ::std::vector<AST::Attribute> outer_attrs, + ParseRestrictions restrictions = ParseRestrictions()); + ::std::unique_ptr<AST::LazyBooleanExpr> parse_lazy_and_expr(const_TokenPtr tok, + ::std::unique_ptr<AST::Expr> left, ::std::vector<AST::Attribute> outer_attrs, + ParseRestrictions restrictions = ParseRestrictions()); + ::std::unique_ptr<AST::TypeCastExpr> parse_type_cast_expr(const_TokenPtr tok, + ::std::unique_ptr<AST::Expr> expr_to_cast, ::std::vector<AST::Attribute> outer_attrs, + ParseRestrictions restrictions = ParseRestrictions()); + ::std::unique_ptr<AST::AssignmentExpr> parse_assig_expr(const_TokenPtr tok, + ::std::unique_ptr<AST::Expr> left, ::std::vector<AST::Attribute> outer_attrs, + ParseRestrictions restrictions = ParseRestrictions()); + ::std::unique_ptr<AST::CompoundAssignmentExpr> parse_plus_assig_expr(const_TokenPtr tok, + ::std::unique_ptr<AST::Expr> left, ::std::vector<AST::Attribute> outer_attrs, + ParseRestrictions restrictions = ParseRestrictions()); + ::std::unique_ptr<AST::CompoundAssignmentExpr> parse_minus_assig_expr(const_TokenPtr tok, + ::std::unique_ptr<AST::Expr> left, ::std::vector<AST::Attribute> outer_attrs, + ParseRestrictions restrictions = ParseRestrictions()); + ::std::unique_ptr<AST::CompoundAssignmentExpr> parse_mult_assig_expr(const_TokenPtr tok, + ::std::unique_ptr<AST::Expr> left, ::std::vector<AST::Attribute> outer_attrs, + ParseRestrictions restrictions = ParseRestrictions()); + ::std::unique_ptr<AST::CompoundAssignmentExpr> parse_div_assig_expr(const_TokenPtr tok, + ::std::unique_ptr<AST::Expr> left, ::std::vector<AST::Attribute> outer_attrs, + ParseRestrictions restrictions = ParseRestrictions()); + ::std::unique_ptr<AST::CompoundAssignmentExpr> parse_mod_assig_expr(const_TokenPtr tok, + ::std::unique_ptr<AST::Expr> left, ::std::vector<AST::Attribute> outer_attrs, + ParseRestrictions restrictions = ParseRestrictions()); + ::std::unique_ptr<AST::CompoundAssignmentExpr> parse_and_assig_expr(const_TokenPtr tok, + ::std::unique_ptr<AST::Expr> left, ::std::vector<AST::Attribute> outer_attrs, + ParseRestrictions restrictions = ParseRestrictions()); + ::std::unique_ptr<AST::CompoundAssignmentExpr> parse_or_assig_expr(const_TokenPtr tok, + ::std::unique_ptr<AST::Expr> left, ::std::vector<AST::Attribute> outer_attrs, + ParseRestrictions restrictions = ParseRestrictions()); + ::std::unique_ptr<AST::CompoundAssignmentExpr> parse_xor_assig_expr(const_TokenPtr tok, + ::std::unique_ptr<AST::Expr> left, ::std::vector<AST::Attribute> outer_attrs, + ParseRestrictions restrictions = ParseRestrictions()); + ::std::unique_ptr<AST::CompoundAssignmentExpr> parse_left_shift_assig_expr(const_TokenPtr tok, + ::std::unique_ptr<AST::Expr> left, ::std::vector<AST::Attribute> outer_attrs, + ParseRestrictions restrictions = ParseRestrictions()); + ::std::unique_ptr<AST::CompoundAssignmentExpr> parse_right_shift_assig_expr( + const_TokenPtr tok, ::std::unique_ptr<AST::Expr> left, + ::std::vector<AST::Attribute> outer_attrs, + ParseRestrictions restrictions = ParseRestrictions()); + ::std::unique_ptr<AST::AwaitExpr> parse_await_expr(const_TokenPtr tok, + ::std::unique_ptr<AST::Expr> expr_to_await, ::std::vector<AST::Attribute> outer_attrs); + ::std::unique_ptr<AST::MethodCallExpr> parse_method_call_expr(const_TokenPtr tok, + ::std::unique_ptr<AST::Expr> receiver_expr, ::std::vector<AST::Attribute> outer_attrs, + ParseRestrictions restrictions = ParseRestrictions()); + ::std::unique_ptr<AST::CallExpr> parse_function_call_expr(const_TokenPtr tok, + ::std::unique_ptr<AST::Expr> function_expr, ::std::vector<AST::Attribute> outer_attrs, + ParseRestrictions restrictions = ParseRestrictions()); + ::std::unique_ptr<AST::RangeExpr> parse_led_range_exclusive_expr(const_TokenPtr tok, + ::std::unique_ptr<AST::Expr> left, ::std::vector<AST::Attribute> outer_attrs, + ParseRestrictions restrictions = ParseRestrictions()); + ::std::unique_ptr<AST::RangeExpr> parse_nud_range_exclusive_expr( const_TokenPtr tok, ::std::vector<AST::Attribute> outer_attrs); - AST::RangeFromToInclExpr* parse_range_inclusive_expr( - const_TokenPtr tok, AST::Expr* left, ::std::vector<AST::Attribute> outer_attrs); - AST::RangeToInclExpr* parse_range_to_inclusive_expr( + ::std::unique_ptr<AST::RangeFromToInclExpr> parse_range_inclusive_expr(const_TokenPtr tok, + ::std::unique_ptr<AST::Expr> left, ::std::vector<AST::Attribute> outer_attrs, + ParseRestrictions restrictions = ParseRestrictions()); + ::std::unique_ptr<AST::RangeToInclExpr> parse_range_to_inclusive_expr( const_TokenPtr tok, ::std::vector<AST::Attribute> outer_attrs); - AST::TupleIndexExpr* parse_tuple_index_expr( - const_TokenPtr tok, AST::Expr* tuple_expr, ::std::vector<AST::Attribute> outer_attrs); - AST::FieldAccessExpr* parse_field_access_expr( - const_TokenPtr tok, AST::Expr* struct_expr, ::std::vector<AST::Attribute> outer_attrs); - AST::ArrayIndexExpr* parse_index_expr( - const_TokenPtr tok, AST::Expr* array_expr, ::std::vector<AST::Attribute> outer_attrs); + ::std::unique_ptr<AST::TupleIndexExpr> parse_tuple_index_expr(const_TokenPtr tok, + ::std::unique_ptr<AST::Expr> tuple_expr, ::std::vector<AST::Attribute> outer_attrs, + ParseRestrictions restrictions = ParseRestrictions()); + ::std::unique_ptr<AST::FieldAccessExpr> parse_field_access_expr(const_TokenPtr tok, + ::std::unique_ptr<AST::Expr> struct_expr, ::std::vector<AST::Attribute> outer_attrs, + ParseRestrictions restrictions = ParseRestrictions()); + ::std::unique_ptr<AST::ArrayIndexExpr> parse_index_expr(const_TokenPtr tok, + ::std::unique_ptr<AST::Expr> array_expr, ::std::vector<AST::Attribute> outer_attrs, + ParseRestrictions restrictions = ParseRestrictions()); + ::std::unique_ptr<AST::MacroInvocation> parse_macro_invocation_partial( + AST::PathInExpression path, ::std::vector<AST::Attribute> outer_attrs); + ::std::unique_ptr<AST::StructExprStruct> parse_struct_expr_struct_partial( + AST::PathInExpression path, ::std::vector<AST::Attribute> outer_attrs); + ::std::unique_ptr<AST::StructExprTuple> parse_struct_expr_tuple_partial( + AST::PathInExpression path, ::std::vector<AST::Attribute> outer_attrs); + AST::PathInExpression parse_path_in_expression_pratt(const_TokenPtr tok); + ::std::unique_ptr<AST::ClosureExpr> parse_closure_expr_pratt(const_TokenPtr tok, + ::std::vector<AST::Attribute> outer_attrs = ::std::vector<AST::Attribute>()); + ::std::unique_ptr<AST::TupleIndexExpr> parse_tuple_index_expr_float(const_TokenPtr tok, + ::std::unique_ptr<AST::Expr> tuple_expr, ::std::vector<AST::Attribute> outer_attrs, + ParseRestrictions restrictions = ParseRestrictions()); // Expression-related (non-Pratt parsed) - AST::ExprWithoutBlock* parse_expr_without_block( - ::std::vector<AST::Attribute> outer_attrs = ::std::vector<AST::Attribute>()); - AST::BlockExpr* parse_block_expr( + ::std::unique_ptr<AST::ExprWithoutBlock> parse_expr_without_block( ::std::vector<AST::Attribute> outer_attrs = ::std::vector<AST::Attribute>()); - AST::IfExpr* parse_if_expr( + ::std::unique_ptr<AST::BlockExpr> parse_block_expr( + ::std::vector<AST::Attribute> outer_attrs = ::std::vector<AST::Attribute>(), + bool pratt_parse = false); + ::std::unique_ptr<AST::IfExpr> parse_if_expr( ::std::vector<AST::Attribute> outer_attrs = ::std::vector<AST::Attribute>()); - AST::IfLetExpr* parse_if_let_expr( + ::std::unique_ptr<AST::IfLetExpr> parse_if_let_expr( ::std::vector<AST::Attribute> outer_attrs = ::std::vector<AST::Attribute>()); - AST::LoopExpr* parse_loop_expr( + ::std::unique_ptr<AST::LoopExpr> parse_loop_expr( ::std::vector<AST::Attribute> outer_attrs = ::std::vector<AST::Attribute>(), AST::LoopLabel label = AST::LoopLabel::error()); - AST::WhileLoopExpr* parse_while_loop_expr( + ::std::unique_ptr<AST::WhileLoopExpr> parse_while_loop_expr( ::std::vector<AST::Attribute> outer_attrs = ::std::vector<AST::Attribute>(), AST::LoopLabel label = AST::LoopLabel::error()); - AST::WhileLetLoopExpr* parse_while_let_loop_expr( + ::std::unique_ptr<AST::WhileLetLoopExpr> parse_while_let_loop_expr( ::std::vector<AST::Attribute> outer_attrs = ::std::vector<AST::Attribute>(), AST::LoopLabel label = AST::LoopLabel::error()); - AST::ForLoopExpr* parse_for_loop_expr( + ::std::unique_ptr<AST::ForLoopExpr> parse_for_loop_expr( ::std::vector<AST::Attribute> outer_attrs = ::std::vector<AST::Attribute>(), AST::LoopLabel label = AST::LoopLabel::error()); - AST::MatchExpr* parse_match_expr( - ::std::vector<AST::Attribute> outer_attrs = ::std::vector<AST::Attribute>()); + ::std::unique_ptr<AST::MatchExpr> parse_match_expr( + ::std::vector<AST::Attribute> outer_attrs = ::std::vector<AST::Attribute>(), + bool pratt_parse = false); AST::MatchArm parse_match_arm(); - ::std::vector< ::std::unique_ptr<AST::Pattern> > parse_match_arm_patterns(); - AST::BaseLoopExpr* parse_labelled_loop_expr( + ::std::vector< ::std::unique_ptr<AST::Pattern> > parse_match_arm_patterns( + TokenId end_token_id); + ::std::unique_ptr<AST::BaseLoopExpr> parse_labelled_loop_expr( ::std::vector<AST::Attribute> outer_attrs = ::std::vector<AST::Attribute>()); AST::LoopLabel parse_loop_label(); - AST::AsyncBlockExpr* parse_async_block_expr( + ::std::unique_ptr<AST::AsyncBlockExpr> parse_async_block_expr( ::std::vector<AST::Attribute> outer_attrs = ::std::vector<AST::Attribute>()); - AST::UnsafeBlockExpr* parse_unsafe_block_expr( + ::std::unique_ptr<AST::UnsafeBlockExpr> parse_unsafe_block_expr( ::std::vector<AST::Attribute> outer_attrs = ::std::vector<AST::Attribute>()); - AST::GroupedExpr* parse_grouped_expr( + ::std::unique_ptr<AST::GroupedExpr> parse_grouped_expr( ::std::vector<AST::Attribute> outer_attrs = ::std::vector<AST::Attribute>()); - AST::ClosureExpr* parse_closure_expr( + ::std::unique_ptr<AST::ClosureExpr> parse_closure_expr( ::std::vector<AST::Attribute> outer_attrs = ::std::vector<AST::Attribute>()); AST::ClosureParam parse_closure_param(); - AST::LiteralExpr* parse_literal_expr( - ::std::vector<AST::Attribute> outer_attrs = ::std::vector<AST::Attribute>()); - AST::ReturnExpr* parse_return_expr( - ::std::vector<AST::Attribute> outer_attrs = ::std::vector<AST::Attribute>(), bool pratt_parse = false); - AST::BreakExpr* parse_break_expr( - ::std::vector<AST::Attribute> outer_attrs = ::std::vector<AST::Attribute>(), bool pratt_parse = false); - AST::ContinueExpr* parse_continue_expr( + ::std::unique_ptr<AST::LiteralExpr> parse_literal_expr( ::std::vector<AST::Attribute> outer_attrs = ::std::vector<AST::Attribute>()); - AST::ArrayExpr* parse_array_expr( - ::std::vector<AST::Attribute> outer_attrs = ::std::vector<AST::Attribute>()); - AST::ExprWithoutBlock* parse_grouped_or_tuple_expr( - ::std::vector<AST::Attribute> outer_attrs = ::std::vector<AST::Attribute>(), bool pratt_parse = false); + ::std::unique_ptr<AST::ReturnExpr> parse_return_expr( + ::std::vector<AST::Attribute> outer_attrs = ::std::vector<AST::Attribute>(), + bool pratt_parse = false); + ::std::unique_ptr<AST::BreakExpr> parse_break_expr( + ::std::vector<AST::Attribute> outer_attrs = ::std::vector<AST::Attribute>(), + bool pratt_parse = false); + ::std::unique_ptr<AST::ContinueExpr> parse_continue_expr( + ::std::vector<AST::Attribute> outer_attrs = ::std::vector<AST::Attribute>(), + bool pratt_parse = false); + ::std::unique_ptr<AST::ArrayExpr> parse_array_expr( + ::std::vector<AST::Attribute> outer_attrs = ::std::vector<AST::Attribute>(), + bool pratt_parse = false); + ::std::unique_ptr<AST::ExprWithoutBlock> parse_grouped_or_tuple_expr( + ::std::vector<AST::Attribute> outer_attrs = ::std::vector<AST::Attribute>(), + bool pratt_parse = false); + ::std::unique_ptr<AST::StructExprField> parse_struct_expr_field(); // Type-related - AST::Type* parse_type(); - AST::TypeNoBounds* parse_type_no_bounds(); - AST::TypeNoBounds* parse_slice_or_array_type(); - AST::RawPointerType* parse_raw_pointer_type(); - AST::ReferenceType* parse_reference_type(); - AST::BareFunctionType* parse_bare_function_type(::std::vector<AST::LifetimeParam> for_lifetimes); - AST::Type* parse_paren_prefixed_type(); - AST::TypeNoBounds* parse_paren_prefixed_type_no_bounds(); - AST::Type* parse_for_prefixed_type(); + ::std::unique_ptr<AST::Type> parse_type(); + ::std::unique_ptr<AST::TypeNoBounds> parse_type_no_bounds(); + ::std::unique_ptr<AST::TypeNoBounds> parse_slice_or_array_type(); + ::std::unique_ptr<AST::RawPointerType> parse_raw_pointer_type(); + ::std::unique_ptr<AST::ReferenceType> parse_reference_type(); + ::std::unique_ptr<AST::BareFunctionType> parse_bare_function_type( + ::std::vector<AST::LifetimeParam> for_lifetimes); + ::std::unique_ptr<AST::Type> parse_paren_prefixed_type(); + ::std::unique_ptr<AST::TypeNoBounds> parse_paren_prefixed_type_no_bounds(); + ::std::unique_ptr<AST::Type> parse_for_prefixed_type(); AST::MaybeNamedParam parse_maybe_named_param(); // Statement-related - AST::Stmt* parse_stmt(); - AST::LetStmt* parse_let_stmt(::std::vector<AST::Attribute> outer_attrs); - AST::ExprStmt* parse_expr_stmt(::std::vector<AST::Attribute> outer_attrs); - AST::ExprStmtWithBlock* parse_expr_stmt_with_block(::std::vector<AST::Attribute> outer_attrs); - AST::ExprStmtWithoutBlock* parse_expr_stmt_without_block( + ::std::unique_ptr<AST::Stmt> parse_stmt(); + ::std::unique_ptr<AST::LetStmt> parse_let_stmt(::std::vector<AST::Attribute> outer_attrs); + ::std::unique_ptr<AST::ExprStmt> parse_expr_stmt(::std::vector<AST::Attribute> outer_attrs); + ::std::unique_ptr<AST::ExprStmtWithBlock> parse_expr_stmt_with_block( ::std::vector<AST::Attribute> outer_attrs); + ::std::unique_ptr<AST::ExprStmtWithoutBlock> parse_expr_stmt_without_block( + ::std::vector<AST::Attribute> outer_attrs); + ExprOrStmt parse_stmt_or_expr_without_block(); + ExprOrStmt parse_macro_invocation_maybe_semi(::std::vector<AST::Attribute> outer_attrs); + ExprOrStmt parse_path_based_stmt_or_expr(::std::vector<AST::Attribute> outer_attrs); // Pattern-related - AST::Pattern* parse_pattern(); - AST::Pattern* parse_literal_or_range_pattern(); - AST::RangePatternBound* parse_range_pattern_bound(); - AST::ReferencePattern* parse_reference_pattern(); - AST::Pattern* parse_grouped_or_tuple_pattern(); - AST::SlicePattern* parse_slice_pattern(); - AST::IdentifierPattern* parse_identifier_pattern(); - AST::Pattern* parse_ident_leading_pattern(); - AST::TupleStructItems* parse_tuple_struct_items(); + ::std::unique_ptr<AST::Pattern> parse_pattern(); + ::std::unique_ptr<AST::Pattern> parse_literal_or_range_pattern(); + ::std::unique_ptr<AST::RangePatternBound> parse_range_pattern_bound(); + ::std::unique_ptr<AST::ReferencePattern> parse_reference_pattern(); + ::std::unique_ptr<AST::Pattern> parse_grouped_or_tuple_pattern(); + ::std::unique_ptr<AST::SlicePattern> parse_slice_pattern(); + ::std::unique_ptr<AST::IdentifierPattern> parse_identifier_pattern(); + ::std::unique_ptr<AST::Pattern> parse_ident_leading_pattern(); + ::std::unique_ptr<AST::TupleStructItems> parse_tuple_struct_items(); AST::StructPatternElements parse_struct_pattern_elems(); - AST::StructPatternField* parse_struct_pattern_field(); + ::std::unique_ptr<AST::StructPatternField> parse_struct_pattern_field(); // void parse_crate(); // AST::Module parse_module(); @@ -353,9 +492,12 @@ namespace Rust { // Construct parser with specified lexer reference. Parser(Lexer& parLexer) : lexer(parLexer), printf_fn(), puts_fn(), scanf_fn() {} - // Main entry point for parser. + // (old) Main entry point for parser. void parse_program(); + // Main entry point for parser. + AST::Crate parse_crate(); + Tree parse_statement(); Tree parse_variable_declaration(); diff --git a/gcc/rust/test3/rsspec.cc b/gcc/rust/test3/rsspec.cc index 69a14ad..8f16e6c 100644 --- a/gcc/rust/test3/rsspec.cc +++ b/gcc/rust/test3/rsspec.cc @@ -16,16 +16,18 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -/* #include "config.h" +#include "config.h" +#include "system.h" #include "coretypes.h" -#include "gcc.h" +//#include "gcc.h" #include "opts.h" -#include "system.h" -#include "intl.h" #include "tm.h" +//#include "intl.h" -#ifndef MATH_LIBRARY +// are gcc and intl includes required? + +/*#ifndef MATH_LIBRARY #define MATH_LIBRARY "m" #endif @@ -117,8 +119,10 @@ static struct cl_decoded_option* grs_new_decoded_options;*/ // Presumably this is the "compiler driver", which runs the compiler // Handle calling the compiler (i.e. options, libraries to use) // Used to change flags before passing them to the driver -void lang_specific_driver(struct cl_decoded_option** /* in_decoded_options*/, - unsigned int* /* in_decoded_options_count*/, int* /* in_added_libraries*/) { +void lang_specific_driver(struct cl_decoded_option** in_decoded_options ATTRIBUTE_UNUSED, + unsigned int* in_decoded_options_count ATTRIBUTE_UNUSED, int* in_added_libraries ATTRIBUTE_UNUSED) { + // as of now, no options need changing, but they may in the future + /* unsigned int i = 0; unsigned int argc = *in_decoded_options_count; // argument list count struct cl_decoded_option* decoded_options = *in_decoded_options; // argument list diff --git a/gcc/rust/test3/rust-buffered-queue.h b/gcc/rust/test3/rust-buffered-queue.h index 65c814d..ac0ea1a 100644 --- a/gcc/rust/test3/rust-buffered-queue.h +++ b/gcc/rust/test3/rust-buffered-queue.h @@ -103,6 +103,16 @@ namespace Rust { end++; } + // Replaces the current value in the buffer. Total HACK. + void replace_current_value(T replacement) { + // call peek to ensure value exists + peek(0); + + buffer[start] = replacement; + + // don't move start or end + } + private: // Source of tokens for queue. Source& source; diff --git a/gcc/rust/test3/rust-lang.cc b/gcc/rust/test3/rust-lang.cc index 80bfa74..5c47878 100644 --- a/gcc/rust/test3/rust-lang.cc +++ b/gcc/rust/test3/rust-lang.cc @@ -16,23 +16,28 @@ #include "common/common-target.h" // note: header files must be in this order or else forward declarations don't work properly. Kinda // dumb system, but have to live with it. clang-format seems to mess it up -/* Order: config, system, coretypes, target, tree, gimple-expr, diagnostic, opts, fold-const, +/* Order: config, system, coretypes, target, tree, gimple-expr, diagnostic, opts, fold-const, * gimplify, stor-layout, debug, convert, langhooks, langhooks-def, common-target */ +// FIXME: test saving intellisense +#include "options.h" + // version check to stop compiling if c++ isn't c++11 or higher #if __cplusplus < 201103 -# error "GCC Rust frontend requires C++11 or higher. You can compile the g++ frontend first and then compile the Rust frontend using that." +#error \ + "GCC Rust frontend requires C++11 or higher. You can compile the g++ frontend first and then compile the Rust frontend using that." #endif // TODO: is this best way to do it? Is it allowed? (should be) /* General TODOs: - * - maybe convert all raw pointer-returning/passing functions that conceptually return a unique + * - maybe convert all raw pointer-returning/passing functions that conceptually return a unique * pointer actually return a unique pointer. i.e. parse methods and constructors for AST objects. - * make_unique should probably be avoided to keep C++11 compatibility. + * make_unique should probably be avoided to keep C++11 compatibility. * - convert all copies of expensive-to-copy (deep copy) AST objects into moves, if possible. Don't * remove clone functionality - it may be required for e.g. HIR conversion. */ #include "rust-parse.h" +#include "rust-session-manager.h" // Language-dependent contents of a type. GTY() mark used for garbage collector. struct GTY(()) lang_type { @@ -63,11 +68,15 @@ struct GTY(()) language_function { int dummy; }; +// Kinda HACK-ish - store parsing session as static variable +static Rust::Session session; + /* Language hooks. */ /* Initial lang hook called (possibly), used for initialisation. * Must call build_common_tree_nodes, set_sizetype, build_common_tree_nodes_2, and - * build_common_builtin_nodes, as well as set global variable void_list_node. */ + * build_common_builtin_nodes, as well as set global variable void_list_node. + * Apparently called after option handling? */ static bool grs_langhook_init(void) { /* Something to do with this: This allows the code in d-builtins.cc to not have to worry about @@ -86,61 +95,24 @@ static bool grs_langhook_init(void) { // using_eh_for_cleanups(); // rdot_init(); - return true; -} -// Parses a single file with filename filename. -static void grs_parse_file(const char* filename) { - FILE* file = fopen(filename, "r"); + // initialise compiler session + session.init(); - if (file == NULL) { - fatal_error(UNKNOWN_LOCATION, "cannot open filename %s: %m", filename); - } - - // parse file here - // create lexer and parser - Rust::Lexer lex(filename, file); - Rust::Parser parser(lex); - - //parser.parse_program(); - // lexer debug - //parser.debug_dump_lex_output(); - - // parser debug - parser.debug_dump_ast_output(); - - // semantic analyser debug - /* Rust::const_TokenPtr tok = lex.peek_token(); - // do shit until EOF - while (true) { - bool has_text = tok->get_id() == Rust::IDENTIFIER || tok->get_id() == Rust::INT_LITERAL - || tok->get_id() == Rust::FLOAT_LITERAL - || tok->get_id() == Rust::STRING_LITERAL; - - location_t loc = tok->get_locus(); - - fprintf(stderr, "<id=%s%s, %s, line=%d, col=%d>\n", tok->token_id_to_str(), - has_text ? (std::string(", text=") + tok->get_str()).c_str() : "", LOCATION_FILE(loc), - LOCATION_LINE(loc), LOCATION_COLUMN(loc)); - - if (tok->get_id() == Rust::END_OF_FILE) - break; - - lex.skip_token(); - tok = lex.peek_token(); - }*/ + return true; +} - fclose(file); +/* The option mask (something to do with options for specific frontends or something). */ +static unsigned int grs_langhook_option_lang_mask(void) { + return CL_Rust; } -/* Actual main entry point for front-end. Called by langhook to parse files. - * May move to a different compilation unit if frontend gets too big. */ -static void grs_parse_files(int num_files, const char** files) { - for (int i = 0; i < num_files; i++) { - grs_parse_file(files[i]); - } +/* Initialize the options structure. */ +static void grs_langhook_init_options_struct(struct gcc_options* opts) { + // nothing yet - used by frontends to change specific options for the language + session.init_options(); } /* Main entry point for front-end, apparently. Finds input file names in global vars in_fnames and @@ -151,26 +123,30 @@ static void grs_parse_files(int num_files, const char** files) { static void grs_langhook_parse_file(void) { fprintf(stderr, "Preparing to parse files. \n"); - grs_parse_files(num_in_fnames, in_fnames); + // grs_parse_files(num_in_fnames, in_fnames); + session.parse_files(num_in_fnames, in_fnames); } +/* Seems to get the exact type for a specific type - e.g. for scalar float with 32-bit bitsize, it + * returns float, and for 64-bit bitsize, it returns double. Used to map RTL nodes to machine modes or + * something like that. */ static tree grs_langhook_type_for_mode(machine_mode mode, int unsignedp) { + // TODO: change all this later to match rustc types if (mode == TYPE_MODE(float_type_node)) return float_type_node; if (mode == TYPE_MODE(double_type_node)) return double_type_node; - // don't know what this means but assume it has something to do with weird precisions - if (mode == TYPE_MODE(intQI_type_node)) // quarter precision? + if (mode == TYPE_MODE(intQI_type_node)) // quarter integer mode - single byte treated as integer return unsignedp ? unsigned_intQI_type_node : intQI_type_node; - if (mode == TYPE_MODE(intHI_type_node)) // half precision? + if (mode == TYPE_MODE(intHI_type_node)) // half integer mode - two-byte integer return unsignedp ? unsigned_intHI_type_node : intHI_type_node; - if (mode == TYPE_MODE(intSI_type_node)) // single precision? + if (mode == TYPE_MODE(intSI_type_node)) // single integer mode - four-byte integer return unsignedp ? unsigned_intSI_type_node : intSI_type_node; - if (mode == TYPE_MODE(intDI_type_node)) // double precision? + if (mode == TYPE_MODE(intDI_type_node)) // double integer mode - eight-byte integer return unsignedp ? unsigned_intDI_type_node : intDI_type_node; - if (mode == TYPE_MODE(intTI_type_node)) // triple precision? + if (mode == TYPE_MODE(intTI_type_node)) // tetra integer mode - 16-byte integer return unsignedp ? unsigned_intTI_type_node : intTI_type_node; if (mode == TYPE_MODE(integer_type_node)) @@ -196,34 +172,105 @@ static tree grs_langhook_type_for_mode(machine_mode mode, int unsignedp) { return NULL; } +/* This appears to be used for creating different types for different bit sizes (e.g. int and long). + * Also, the Go frontend calls this from type_for_mode to determine the type from a specific bitsize + * for integer types. + * FIXME: change this when working on AST-GENERIC conversion to allow the full range of Rust type + * sizes. */ static tree grs_langhook_type_for_size( unsigned int bits ATTRIBUTE_UNUSED, int unsignedp ATTRIBUTE_UNUSED) { gcc_unreachable(); return NULL_TREE; + // nothing at the moment, but change later } -// Record a builtin function. We just ignore builtin functions. +// Record a builtin function. We just ignore builtin functions. static tree grs_langhook_builtin_function(tree decl ATTRIBUTE_UNUSED) { return decl; } +/* Return true if we are in the global binding level (which is never, apparently). */ static bool grs_langhook_global_bindings_p(void) { // return current_function_decl == NULL_TREE; - //gcc_unreachable(); - //return true; + // gcc_unreachable(); + // return true; return false; } +/* Push a declaration into the current binding level. We can't + usefully implement this since we don't want to convert from tree + back to one of our internal data structures. I think the only way + this is used is to record a decl which is to be returned by + getdecls, and we could implement it for that purpose if + necessary. */ static tree grs_langhook_pushdecl(tree decl ATTRIBUTE_UNUSED) { gcc_unreachable(); return NULL; } +/* This hook is used to get the current list of declarations as trees. + We don't support that; instead we use the write_globals hook. This + can't simply crash because it is called by -gstabs. */ static tree grs_langhook_getdecls(void) { // gcc_unreachable(); return NULL; } +// Handle Rust-specific options. Return false if nothing happened. +static bool grs_langhook_handle_option(size_t scode, const char* arg, HOST_WIDE_INT value, + int kind ATTRIBUTE_UNUSED, location_t loc ATTRIBUTE_UNUSED, + const struct cl_option_handlers* handlers ATTRIBUTE_UNUSED) { + // Convert integer code to lang.opt enum codes with names. + enum opt_code code = (enum opt_code)scode; + // used to store whether results of various stuff are successful + // bool ret = true; + + // delegate to session manager + return session.handle_option(code, arg, value, kind, loc, handlers); + + // Handles options as listed in lang.opt. + /*switch (code) { + case OPT_I: + // TODO: add search path + break; + case OPT_L: + // TODO: add library link path or something + break; + case OPT_frust_dump: + // enable dump and return whether this was successful + ret = rust_enable_dump(arg) ? true : false; + break; + // no option handling for -o + default: + // return 1 to indicate option is valid + break; + } + + return ret;*/ +} + +/* Run after parsing options. */ +static bool grs_langhook_post_options(const char** pfilename ATTRIBUTE_UNUSED) { + // can be used to override other options if required + + // satisfies an assert in init_excess_precision in toplev.c + if (flag_excess_precision/*_cmdline*/ == EXCESS_PRECISION_DEFAULT) + flag_excess_precision/*_cmdline*/ = EXCESS_PRECISION_STANDARD; + + /* Returning false means that the backend should be used. */ + return false; +} + +/* Rust-specific gimplification. May need to gimplify e.g. CALL_EXPR_STATIC_CHAIN */ +static int grs_langhook_gimplify_expr(tree* expr_p ATTRIBUTE_UNUSED, + gimple_seq* pre_p ATTRIBUTE_UNUSED, gimple_seq* post_p ATTRIBUTE_UNUSED) { + /*if (TREE_CODE (*expr_p) == CALL_EXPR + && CALL_EXPR_STATIC_CHAIN (*expr_p) != NULL_TREE) + gimplify_expr (&CALL_EXPR_STATIC_CHAIN (*expr_p), pre_p, post_p, + is_gimple_val, fb_rvalue);*/ + return GS_UNHANDLED; +} + /* Create an expression whose value is that of EXPR, converted to type TYPE. The TREE_TYPE of the value is always TYPE. This function implements all reasonable @@ -240,10 +287,10 @@ static tree grs_langhook_getdecls(void) { */ #undef LANG_HOOKS_NAME #undef LANG_HOOKS_INIT -//#undef LANG_HOOKS_OPTION_LANG_MASK -//#undef LANG_HOOKS_INIT_OPTIONS_STRUCT -//#undef LANG_HOOKS_HANDLE_OPTION -//#undef LANG_HOOKS_POST_OPTIONS +#undef LANG_HOOKS_OPTION_LANG_MASK +#undef LANG_HOOKS_INIT_OPTIONS_STRUCT +#undef LANG_HOOKS_HANDLE_OPTION +#undef LANG_HOOKS_POST_OPTIONS #undef LANG_HOOKS_PARSE_FILE #undef LANG_HOOKS_TYPE_FOR_MODE #undef LANG_HOOKS_TYPE_FOR_SIZE @@ -252,15 +299,15 @@ static tree grs_langhook_getdecls(void) { #undef LANG_HOOKS_PUSHDECL #undef LANG_HOOKS_GETDECLS //#undef LANG_HOOKS_WRITE_GLOBALS -//#undef LANG_HOOKS_GIMPLIFY_EXPR +#undef LANG_HOOKS_GIMPLIFY_EXPR //#undef LANG_HOOKS_EH_PERSONALITY #define LANG_HOOKS_NAME "GNU Rust" #define LANG_HOOKS_INIT grs_langhook_init -//#define LANG_HOOKS_OPTION_LANG_MASK grs_langhook_option_lang_mask -//#define LANG_HOOKS_INIT_OPTIONS_STRUCT grs_langhook_init_options_struct -//#define LANG_HOOKS_HANDLE_OPTION grs_langhook_handle_option -//#define LANG_HOOKS_POST_OPTIONS grs_langhook_post_options +#define LANG_HOOKS_OPTION_LANG_MASK grs_langhook_option_lang_mask +#define LANG_HOOKS_INIT_OPTIONS_STRUCT grs_langhook_init_options_struct +#define LANG_HOOKS_HANDLE_OPTION grs_langhook_handle_option +#define LANG_HOOKS_POST_OPTIONS grs_langhook_post_options /* Main lang-hook, apparently. Finds input file names in global vars in_fnames and num_in_fnames * From this, frontend can take over and do actual parsing and initial compilation. * This hook must create a complete parse tree in a global var, and then return. */ @@ -272,7 +319,7 @@ static tree grs_langhook_getdecls(void) { #define LANG_HOOKS_PUSHDECL grs_langhook_pushdecl #define LANG_HOOKS_GETDECLS grs_langhook_getdecls //#define LANG_HOOKS_WRITE_GLOBALS grs_langhook_write_globals -//#define LANG_HOOKS_GIMPLIFY_EXPR grs_langhook_gimplify_expr +#define LANG_HOOKS_GIMPLIFY_EXPR grs_langhook_gimplify_expr //#define LANG_HOOKS_EH_PERSONALITY grs_langhook_eh_personality // Expands all LANG_HOOKS_x of GCC diff --git a/gcc/rust/test3/rust-session-manager.cc b/gcc/rust/test3/rust-session-manager.cc new file mode 100644 index 0000000..443818c --- /dev/null +++ b/gcc/rust/test3/rust-session-manager.cc @@ -0,0 +1,654 @@ +#include "rust-session-manager.h" + +#include "diagnostic.h" +#include "input.h" + +#include "rust-lex.h" +#include "rust-parse.h" + +#include <algorithm> + +namespace Rust { + // Simple wrapper for FILE* that simplifies destruction. + struct RAIIFile { + FILE* file; + + RAIIFile(const char* filename) : file(fopen(filename, "r")) {} + + ~RAIIFile() { + fclose(file); + } + }; + + // Implicitly enable a target_feature (and recursively enable dependencies). + void Session::implicitly_enable_feature(::std::string feature_name) { + // TODO: is this really required since features added would be complete via target spec? + + if (!options.target_data.has_key_value_pair("target_data", feature_name)) { + // if feature has dependencies, enable them + if (feature_name == "aes") { + implicitly_enable_feature("sse2"); + } else if (feature_name == "avx") { + implicitly_enable_feature("sse4.2"); + } else if (feature_name == "avx2") { + implicitly_enable_feature("avx"); + } else if (feature_name == "fma") { + implicitly_enable_feature("avx"); + } else if (feature_name == "pclmulqdq") { + implicitly_enable_feature("sse2"); + } else if (feature_name == "sha") { + implicitly_enable_feature("sse2"); + } else if (feature_name == "sse2") { + implicitly_enable_feature("sse"); + } else if (feature_name == "sse3") { + implicitly_enable_feature("sse2"); + } else if (feature_name == "sse4.1") { + implicitly_enable_feature("sse3"); + } else if (feature_name == "sse4.2") { + implicitly_enable_feature("sse4.1"); + } else if (feature_name == "ssse3") { + implicitly_enable_feature("sse3"); + } + + options.target_data.insert_key_value_pair("target_feature", ::std::move(feature_name)); + } + } + + // Meant to enable all target features. As this will be done by target hook, this method's + // deprecated. + void Session::enable_features() { + bool has_target_crt_static = false; + const char* target = "PLACEHOLDER"; + + fprintf(stderr, "ERROR: Somewhere in call chain Session::enable_features is called.\n"); + + if (has_target_crt_static) { + // enable "crt-static" attribute + } + + /* TODO: do this via target hook. have one for each target that implicitly enables the + * features for that platform. Would probably have to make custom target hook. */ + + /* + if (target == "x86" || target == "x86_64") { + if (TARGET_ISA_AES) { + // enable aes, implicitly enable sse2 + implicitly_enable_feature("aes"); + } + + if (TARGET_ISA_AVX) { + // enable avx, implicitly enable sse4.2 + implicitly_enable_feature("sse4.2"); + } + + if (TARGET_ISA_AVX2) { + // enable avx2, implicitly enable avx + implicitly_enable_feature("avx"); + } + + if (TARGET_ISA_BMI) { + // enable bmi1 + implicitly_enable_feature("bmi1"); + } + + if (TARGET_ISA_BMI2) { + // enable bmi2 + implicitly_enable_feature("bmi2"); + } + + if (TARGET_ISA_FMA) { + // enable fma, implicitly enable avx + implicitly_enable_feature("fma"); + } + + if (TARGET_ISA_FXSR) { + // enable fxsr + implicitly_enable_feature("fxsr"); + } + + if (TARGET_ISA_LZCNT) { + // enable lzcnt + implicitly_enable_feature("lzcnt"); + } + + if (TARGET_ISA_VPCLMULQDQ) { + // enable pclmulqdq, implicitly enable sse2 + implicitly_enable_feature("pclmulqdq"); + } + + if (TARGET_ISA_POPCNT) { + // enable popcnt + implicitly_enable_feature("popcnt"); + } + + if (TARGET_ISA_RDRND) { + // enable rdrand + implicitly_enable_feature("rdrand"); + } + + if (TARGET_ISA_RDSEED) { + // enable rdseed + implicitly_enable_feature("rdseed"); + } + + if (TARGET_ISA_SHA) { + // enable sha, implicitly enable sse2 + implicitly_enable_feature("sha"); + } + + if (TARGET_ISA_SSE) { + // enable sse + implicitly_enable_feature("sse"); + } + + if (TARGET_ISA_SSE2) { + // enable sse2, implicitly enable sse + implicitly_enable_feature("sse2"); + } + + if (TARGET_ISA_SSE3) { + // enable sse3, implicitly enable sse2 + implicitly_enable_feature("sse3"); + } + + if (TARGET_ISA_SSE4_1) { + // enable sse4.1, implicitly enable sse3 + implicitly_enable_feature("sse4.1"); + } + + if (TARGET_ISA_SSE4_2) { + // enable sse4.2, implicitly enable sse4.1 + implicitly_enable_feature("sse4.2"); + } + + if (TARGET_ISA_SSSE3) { + // enable ssse3, implicitly enable sse3 + implicitly_enable_feature("ssse3"); + } + + if (TARGET_ISA_XSAVE) { + // enable xsave + implicitly_enable_feature("xsave"); + } + + if (TARGET_ISA_XSAVEC) { + // enable xsavec + implicitly_enable_feature("xsavec"); + } + + if (TARGET_ISA_XSAVEOPT) { + // enable xsaveopt + implicitly_enable_feature("xsaveopt"); + } + + if (TARGET_ISA_XSAVES) { + // enable xsaves + implicitly_enable_feature("xsaves"); + } + } + options.target_data.features.shrink_to_fit(); + ::std::sort(options.target_data.features.begin(), options.target_data.features.end());*/ + } + + void Session::init() { + // nothing yet + } + + // Initialise default options. Actually called before handle_option, unlike init itself. + void Session::init_options() { + options.dump_option = CompileOptions::NO_DUMP; + } + + // Handle option selection. + bool Session::handle_option(enum opt_code code, const char* arg, + HOST_WIDE_INT value ATTRIBUTE_UNUSED, int kind ATTRIBUTE_UNUSED, + location_t loc ATTRIBUTE_UNUSED, const struct cl_option_handlers* handlers ATTRIBUTE_UNUSED) { + // used to store whether results of various stuff are successful + bool ret = true; + + // Handles options as listed in lang.opt. + switch (code) { + case OPT_I: + // TODO: add search path + break; + case OPT_L: + // TODO: add library link path or something + break; + case OPT_frust_dump_: + // enable dump and return whether this was successful + if (arg != NULL) { + ret = enable_dump(::std::string(arg)); + } else { + ret = false; + } + break; + // no option handling for -o + default: + // return 1 to indicate option is valid + break; + } + + return ret; + } + + /* Enables a certain dump depending on the name passed in. Returns true if name is valid, false + * otherwise. */ + bool Session::enable_dump(::std::string arg) { + // FIXME: change dumping algorithm when new non-inhibiting dump system is created + if (arg == "all") { + error_at( + UNKNOWN_LOCATION, "dumping all is not supported as of now. choose 'lex' or 'parse'"); + return false; + } else if (arg == "lex") { + options.dump_option = CompileOptions::LEXER_DUMP; + } else if (arg == "parse") { + options.dump_option = CompileOptions::PARSER_AST_DUMP; + } else if (arg == "register_plugins") { + options.dump_option = CompileOptions::REGISTER_PLUGINS_DUMP; + } else if (arg == "injection") { + options.dump_option = CompileOptions::INJECTION_DUMP; + } else if (arg == "expansion") { + options.dump_option = CompileOptions::EXPANSION_DUMP; + } else if (arg == "name_resolution") { + options.dump_option = CompileOptions::NAME_RESOLUTION_DUMP; + } else if (arg == "") { + error_at(UNKNOWN_LOCATION, "dump option was not given a name. choose 'lex' or 'parse'"); + return false; + } else { + error_at(UNKNOWN_LOCATION, "dump option '%s' was unrecognised. choose 'lex' or 'parse'", + arg.c_str()); + return false; + } + return true; + } + + /* Actual main entry point for front-end. Called from langhook to parse files. */ + void Session::parse_files(int num_files, const char** files) { + for (int i = 0; i < num_files; i++) { + parse_file(files[i]); + } + // TODO: should semantic analysis be dealed with here? or per file? for now, per-file. + } + + // Parses a single file with filename filename. + void Session::parse_file(const char* filename) { + RAIIFile file_wrap(filename); + + if (file_wrap.file == NULL) { + fatal_error(UNKNOWN_LOCATION, "cannot open filename %s: %m", filename); + } + + // parse file here + // create lexer and parser - these are file-specific and so aren't instance variables + Rust::Lexer lex(filename, file_wrap.file); + Rust::Parser parser(lex); + + // determine parsing method from options + /* FIXME: currently, the dump means that full compilation will not occur as of present. In + * future, dumps should not inhibit full compilation. */ + switch (options.dump_option) { + case CompileOptions::NO_DUMP: + fatal_error(UNKNOWN_LOCATION, "no-dump parsing has not been enabled yet"); + return; + case CompileOptions::LEXER_DUMP: + parser.debug_dump_lex_output(); + return; + case CompileOptions::PARSER_AST_DUMP: + parser.debug_dump_ast_output(); + return; + case CompileOptions::REGISTER_PLUGINS_DUMP: + case CompileOptions::INJECTION_DUMP: + case CompileOptions::EXPANSION_DUMP: + case CompileOptions::NAME_RESOLUTION_DUMP: + // will break later after more stages + break; + // semantic analysis when completed + default: + fatal_error(UNKNOWN_LOCATION, "unrecognised dump option: '%u'", options.dump_option); + return; + } + + /* basic pipeline: + * - lex + * - parse + * - register plugins (dummy stage for now) - attribute injection? what is this? + * (attribute injection is injecting attributes specified in command line into crate root) + * - injection (some lint checks or dummy, register builtin macros, crate injection) + * - expansion (expands all macros, maybe build test harness, AST validation, maybe macro + * crate) + * - name resolution (name resolution, maybe feature checking, maybe buffered lints) + * TODO not done */ + + // generate crate from parser + AST::Crate parsed_crate = parser.parse_crate(); + + fprintf(stderr, "\033[0;31mSUCCESSFULLY PARSED CRATE \n\033[0m"); + + // register plugins pipeline stage + register_plugins(parsed_crate); + fprintf(stderr, "\033[0;31mSUCCESSFULLY REGISTERED PLUGINS \n\033[0m"); + + if (options.dump_option == CompileOptions::REGISTER_PLUGINS_DUMP) { + // TODO: what do I dump here? + return; + } + + // injection pipeline stage + injection(parsed_crate); + fprintf(stderr, "\033[0;31mSUCCESSFULLY FINISHED INJECTION \n\033[0m"); + + if (options.dump_option == CompileOptions::INJECTION_DUMP) { + // TODO: what do I dump here? injected crate names? + return; + } + + // expansion pipeline stage + expansion(parsed_crate); + fprintf(stderr, "\033[0;31mSUCCESSFULLY FINISHED EXPANSION \n\033[0m"); + + if (options.dump_option == CompileOptions::EXPANSION_DUMP) { + // TODO: what do I dump here? expanded macros? AST with expanded macros? + return; + } + + // name resolution pipeline stage + name_resolution(parsed_crate); + fprintf(stderr, "\033[0;31mSUCCESSFULLY FINISHED NAME RESOLUTION \n\033[0m"); + + if (options.dump_option == CompileOptions::NAME_RESOLUTION_DUMP) { + // TODO: what do I dump here? resolved names? AST with resolved names? + return; + } + } + + // Checks whether 'cfg' attribute prevents compilation. + bool check_cfg(const AST::Attribute& attr ATTRIBUTE_UNUSED) { + // if "has sub items", and if 'cfg' attr, recursively call this on sub items? + + // TODO: actually implement. assume true for now + + return true; + } + // TODO: deprecated - don't use + + // Checks whether any 'cfg' attribute on the item prevents compilation of that item. + bool check_item_cfg(::std::vector<AST::Attribute> attrs) { + for (const auto& attr : attrs) { + if (attr.get_path() == "cfg" && !check_cfg(attr)) { + return false; + } + } + + return true; + } + // TODO: deprecated - don't use + + // TODO: actually implement method + void load_extern_crate(::std::string crate_name ATTRIBUTE_UNUSED) {} + // TODO: deprecated - don't use + + // Parses up to the "load (external) crates" part of the frontend. + // TODO: lots of this code is probably actually useful outside of dumping, so maybe split off + // function + void Session::debug_dump_load_crates(Parser& parser) { + // parse crate as AST + AST::Crate crate = parser.parse_crate(); + + /* TODO: search through inner attrs and see whether any of those attr paths contain "no_core", + * "no_std", "compiler_builtins". If so/not, save certain crate names. In these names, insert + * items at beginning of crate items. This is crate injection. Also, inject prelude use decl + * at beginning (first name is assumed to be prelude - prelude is a use decl automatically + * generated to enable using Option and Copy without qualifying it or importing it via 'use' + * manually) */ + + ::std::vector< ::std::string> crate_names; + for (const auto& item : crate.items) { + // if item is extern crate, add name? to list of stuff ONLY IF config is checked + // if item is module, iterate this loop inside it as well (recursive?) ONLY IF config is + // checked + + // TODO: actually do the checks somewhere - probably in the items + + item->add_crate_name(crate_names); + } + + /* loop through list of crate names/paths/whatever, attempting to load each one. save loaded + * crates to a Session variable? Or save to current AST::Crate? */ + for (const auto& name : crate_names) { + load_extern_crate(name /*, basename = ""?*/); + } + // for each loaded crate, load dependencies of it as well + } + // TODO: deprecated - don't use + + void Session::register_plugins(AST::Crate& crate ATTRIBUTE_UNUSED) { + fprintf(stderr, "ran register_plugins (with no body)\n"); + } + + // TODO: move somewhere else + bool contains_name(::std::vector<AST::Attribute> attrs, ::std::string name) { + for (const auto& attr : attrs) { + if (attr.get_path() == name) { + return true; + } + } + + return false; + } + + void Session::injection(AST::Crate& crate) { + fprintf(stderr, "started injection\n"); + + // lint checks in future maybe? + + // register builtin macros + /* In rustc, builtin macros are divided into 3 categories depending on use - "bang" macros, + * "attr" macros, and "derive" macros. I think the meanings of these categories should be + * fairly obvious to anyone who has used rust. Builtin macro list by category: Bang + * - asm + * - assert + * - cfg + * - column + * - compile_error + * - concat_idents + * - concat + * - env + * - file + * - format_args_nl + * - format_args + * - global_asm + * - include_bytes + * - include_str + * - include + * - line + * - log_syntax + * - module_path + * - option_env + * - stringify + * - trace_macros + * Attr + * - bench + * - global_allocator + * - test + * - test_case + * Derive + * - Clone + * - Copy + * - Debug + * - Default + * - Eq + * - Hash + * - Ord + * - PartialEq + * - PartialOrd + * - RustcDecodable + * - RustcEncodable + * rustc also has a "quote" macro that is defined differently and is supposedly not stable so + * eh. */ + /* TODO: actually implement injection of these macros. In particular, derive macros, cfg, and + * test should be prioritised since they seem to be used the most. */ + + // crate injection + ::std::vector< ::std::string> names; + if (contains_name(crate.inner_attrs, "no_core")) { + // no prelude + injected_crate_name = ""; + } else if (contains_name(crate.inner_attrs, "no_std")) { + names.push_back("core"); + + if (!contains_name(crate.inner_attrs, "compiler_builtins")) { + names.push_back("compiler_builtins"); + } + + injected_crate_name = "core"; + } else { + names.push_back("std"); + + injected_crate_name = "std"; + } + + // reverse iterate through names to insert crate items in "forward" order at beginning of + // crate + for (auto it = names.rbegin(); it != names.rend(); ++it) { + // create "macro use" attribute for use on extern crate item to enable loading macros from + // it + AST::Attribute attr(AST::SimplePath::from_str("macro_use"), NULL); + + // create "extern crate" item with the name + ::std::unique_ptr<AST::ExternCrate> extern_crate(new AST::ExternCrate( + *it, AST::Visibility::create_error(), { ::std::move(attr) }, UNKNOWN_LOCATION)); + + // insert at beginning + crate.items.insert(crate.items.begin(), ::std::move(extern_crate)); + } + + // create use tree path + // prelude is injected_crate_name + ::std::vector<AST::SimplePathSegment> segments + = { AST::SimplePathSegment(injected_crate_name), AST::SimplePathSegment("prelude"), + AST::SimplePathSegment("v1") }; + // create use tree and decl + ::std::unique_ptr<AST::UseTreeGlob> use_tree(new AST::UseTreeGlob( + AST::UseTreeGlob::PATH_PREFIXED, AST::SimplePath(::std::move(segments)), UNKNOWN_LOCATION)); + AST::Attribute prelude_attr(AST::SimplePath::from_str("prelude_import"), NULL); + ::std::unique_ptr<AST::UseDeclaration> use_decl(new AST::UseDeclaration(::std::move(use_tree), + AST::Visibility::create_error(), { ::std::move(prelude_attr) }, UNKNOWN_LOCATION)); + + crate.items.insert(crate.items.begin(), ::std::move(use_decl)); + + /* TODO: potentially add checking attribute crate type? I can't figure out what this does + * currently comment says "Unconditionally collect crate types from attributes to make them + * used", which presumably refers to checking the linkage info by "crate_type". It also seems + * to ensure that an invalid crate type is not specified, so maybe just do that. Valid crate + * types: bin lib dylib staticlib cdylib rlib proc-macro */ + + fprintf(stderr, "finished injection\n"); + } + + void Session::expansion(AST::Crate& crate ATTRIBUTE_UNUSED) { + fprintf(stderr, "started expansion\n"); + + // rustc has a modification to windows PATH temporarily here, which may end up being required + + // create macro expansion config? + // if not, would at least have to configure recursion_limit + + // create extctxt? from parse session, cfg, and resolver? + // expand by calling cxtctxt object's monotonic_expander's expand_crate method. + + // error reporting - check unused macros, get missing fragment specifiers + + // build test harness + + // ast validation (also with proc macro decls) + + // maybe create macro crate if not rustdoc + + fprintf(stderr, "finished expansion\n"); + } + + void Session::name_resolution(AST::Crate& crate ATTRIBUTE_UNUSED) { + fprintf(stderr, "started name resolution\n"); + + fprintf(stderr, "finished name resolution\n"); + } + + // NOTEs: + /* mrustc compile pipeline: + * - target load (pass target spec to parser?) + * - parse (convert source to AST) + * - load crates (load any explicitly mentioned extern crates [not all of them]) + * - expand (AST transformations from attributes and macros, loads remaining extern crates + * [std/core and any triggered by macro expansion]) + * - implicit crates (test harness, allocator crate, panic crate) + * - resolve use (annotate every 'use' item with source [supposedly handles nasty recursion]) + * - resolve index (generate index of visible items for every module [avoids recursion in next + * pass]) + * - resolve absolute (resolve all paths into either variable names [types/values] or absolute + * paths) + * - HIR lower (convert modified AST to simpler HIR [both expressions and module tree]) + * - resolve type aliases (replace any usages of type aliases with actual type [except associated + * types]) + * - resolve bind (iterate HIR tree and set binding annotations on all concrete types [avoids + * path lookups later]) + * - resolve HIR markings (generate "markings" [e.g. for Copy/Send/Sync/...] for all types + * - sort impls (small pass - sort impls into groups) + * - resolve UFCS outer (determine source trait for all top-level <T>::Type [qualified] paths) + * - resolve UFCS paths (do the same, but include for exprs this time. also normalises results of + * previous pass [expanding known associated types]) + * - constant evaluate (evaluate all constants) + * - typecheck outer (checks impls are sane) + * - typecheck expressions (resolve and check types for all exprs) + * - expand HIR annotate (annotate how exprs are used - used for closure extractions and + * reborrows) + * - expand HIR closures (extract closures into structs implementing Fn* traits) + * - expand HIR vtables (generate vtables for types with dyn dispatch) + * - expand HIR calls (converts method and callable calls into explicit function calls) + * - expand HIR reborrows (apply reborrow rules [taking '&mut *v' instead of 'v']) + * - expand HIR erasedtype (replace all erased types 'impl Trait' with the true type) + * - typecheck expressions (validate - double check that previous passes haven't broke type + * system rules) + * - lower MIR (convert HIR exprs into a control-flow graph [MIR]) + * - MIR validate (check that the generated MIR is consistent) + * - MIR cleanup (perform various transformations on MIR - replace reads of const items with the + * item itself; convert casts to unsized types into 'MakeDst' operations) + * - MIR optimise (perform various simple optimisations on the MIR - constant propagation, dead + * code elimination, borrow elimination, some inlining) + * - MIR validate PO (re-validate the MIR) + * - MIR validate full (optionally: perform expensive state-tracking validation on MIR) + * - trans enumerate (enumerate all items needed for code generation, primarily types used for + * generics) + * - trans auto impls (create magic trait impls as enumerated in previous pass) + * - trans monomorph (generate monomorphised copies of all functions [with generics replaced with + * real types]) + * - MIR optimise inline (run optimisation again, this time with full type info [primarily for + * inlining]) + * - HIR serialise (write out HIR dump [module tree and generic/inline MIR]) + * - trans codegen (generate final output file: emit C source file and call C compiler) */ + + /* rustc compile pipeline (basic, in way less detail): + * - parse input (parse .rs to AST) + * - name resolution, macro expansion, and configuration (process AST recursively, resolving + * paths, expanding macros, processing #[cfg] nodes [i.e. maybe stripping stuff from AST]) + * - lower to HIR + * - type check and other analyses (e.g. privacy checking) + * - lower to MIR and post-processing (and do stuff like borrow checking) + * - translation to LLVM IR and LLVM optimisations (produce the .o files) + * - linking (link together .o files) */ + + /* Pierced-together rustc compile pipeline (from source): + * - parse input (parse file to crate) + * - register plugins (attributes injection, set various options, register lints, load plugins) + * - expansion/configure and expand (initial 'cfg' processing, 'loading compiler plugins', + * syntax expansion, secondary 'cfg' expansion, synthesis of a test harness if required, + * injection of any std lib dependency and prelude, and name resolution) - actually documented + * inline + * - seeming pierced-together order: pre-AST expansion lint checks, registering builtin + * macros, crate injection, then expand all macros, then maybe build test harness, AST validation, + * maybe create a macro crate (if not rustdoc), name resolution, complete gated feature + * checking, add all buffered lints + * - create global context (lower to HIR) + * - analysis on global context (HIR optimisations? create MIR?) + * - code generation + * - link */ +}
\ No newline at end of file diff --git a/gcc/rust/test3/rust-session-manager.h b/gcc/rust/test3/rust-session-manager.h new file mode 100644 index 0000000..c268453 --- /dev/null +++ b/gcc/rust/test3/rust-session-manager.h @@ -0,0 +1,180 @@ +#ifndef RUST_SESSION_MANAGER_H +#define RUST_SESSION_MANAGER_H +// Session manager - controls compiler session. + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "options.h" +// order: config, system, coretypes, options + +#include <string> +#include <unordered_map> +#include <unordered_set> +#include <vector> +#include <utility> + +namespace Rust { + // parser forward decl + class Parser; + // crate forward decl + namespace AST { + struct Crate; + } + + // Data related to target, most useful for conditional compilation and whatever. + struct TargetOptions { + // TODO: maybe make private and access through helpers to allow changes to impl + std::unordered_map<std::string, std::unordered_set<std::string>> features; + + public: + // Returns whether a key is defined in the feature set. + bool has_key(std::string key) const { + return features.find(key) != features.end(); + } + + // Returns whether a key exists with the given value in the feature set. + bool has_key_value_pair(std::string key, std::string value) const { + auto it = features.find(key); + if (it != features.end()) { + auto set = it->second; + auto it2 = set.find(value); + if (it2 != set.end()) + return true; + } + return false; + } + + // Returns the singular value from the key, or if the key has multiple, an empty string. + std::string get_singular_value(std::string key) const { + auto it = features.find(key); + if (it != features.end()) { + auto set = it->second; + if (set.size() == 1) + return *set.begin(); + } + return ""; + } + + // Returns all values associated with a key (including none), or an empty set if no key is found. + std::unordered_set< ::std::string> get_values_for_key(std::string key) const { + auto it = features.find(key); + if (it != features.end()) { + return it->second; + } + return {}; + } + + /* Inserts a key (no value) into the feature set. This will do nothing if the key already exists. + * This returns whether the insertion was successful (i.e. whether key already existed). */ + bool insert_key(std::string key) { + return features.insert(std::make_pair(key, std::unordered_set<std::string>())).second; + } + + // Inserts a key-value pair into the feature set. + void insert_key_value_pair(std::string key, std::string value) { + auto existing_set = get_values_for_key(key); + existing_set.insert(std::move(value)); + features[std::move(key)] = std::move(existing_set); + } + + /* According to reference, Rust uses either multi-map key-values or just values (although + * values may be aliases for a key-value value). This seems like overkill. Thus, depending on + * whether the attributes used in cfg are fixed or not, I think I'll either put each + * non-multimap "key-value" as a separate field and have the multimap "key-values" in a + * regular map for that one key, or actually use a multimap. + * + * rustc itself uses a set of key-value tuples where the second tuple element is optional. + * This gets rid of the requirement to make a multi-map, I guess, but seems like it might make + * search slow (unless all "is defined"-only ones have empty string as second element). */ + /* cfg attributes: + * - target_arch: single value + * - target_feature: multiple values possible + * - target_os: single value + * - target_family: single value (or no value?) + * - unix: set when target_family = "unix" + * - windows: set when target_family = "windows" + * - if these are just syntactic sugar, then maybe have a separate set or map for this kind + * of stuff + * - target_env: set when needed for disambiguation about ABI - usually empty string for GNU, + * complicated + * - seems to be a single value (if any) + * - target_endian: single value; "little" or "big" + * - target_pointer_width: single value, "32" for 32-bit pointers, etc. + * - target_vendor, single value + * - test: set when testing is being done + * - again, seems similar to a "is defined" rather than "is equal to" like unix + * - debug_assertions: seems to "is defined" + * - proc_macro: no idea, bad docs. seems to be boolean, so maybe "is defined" */ + }; + + // Defines compiler options (e.g. dump, etc.). + struct CompileOptions { + // TODO: use bitfield for smaller memory requirements? + + // FIXME: this is set up for "instead of" dumping - in future, dumps should not inhibit + // compilation + enum DumpOptions { + NO_DUMP, + LEXER_DUMP, + PARSER_AST_DUMP, + REGISTER_PLUGINS_DUMP, + INJECTION_DUMP, + EXPANSION_DUMP, + NAME_RESOLUTION_DUMP, + // TODO: add more? + } dump_option; + + // configuration options - actually useful for conditional compilation and whatever + // data related to target arch, features, os, family, env, endian, pointer width, vendor + TargetOptions target_data; + bool enable_test = false; + bool debug_assertions = false; + bool proc_macro = false; + }; + + /* Defines a compiler session. This is for a single compiler invocation, so potentially includes + * parsing multiple crates. */ + struct Session { + CompileOptions options; + // This should really be in a per-crate storage area but it is wiped with every file so eh. + ::std::string injected_crate_name; + + public: + /* Initialise compiler session. Corresponds to langhook grs_langhook_init(). Note that this is + * called after option handling. */ + void init(); + bool handle_option(enum opt_code code, const char* arg, HOST_WIDE_INT value, int kind, + location_t loc, const struct cl_option_handlers* handlers); + void parse_files(int num_files, const char** files); + void init_options(); + + private: + // TODO: should this be private or public? + void parse_file(const char* filename); + bool enable_dump(::std::string arg); + + void debug_dump_load_crates(Parser& parser); + + void implicitly_enable_feature(::std::string feature_name); + void enable_features(); + + // pipeline stages - TODO maybe move? + /* Register plugins pipeline stage. TODO maybe move to another object? Currently dummy stage. + * In future will handle attribute injection (top-level inner attribute creation from command + * line arguments), setting options maybe, registering lints maybe, loading plugins maybe. */ + void register_plugins(AST::Crate& crate); + /* Injection pipeline stage. TODO maybe move to another object? Maybe have some lint checks + * (in future, obviously), register builtin macros, crate injection. */ + void injection(AST::Crate& crate); + /* Expansion pipeline stage. TODO maybe move to another object? Expands all macros, maybe + * build test harness in future, AST validation, maybe create macro crate (if not rustdoc).*/ + void expansion(AST::Crate& crate); + /* Name resolution pipeline stage. TODO maybe move to another object. Performs name + * resolution, maybe complete gated feature checking, maybe create buffered lints in future. + */ + void name_resolution(AST::Crate& crate); + }; +} + +#endif
\ No newline at end of file |