+
+static void check_constant_against_type(classinfo_t*t, constant_t*c)
+{
+#define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
+ if(TYPE_IS_NUMBER(t)) {
+ xassert(c->type == CONSTANT_FLOAT
+ || c->type == CONSTANT_INT
+ || c->type == CONSTANT_UINT);
+ } else if(TYPE_IS_UINT(t)) {
+ xassert(c->type == CONSTANT_UINT ||
+ (c->type == CONSTANT_INT && c->i>0));
+ } else if(TYPE_IS_INT(t)) {
+ xassert(c->type == CONSTANT_INT);
+ } else if(TYPE_IS_BOOLEAN(t)) {
+ xassert(c->type == CONSTANT_TRUE
+ || c->type == CONSTANT_FALSE);
+ }
+}
+
+static void startfunction(token_t*ns, token_t*mod, token_t*getset, token_t*name,
+ params_t*params, classinfo_t*type)
+{
+ token_list_t*t;
+ new_state();
+ global->variable_count = 0;
+ state->function = name->text;
+
+ if(state->m) {
+ syntaxerror("not able to start another method scope");
+ }
+
+ multiname_t*type2 = sig2mname(type);
+ if(!strcmp(state->clsinfo->name,name->text)) {
+ state->m = abc_class_constructor(state->cls, type2, 0);
+ } else {
+ state->minfo = memberinfo_register(state->clsinfo, name->text, MEMBER_METHOD);
+ state->minfo->return_type = type;
+ state->m = abc_class_method(state->cls, type2, name->text, 0);
+ // getslot on a member slot only returns "undefined", so no need
+ // to actually store these
+ //state->minfo->slot = state->m->method->trait->slot_id;
+ }
+ if(getset->type == KW_GET) {
+ state->m->method->trait->kind = TRAIT_GETTER;
+ }
+ if(getset->type == KW_SET) {
+ state->m->method->trait->kind = TRAIT_SETTER;
+ }
+ if(params->varargs) {
+ state->m->method->flags |= METHOD_NEED_REST;
+ }
+
+ char opt=0;
+ param_list_t*p=0;
+ for(p=params->list;p;p=p->next) {
+ if(params->varargs && !p->next) {
+ break; //varargs: omit last parameter in function signature
+ }
+ multiname_t*m = sig2mname(p->param->type);
+ list_append(state->m->method->parameters, m);
+ if(p->param->value) {
+ check_constant_against_type(p->param->type, p->param->value);
+ opt=1;list_append(state->m->method->optional_parameters, p->param->value);
+ } else if(opt) {
+ syntaxerror("non-optional parameter not allowed after optional parameters");
+ }
+ }
+
+ /* state->vars is initialized by state_new */
+ if(new_variable("this", state->clsinfo)!=0) syntaxerror("Internal error");
+
+ for(p=params->list;p;p=p->next) {
+ new_variable(p->param->name, p->param->type);
+ }
+}
+static void endfunction(code_t*body)
+{
+ code_t*c = 0;
+ if(state->late_binding) {
+ c = abc_getlocal_0(c);
+ c = abc_pushscope(c);
+ }
+ c = code_append(c, state->initcode);
+ c = code_append(c, body);
+
+ /* append return if necessary */
+ if(!c || c->opcode != OPCODE_RETURNVOID &&
+ c->opcode != OPCODE_RETURNVALUE)
+ c = abc_returnvoid(c);
+
+ if(state->m->code) syntaxerror("internal error");
+ state->m->code = c;
+ old_state();
+}
+
+
+