int jdip::context_parser::handle_scope(definition_scope *scope, token_t& token, unsigned inherited_flags) { definition* decl; token = read_next_token(scope); for (;;) { switch (token.type) { case TT_TYPENAME: case TT_DECFLAG: case TT_DECLTYPE: case TT_DECLARATOR: case_TT_DECLARATOR: case TT_CLASS: case TT_STRUCT: case TT_ENUM: case TT_UNION: case TT_TILDE: decl = NULL; handle_declarator_block: if (handle_declarators(scope, token, inherited_flags, decl)) { FATAL_RETURN(1); while (token.type != TT_ENDOFCODE and token.type != TT_SEMICOLON and token.type != TT_LEFTBRACE and token.type != TT_RIGHTBRACE) token = read_next_token(scope); } handled_declarator_block: if (token.type != TT_SEMICOLON) { if (token.type == TT_LEFTBRACE || token.type == TT_ASM) { if (!(decl and decl->flags & DEF_OVERLOAD)) { token.report_error(herr, "Unexpected opening brace here; declaration is not a function"); FATAL_RETURN(1); handle_function_implementation(lex,token,scope,herr); } else { definition_overload *ovr = ((definition_overload*)decl); if (ovr->implementation != NULL) { token.report_error(herr, "Multiple implementations of function" FATAL_TERNARY("", "; old implementation discarded")); delete_function_implementation(ovr->implementation); } ovr->implementation = handle_function_implementation(lex,token,scope,herr); } if (token.type != TT_RIGHTBRACE && token.type != TT_SEMICOLON) { token.report_error(herr, "Expected closing symbol to function"); continue; } } else { token.report_errorf(herr, "Expected semicolon before %s following declaration"); #if FATAL_ERRORS return 1; #else semicolon_bail: while (token.type != TT_SEMICOLON && token.type != TT_LEFTBRACE && token.type != TT_RIGHTBRACE && token.type != TT_ENDOFCODE) token = read_next_token(scope); if (token.type == TT_LEFTBRACE) { size_t depth = 1; while (token.type != TT_ENDOFCODE) { token = read_next_token(scope); if (token.type == TT_LEFTBRACE) ++depth; else if (token.type == TT_RIGHTBRACE) if (!--depth) break; } } #endif } } break; case TT_EXTERN: token = read_next_token(scope); if (token.type == TT_STRINGLITERAL) { token = read_next_token(scope); if (token.type == TT_LEFTBRACE) { FATAL_RETURN_IF(handle_scope(scope, token, inherited_flags), 1); if (token.type != TT_RIGHTBRACE) { token.report_error(herr, "Expected closing brace to extern block"); FATAL_RETURN(1); } break; } } else if (token.type == TT_TEMPLATE) { token = read_next_token(scope); if (token.type != TT_CLASS and token.type != TT_STRUCT and token.type != TT_DECLARATOR and token.type != TT_DECFLAG and token.type != TT_DEFINITION) { token.report_errorf(herr, "Expected template specialization following `extern template' directive; %s unhandled"); FATAL_RETURN(1); } if (handle_template_extern(scope, token, inherited_flags)) FATAL_RETURN(1); break; } goto handle_declarator_block; case TT_COMMA: token.report_error(herr, "Unexpected comma at this point."); return 1; case TT_SEMICOLON: /* Printing a warning here is advisable but unnecessary. */ break; case TT_NAMESPACE: if (handle_namespace(scope,token)) return 1; break; case TT_LEFTPARENTH: { token.report_error(herr, "Stray opening parenthesis."); #if FATAL_ERRORS return 1; #else int bc = 1; while (bc) { token = read_next_token(scope); bc += token.type == TT_LEFTPARENTH; bc -= token.type == TT_RIGHTPARENTH; } #endif } break; case TT_RIGHTPARENTH: token.report_error(herr, "Stray closing parenthesis."); return 1; case TT_LEFTBRACKET: token.report_error(herr, "Stray opening bracket."); return 1; case TT_RIGHTBRACKET: token.report_error(herr, "Stray closing bracket."); return 1; case TT_RIGHTBRACE: return 0; case TT_LEFTBRACE: { token.report_error(herr, "Expected scope declaration before opening brace."); #if FATAL_ERRORS return 1; #else int bc = 1; while (bc) { token = read_next_token(scope); if (token.type == TT_ENDOFCODE) { token.report_error(herr, "Expected closing brace before end of code."); return 1; } bc += token.type == TT_LEFTBRACE; bc -= token.type == TT_RIGHTBRACE; } #endif } break; case TT_TYPEDEF: token = read_next_token(scope); if (handle_declarators(scope,token,inherited_flags | DEF_TYPENAME)) FATAL_RETURN(1); break; case TT_PUBLIC: if (scope->flags & DEF_CLASS) { inherited_flags &= ~(DEF_PRIVATE | DEF_PROTECTED); } else token.report_error(herr, "Unexpected `public' token outside class scope."); if ((token = read_next_token(scope)).type != TT_COLON) token.report_error(herr, "Colon expected following `public' token"); break; case TT_PRIVATE: if (scope->flags & DEF_CLASS) { inherited_flags &= ~(DEF_PRIVATE | DEF_PROTECTED); inherited_flags |= DEF_PRIVATE; } else token.report_error(herr, "Unexpected `private' token outside class scope."); if ((token = read_next_token(scope)).type != TT_COLON) token.report_error(herr, "Colon expected following `private' token"); break; case TT_PROTECTED: if (scope->flags & DEF_CLASS) { inherited_flags &= ~(DEF_PRIVATE | DEF_PROTECTED); inherited_flags |= DEF_PROTECTED; } else token.report_error(herr, "Unexpected `protected' token outside class scope."); if ((token = read_next_token(scope)).type != TT_COLON) token.report_error(herr, "Colon expected following `protected' token"); break; case TT_FRIEND: if (!(scope->flags & DEF_CLASS)) { token.report_error(herr, "`friend' statement may only appear in a class or structure"); FATAL_RETURN(1); while ((token = read_next_token(scope)).type != TT_SEMICOLON && token.type != TT_RIGHTBRACE && token.type != TT_ENDOFCODE); } else { if (handle_friend(scope, token, (definition_class*)scope)) FATAL_RETURN(1); if (token.type == TT_SEMICOLON) token = read_next_token(scope); else { token.report_errorf(herr, "Expected semicolon before %s"); FATAL_RETURN(1); } } continue; case TT_USING: token = read_next_token(scope); if (token.type == TT_NAMESPACE) { token = lex->get_token_in_scope(scope, herr); if (token.type == TT_DEFINITION) { definition *d = read_qualified_definition(token, scope); if (!d) { token.report_errorf(herr, "Expected namespace-name following `namespace' token"); FATAL_RETURN(1); } else { if (d->flags & DEF_NAMESPACE) scope->use_namespace((definition_scope*)d); else token.report_error(herr, "Expected namespace-name following `namespace' token"); } if (token.type == TT_SEMICOLON) token = read_next_token(scope); else { token.report_errorf(herr, "Expected semicolon before %s"); FATAL_RETURN(1); } } else { token.report_errorf(herr, "Expected namespace to use before %s"); FATAL_RETURN(1); } } else { definition *usedef = read_qualified_definition(token, scope); if (usedef) scope->use_general(usedef->name, usedef); else { token.report_errorf(herr, "Using directive does not specify an object"); FATAL_RETURN(1); } if (token.type != TT_SEMICOLON) { token.report_errorf(herr, "Expected semicolon before %s to terminate using directive"); FATAL_RETURN(1); } } continue; case TT_SCOPE: token = read_next_token(ctex->get_global()); continue; case TT_MEMBEROF: token.report_error(herr, "Unexpected (scope::*) reference"); return 1; case TT_STATIC_ASSERT: token.report_error(herr, "Unimplemented: static assert"); break; case TT_AUTO: token.report_error(herr, "Unimplemented: `auto' type inference"); break; case TT_CONSTEXPR: token.report_error(herr, "Unimplemented: const expressions outside enum"); break; case TT_DEFINITION: { if (token.def->flags & DEF_NAMESPACE) { definition_scope* dscope = (definition_scope*)token.def; token = read_next_token(scope); if (token.type == TT_SCOPE) { token = read_next_token(dscope); continue; } token.report_errorf(herr, "Expected `::' here to access namespace members"); FATAL_RETURN(1); break; } if (token.def->flags & DEF_TEMPLATE) goto case_TT_DECLARATOR; } case TT_IDENTIFIER: { string tname(token.content.toString()); if (tname == scope->name and (scope->flags & DEF_CLASS)) { token = read_next_token(scope); if (token.type != TT_LEFTPARENTH) { token.report_errorf(herr, "Expected constructor parmeters before %s"); break; } full_type ft; ft.def = scope; token = read_next_token(scope); read_function_params(ft.refs, token, scope); if (handle_declarators(scope,token,ft,inherited_flags | DEF_TYPENAME,decl)) FATAL_RETURN(1); goto handled_declarator_block; } token.report_error(herr, "Unexpected identifier in this scope (" + scope->name + "); `" + tname + "' does not name a type"); } break; case TT_TEMPLATE: if (handle_template(scope, token, inherited_flags)) { FATAL_RETURN(1); goto semicolon_bail; } break; case TT_OPERATORKW: { full_type ft = read_operatorkw_cast_type(token, scope); if (!ft.def) return 1; if (!(decl = scope->overload_function("(cast)", ft, inherited_flags, token, herr))) return 1; goto handled_declarator_block; } break; case TT_ASM: case TT_SIZEOF: case TT_ISEMPTY: case TT_ALIGNOF: case TT_ALIGNAS: case TT_OPERATOR: case TT_ELLIPSIS: case TT_LESSTHAN: case TT_GREATERTHAN: case TT_COLON: case TT_DECLITERAL: case TT_HEXLITERAL: case TT_OCTLITERAL: case TT_STRINGLITERAL: case TT_CHARLITERAL: case TT_NEW: case TT_DELETE: case TTM_CONCAT: case TTM_TOSTRING: case TT_INVALID: case TT_CONST_CAST: case TT_STATIC_CAST: case TT_DYNAMIC_CAST: case TT_REINTERPRET_CAST: case TT_NOEXCEPT: case TT_TYPEID: #include <User/token_cases.h> default: token.report_errorf(herr, "Unexpected %s in this scope"); break; case TT_ENDOFCODE: return 0; } token = read_next_token(scope); } }
int jdip::context_parser::handle_scope(definition_scope *scope, token_t& token, unsigned inherited_flags) { definition* decl; token = read_next_token(scope); for (;;) { switch (token.type) { case TT_TYPENAME: case TT_DECFLAG: case TT_DECLTYPE: case TT_DECLARATOR: case_TT_DECLARATOR: case TT_CLASS: case TT_STRUCT: case TT_ENUM: case TT_UNION: case TT_TILDE: decl = NULL; handle_declarator_block: if (handle_declarators(scope, token, inherited_flags, decl)) { FATAL_RETURN(1); while (token.type != TT_ENDOFCODE and token.type != TT_SEMICOLON and token.type != TT_LEFTBRACE and token.type != TT_RIGHTBRACE) token = read_next_token(scope); } handled_declarator_block: if (token.type != TT_SEMICOLON) { if (token.type == TT_LEFTBRACE || token.type == TT_ASM) { if (!(decl and decl->flags & DEF_FUNCTION)) { token.report_error(herr, "Unexpected opening brace here; declaration is not a function"); FATAL_RETURN(1); handle_function_implementation(lex,token,scope,herr); } else ((definition_function*)decl)->implementation = handle_function_implementation(lex,token,scope,herr); if (token.type != TT_RIGHTBRACE && token.type != TT_SEMICOLON) { token.report_error(herr, "Expected closing symbol to function"); continue; } } else { token.report_errorf(herr, "Expected semicolon before %s following declaration"); #if FATAL_ERRORS return 1; #else semicolon_bail: while (token.type != TT_SEMICOLON && token.type != TT_LEFTBRACE && token.type != TT_RIGHTBRACE && token.type != TT_ENDOFCODE) token = read_next_token(scope); if (token.type == TT_LEFTBRACE) { size_t depth = 1; while (token.type != TT_ENDOFCODE) { token = read_next_token(scope); if (token.type == TT_LEFTBRACE) ++depth; else if (token.type == TT_RIGHTBRACE) if (!--depth) break; } } #endif } } break; case TT_EXTERN: token = read_next_token(scope); if (token.type == TT_STRINGLITERAL) { token = read_next_token(scope); if (token.type == TT_LEFTBRACE) { FATAL_RETURN_IF(handle_scope(scope, token, inherited_flags), 1); if (token.type != TT_RIGHTBRACE) { token.report_error(herr, "Expected closing brace to extern block"); FATAL_RETURN(1); } break; } } else if (token.type == TT_TEMPLATE) { token = read_next_token(scope); if (token.type != TT_CLASS and token.type != TT_STRUCT and token.type != TT_DECLARATOR and token.type != TT_DEFINITION) { token.report_errorf(herr, "Expected template specialization following `extern template' directive; %s unhandled"); FATAL_RETURN(1); } } goto handle_declarator_block; case TT_COMMA: token.report_error(herr, "Unexpected comma at this point."); return 1; case TT_SEMICOLON: /* Printing a warning here is advisable but unnecessary. */ break; case TT_NAMESPACE: if (handle_namespace(scope,token)) return 1; break; case TT_LEFTPARENTH: { token.report_error(herr, "Stray opening parenthesis."); #if FATAL_ERRORS return 1; #else int bc = 1; while (bc) { token = read_next_token(scope); bc += token.type == TT_LEFTPARENTH; bc -= token.type == TT_RIGHTPARENTH; } #endif } break; case TT_RIGHTPARENTH: token.report_error(herr, "Stray closing parenthesis."); return 1; case TT_LEFTBRACKET: token.report_error(herr, "Stray opening bracket."); return 1; case TT_RIGHTBRACKET: token.report_error(herr, "Stray closing bracket."); return 1; case TT_RIGHTBRACE: return 0; case TT_LEFTBRACE: { token.report_error(herr, "Expected scope declaration before opening brace."); #if FATAL_ERRORS return 1; #else int bc = 1; while (bc) { token = read_next_token(scope); if (token.type == TT_ENDOFCODE) { token.report_error(herr, "Expected closing brace before end of code."); return 1; } bc += token.type == TT_LEFTBRACE; bc -= token.type == TT_RIGHTBRACE; } #endif } break; case TT_TYPEDEF: token = read_next_token(scope); if (handle_declarators(scope,token,inherited_flags | DEF_TYPENAME)) FATAL_RETURN(1); break; case TT_PUBLIC: if (scope->flags & DEF_CLASS) { inherited_flags &= ~(DEF_PRIVATE | DEF_PROTECTED); } else token.report_error(herr, "Unexpected `public' token outside class scope."); if ((token = read_next_token(scope)).type != TT_COLON) token.report_error(herr, "Colon expected following `public' token"); break; case TT_PRIVATE: if (scope->flags & DEF_CLASS) { inherited_flags &= ~(DEF_PRIVATE | DEF_PROTECTED); inherited_flags |= DEF_PRIVATE; } else token.report_error(herr, "Unexpected `private' token outside class scope."); if ((token = read_next_token(scope)).type != TT_COLON) token.report_error(herr, "Colon expected following `private' token"); break; case TT_PROTECTED: if (scope->flags & DEF_CLASS) { inherited_flags &= ~(DEF_PRIVATE | DEF_PROTECTED); inherited_flags |= DEF_PROTECTED; } else token.report_error(herr, "Unexpected `protected' token outside class scope."); if ((token = read_next_token(scope)).type != TT_COLON) token.report_error(herr, "Colon expected following `protected' token"); break; case TT_USING: token = read_next_token(scope); if (token.type == TT_NAMESPACE) { token = lex->get_token(herr); if (token.type == TT_IDENTIFIER) { definition* d = scope->look_up(token.content.toString()); if (!d) { token.report_errorf(herr, "Expected id to use before %s"); FATAL_RETURN(1); } else { if (d->flags & DEF_NAMESPACE) scope->use_namespace((definition_scope*)d); else token.report_error(herr, "Expected namespace name following `namespace' token"); } token = read_next_token(scope); } else token.report_error(herr, "Expected namespace name following `namespace' token"); } else { definition *usedef = read_qualified_definition(lex, scope, token, this, herr); if (usedef) scope->use_general(usedef->name, usedef); else { token.report_errorf(herr, "Using directive does not specify an object"); FATAL_RETURN(1); } if (token.type != TT_SEMICOLON) { token.report_errorf(herr, "Expected semicolon before %s to terminate using directive"); FATAL_RETURN(1); } } break; case TT_SCOPE: token = read_next_token(global); continue; case TT_DEFINITION: { if (token.def->flags & DEF_NAMESPACE) { definition_scope* dscope = (definition_scope*)token.def; token = read_next_token(scope); if (token.type == TT_SCOPE) { token = read_next_token(dscope); continue; } token.report_errorf(herr, "Expected `::' here to access namespace members"); FATAL_RETURN(1); break; } if (token.def->flags & DEF_TEMPLATE) goto case_TT_DECLARATOR; } case TT_IDENTIFIER: { string tname(token.content.toString()); if (tname == scope->name and (scope->flags & DEF_CLASS)) { token = read_next_token(scope); if (token.type != TT_LEFTPARENTH) { token.report_errorf(herr, "Expected constructor parmeters before %s"); break; } full_type ft; ft.def = scope; token = read_next_token(scope); read_function_params(ft.refs, lex, token, scope, this, herr); if (handle_declarators(scope,token,ft,inherited_flags | DEF_TYPENAME,decl)) FATAL_RETURN(1); goto handled_declarator_block; } token.report_error(herr, "Unexpected identifier in this scope; `" + tname + "' does not name a type"); } break; case TT_TEMPLATE: if (handle_template(scope, token, inherited_flags)) { FATAL_RETURN(1); goto semicolon_bail; } break; case TT_OPERATORKW: token = read_next_token(scope); if (token.type != TT_DECLARATOR and token.type != TT_DECFLAG and token.type != TT_DECLTYPE) { token.report_errorf(herr, "Expected cast type to overload before %s"); FATAL_RETURN(1); } else { lex_buffer lb(lex); while (token.type != TT_LEFTPARENTH and token.type != TT_LEFTBRACE and token.type != TT_SEMICOLON and token.type != TT_ENDOFCODE) lb.push(token), token = read_next_token(scope); if (token.type != TT_LEFTPARENTH) { token.report_error(herr, "Expected function parmeters before %s"); FATAL_RETURN(1); break; } token.type = TT_ENDOFCODE; lb.push(token); token.type = TT_LEFTPARENTH; lb.reset(); token_t kick = lb.get_token(herr); full_type ft = read_fulltype(&lb, kick, scope, this, herr); string opname; { ref_stack my_func_refs; read_referencers_post(my_func_refs, lex, token, scope, this, herr); if (my_func_refs.empty() or my_func_refs.top().type != ref_stack::RT_FUNCTION) { token.report_error(herr, "Expected function parameters for operator overload"); return 1; } opname = "operator " + ft.toString(); ft.refs.append_c(my_func_refs); } definition_function *const df = new definition_function(opname, scope, ft.def, ft.refs, ft.flags, inherited_flags); decl = df; decpair ins = scope->declare(decl->name, decl); if (!ins.inserted) { arg_key k(df->referencers); decl = ((definition_function*)ins.def)->overload(k, df, herr); } goto handled_declarator_block; } break; case TT_ASM: case TT_SIZEOF: case TT_ISEMPTY: case TT_OPERATOR: case TT_ELLIPSIS: case TT_LESSTHAN: case TT_GREATERTHAN: case TT_COLON: case TT_DECLITERAL: case TT_HEXLITERAL: case TT_OCTLITERAL: case TT_STRINGLITERAL: case TT_CHARLITERAL: case TT_NEW: case TT_DELETE: case TTM_CONCAT: case TTM_TOSTRING: case TT_INVALID: #include <User/token_cases.h> default: token.report_errorf(herr, "Unexpected %s in this scope"); break; case TT_ENDOFCODE: return 0; } token = read_next_token(scope); } }
int context_parser::handle_template(definition_scope *scope, token_t& token, unsigned inherited_flags) { token = read_next_token(scope); if (token.type != TT_LESSTHAN) { token.report_error(herr, "Expected opening triangle bracket following `template' token"); return ERROR_CODE; } token = read_next_token(scope); definition_template* temp = new definition_template("", scope, DEF_TEMPLATE | inherited_flags); for (;;) { string pname; // The name given to this parameter unsigned dtpflags = DEF_TEMPPARAM | DEF_DEPENDENT; definition_tempparam* dtn; if (token.type == TT_TYPENAME || token.type == TT_CLASS || token.type == TT_STRUCT) { token = lex->get_token(herr); if (token.type == TT_IDENTIFIER) { pname = token.content.toString(); token = read_next_token(temp); } dtpflags |= DEF_TYPENAME; } else if (token.type == TT_DECFLAG || token.type == TT_DECLARATOR || token.type == TT_DECLTYPE) { full_type fts = read_fulltype(token, temp); pname = fts.refs.name; } else { if (token.type == TT_GREATERTHAN) break; token.report_errorf(herr, "Expected '>' token here before %s"); FATAL_RETURN((delete temp, 1)); break; } AST *ast = NULL; if (token.type == TT_OPERATOR) { if (token.content.len != 1 or *token.content.str != '=') { token.report_error(herr, "Unexpected operator here; value must be denoted by '='"); FATAL_RETURN((void(delete temp),1)); } token = read_next_token(temp); ast = new AST(); ast->set_use_for_templates(true); astbuilder->parse_expression(ast, token, temp, precedence::comma+1); } dtn = new definition_tempparam(pname, temp, ast, dtpflags); temp->params.push_back(dtn); if (pname.empty()) { char nname[32]; sprintf(nname, "<templateParam%03u>", (unsigned)temp->params.size()); } else temp->use_general(pname, dtn); if (token.type == TT_GREATERTHAN) break; if (token.type != TT_COMMA) token.report_errorf(herr, "Expected '>' or ',' before %s"); token = read_next_token(temp); } token = read_next_token(temp); // ======================================================================================================================================== // =====: Handle template class definitions :============================================================================================== // ======================================================================================================================================== if (token.type == TT_CLASS || token.type == TT_STRUCT) { unsigned protection = token.type == TT_CLASS? DEF_PRIVATE : 0; token = read_next_token(scope); definition_class *tclass; if (token.type == TT_IDENTIFIER) { regular_identifier: temp->name = token.content.toString(); tclass = new definition_class(temp->name, temp, DEF_CLASS | DEF_TYPENAME); temp->def = tclass; scope->declare(temp->name, temp); token = read_next_token(scope); regular_template_class: if (token.type == TT_COLON) { if (handle_class_inheritance(tclass, token, tclass, protection)) return 1; } if (token.type != TT_LEFTBRACE) { if (token.type == TT_SEMICOLON) { tclass->flags |= DEF_INCOMPLETE; return 0; } token.report_errorf(herr, "Opening brace for class body expected before %s"); return 1; } if (handle_scope(tclass, token, protection)) FATAL_RETURN(1); if (token.type != TT_RIGHTBRACE) { token.report_errorf(herr, "Expected closing brace to class body before %s"); FATAL_RETURN(1); } return 0; } else if (token.type == TT_DEFINITION) { if (token.def->parent != scope) goto regular_identifier; if (not((token.def->flags & DEF_TEMPLATE) && (((definition_template*)token.def)->def->flags & DEF_CLASS))) { token.report_error(herr, "Expected class name for specialization; `" + token.def->name + "' does not name a template class"); delete temp; return 1; } definition_template *basetemp = (definition_template*)token.def; token = read_next_token(temp); if (token.type != TT_LESSTHAN) { if (basetemp->def && (basetemp->def->flags & (DEF_CLASS | DEF_INCOMPLETE)) == (DEF_CLASS | DEF_INCOMPLETE)) { if (basetemp->params.size() != temp->params.size()) { token.report_error(herr, "Argument count differs from forward declaration"); delete temp; return 1; } for (size_t i = 0; i < basetemp->params.size(); ++i) { if (basetemp->params[i]->flags != temp->params[i]->flags) { token.report_error(herr, "Parameter " + value((long)i).toString() + " of declaration differs from forward"); delete temp; return 1; } if (!temp->params[i]->name.empty() && basetemp->params[i]->name != temp->params[i]->name) { definition_scope::defiter it = basetemp->using_general.find(basetemp->params[i]->name); if (it != basetemp->using_general.end()) if (it->second == basetemp->params[i]) basetemp->using_general.erase(it); else token.report_warning(herr, "Template parameter `" + basetemp->params[i]->name + "' in forward declaration's using is not mapped to `" + temp->params[i]->name + "'"); else if (!basetemp->params[i]->name.empty()) token.report_warning(herr, "Template parameter `" + basetemp->params[i]->name + "' not found in forward declaration's using; cannot be renamed to `" + temp->params[i]->name + "'"); basetemp->params[i]->name = temp->params[i]->name; basetemp->use_general(basetemp->params[i]->name, basetemp->params[i]); } } delete temp; temp = basetemp; tclass = (definition_class*)temp->def; goto regular_template_class; } token.report_errorf(herr, "Expected opening triangle bracket for template definition before %s"); delete temp; return 1; } arg_key argk(basetemp->params.size()); definition_template::specialization *spec = new definition_template::specialization(basetemp->params.size(), temp->params.size(), temp); argk.mirror_types(basetemp); size_t args_given = 0; for (;;++args_given) { token = read_next_token(temp); if (token.type == TT_GREATERTHAN) break; if (token.type == TT_SEMICOLON || token.type == TT_LEFTBRACE) { token.report_errorf(herr, "Expected closing triangle bracket to template parameters before %s"); break; } if (token.type == TT_COMMA) continue; if (args_given >= basetemp->params.size()) { token.report_error(herr, "Too many parameters for template `" + basetemp->name + "'"); delete temp; return 1; } if ((argk[args_given].type == arg_key::AKT_VALUE) and (token.type == TT_DEFINITION or token.type == TT_DECLARATOR) and (token.def->flags & DEF_TEMPPARAM)) { for (size_t i = 0; i < temp->params.size(); ++i) if (temp->params[i] == token.def) { if (~temp->params[i]->flags & DEF_TYPENAME) { spec->key.arg_inds[i][++spec->key.arg_inds[i][0]] = args_given; argk[args_given].val() = VT_DEPENDENT; token = read_next_token(temp); goto handled_argk; // break 2; } else token.report_error(herr, "Type mismatch in passing parameter " + parse_bacics::visible::toString(args_given) + " to template specialization: real-valued parameter expected"); } } if (read_template_parameter(argk, args_given, basetemp, token, temp)) { delete temp; // XXX: is this needed? return 1; } if (argk[args_given].type == arg_key::AKT_FULLTYPE) { definition *def = argk[args_given].ft().def; for (size_t i = 0; i < temp->params.size(); ++i) if (temp->params[i] == def) { spec->key.arg_inds[i][++spec->key.arg_inds[i][0]] = args_given; argk[args_given].ft().def = arg_key::abstract; } } handled_argk: if (token.type == TT_GREATERTHAN) { ++args_given; break; } if (token.type != TT_COMMA) { token.report_errorf(herr, "Comma or closing triangle bracket expected here before %s"); break; } } if (check_read_template_parameters(argk, args_given, basetemp, token, herr)) { delete temp; // XXX: Needed? return 1; } // cout << "Specialization key: " << argk.toString() << endl; spec->filter = argk; definition_template::speclist &slist = basetemp->specializations; for (definition_template::speclist::iterator it = slist.begin(); it != slist.end(); ++it) if ((*it)->key.same_as(spec->key)) { delete spec; spec = *it; if (~spec->spec_temp->flags & DEF_INCOMPLETE) { token.report_error(herr, "Cannot specialize template: specialization by this type already exists."); delete temp; return 1; } spec->spec_temp->using_general.clear(); // XXX: Maybe replace this with something to specifically delete template parameters, just in case? Could anything else be used? I'm thinking not. for (definition_template::piterator pit = temp->params.begin(); pit != temp->params.end(); ++pit) spec->spec_temp->use_general((*pit)->name, *pit); delete temp; temp = spec->spec_temp; break; } slist.push_back(spec); temp->name = basetemp->name + "<" + argk.toString() + ">"; tclass = new definition_class(temp->name, temp, DEF_CLASS | DEF_TYPENAME); temp->def = tclass; tclass->instance_of = basetemp; token = read_next_token(scope); goto regular_template_class; } token.report_errorf(herr, "Expected class name here before %s"); delete temp; return 1; } // ======================================================================================================================================== // =====: Handle template function definitions :=========================================================================================== // ======================================================================================================================================== int funcflags = 0; if (token.type == TT_DECLARATOR || token.type == TT_DECFLAG || token.type == TT_DECLTYPE || token.type == TT_DEFINITION || token.type == TT_TYPENAME) { full_type funcrefs = read_fulltype(token, temp); if (!funcrefs.def) { if (token.type == TT_OPERATORKW) { funcflags = funcrefs.flags; if (!funcrefs.refs.empty()) { token.report_error(herr, "Program error: references attatched to typeless expression"); return 1; } goto template_cast_operator; } token.report_error(herr, "Expected return type for template function at this point"); delete temp; return 1; } if (funcrefs.refs.empty() || funcrefs.refs.top().type != ref_stack::RT_FUNCTION) { if (token.type == TT_DEFINITION && in_template(token.def)) { read_qualified_definition(token, scope); // We don't need to know the definition, just skip it. If we were a compiler, we'd need to know this. :P if (token.type == TT_OPERATOR && token.content.len == 1 && *token.content.str == '=') { // We don't need to know the value, either; we just need to skip it. token = read_next_token(scope); AST a; astbuilder->parse_expression(&a, token, scope, precedence::comma); // Read and discard; kind of a hack, but it's safe. } if (token.type != TT_SEMICOLON) { if (token.type == TT_LEFTPARENTH) // We're implementing a template function within a different class { read_referencers_post(funcrefs.refs, token, temp); if (token.type == TT_LEFTBRACE) delete_function_implementation(handle_function_implementation(lex, token, temp, herr)); else token.report_error(herr, "I have no idea where I am."); delete temp; return 0; } token.report_errorf(herr, "Expected semicolon following template member definition before %s"); FATAL_RETURN((void(delete temp), 1)); } delete temp; // We're done with temp. return 0; } if (funcrefs.refs.ndef && funcrefs.refs.ndef->flags & DEF_HYPOTHETICAL) { // TODO: Do some error checking here to make sure whatever's being declared in that AST is a member of the template. Mark it non-extern. } else if (funcrefs.refs.ndef && (funcrefs.refs.ndef->flags & DEF_TYPED)) { definition_typed* dt = (definition_typed*)funcrefs.refs.ndef; if (dt->modifiers & builtin_flag__static) dt->flags &= ~DEF_INCOMPLETE; // TODO: Make structures OR static members by DEF_INCOMPLETE on creation; add error checking here else token.report_error(herr, "Definition of non-static member `" + dt->name + "'"); } else token.report_errorf(herr, "Definition in template must be a function; `" + funcrefs.def->name + " " + funcrefs.refs.name + "' is not a function (at %s)"); delete temp; return 1; } string funcname = funcrefs.refs.name; if (funcname.empty()) { if ((funcrefs.refs.ndef && funcrefs.refs.ndef->name == constructor_name) || is_potential_constructor(scope, funcrefs)) { funcname = constructor_name; if (token.type == TT_COLON) { // TODO: Actually store this. And the other one. :P handle_constructor_initializers(lex, token, scope, herr); } } else if (!funcrefs.refs.ndef) { token.report_error(herr, "Template functions must have names"); delete temp; return 1; } } definition_function *func = NULL; definition *maybe = funcrefs.refs.ndef; if (!maybe) maybe = scope->find_local(funcname); if (maybe) if (!(maybe->flags & DEF_FUNCTION)) { token.report_error(herr, "Cannot redeclare " + maybe->kind() + " `" + funcname + "' as function in this scope"); delete temp; return 1; } else func = (definition_function*)maybe; else {} definition_overload *tovr = new definition_overload(funcname, scope, funcrefs.def, funcrefs.refs, funcrefs.flags, DEF_FUNCTION); temp->def = tovr; if (!func) scope->declare(funcname, func = new definition_function(funcname, scope)); func->overload(temp, herr); if (token.type == TT_COLON) { token.report_error(herr, "Unexpected colon; `" + funcname + "' is not a constructor"); return 1; } if (token.type == TT_LEFTBRACE) tovr->implementation = (handle_function_implementation(lex, token, temp, herr)); else if (token.type != TT_SEMICOLON) { token.report_errorf(herr, "Expected template function body or semicolon before %s"); FATAL_RETURN(1); } } else if (token.type == TT_OPERATORKW) { template_cast_operator: full_type ft = read_operatorkw_cast_type(token, temp); definition_overload *ovr = new definition_overload("(cast)", scope, ft.def, ft.refs, ft.flags, DEF_FUNCTION | inherited_flags | funcflags); if (!ovr) return 1; if (token.type == TT_LEFTBRACE) ovr->implementation = handle_function_implementation(lex, token, scope, herr); else ovr->flags |= DEF_INCOMPLETE; temp->def = ovr; scope->overload_function("(cast)", temp, inherited_flags | funcflags, token, herr); return 0; } else if (token.type == TT_TEMPLATE) { // FIXME: OH MY F*****G WHAT // These templates are used when declaring functions which have templates as parameters, handle_template(temp, token, inherited_flags); delete temp; return 0; } else if (token.type == TT_FRIEND) { if (scope->flags & DEF_CLASS) { token = read_next_token(scope); if (token.type == TT_CLASS) { read_qualified_definition(token, temp); delete temp; if (token.type != TT_SEMICOLON) token.report_errorf(herr, "Expected semicolon to close friend statement before %s"); return 0; // TODO: store this friend somewhere } else { read_fulltype(token, temp); delete temp; if (token.type != TT_SEMICOLON) token.report_errorf(herr, "Expected semicolon to close friend statement before %s"); return 0; // TODO: store this friend somewhere } delete temp; } else { token.report_error(herr, "Unexpected `friend' statement: not in a class"); delete temp; return 1; } } else { token.report_errorf(herr, "Expected class or function declaration following template clause before %s"); delete temp; return ERROR_CODE; } return 0; }