func outputCheckErrorReturn(f simprogtext.SimProgFile,
	errVar simprogtext.Var, nilVals []string) {
	retArgs := make([]string, len(nilVals)+1)
	copy(retArgs, nilVals)
	retArgs[len(nilVals)] = errVar.VarName()

	f.AddLineIndent("if %s != nil {", errVar.VarName())
	f.AddLine("return %s", strings.Join(retArgs, ", "))
	f.AddLineUnindent("}")
}
func (m *method) outputCall(f simprogtext.SimProgFile,
	mCallVar, argsVar, errVar, rcvVar simprogtext.Var,
	nilRetVals []string) error {
	paramVars := make([]simprogtext.DynSSAVar, len(m.Params))
	finalParams := make([]string, len(m.Params))

	f.AddLineIndent("if len(%s.Arguments) != %d {", mCallVar.VarName(),
		len(m.Params))
	f.AddLine(
		`fmt.Errof("Method \"%s\": Wrong number of arguments: %%d (want: %d)",`+
			`len(%s))`, m.Name, len(m.Params), argsVar.VarName())

	f.AddLineUnindent("}")

	var err error
	for i, param := range m.Params {
		paramVars[i] = simprogtext.NewDynSSAVar(fmt.Sprintf(
			"param_%d", param.Position), "")
		// parse Argument
		err = (*parameter)(param).OutputParseArgument(f, paramVars[i],
			simprogtext.NewSimpleVar(fmt.Sprintf("%s[%d]", argsVar.VarName(),
				i)), errVar)

		// go sucks
		if err != nil {
			return err
		}

		// check error
		outputCheckErrorReturn(f, errVar, nilRetVals)
	}

	for i, param := range m.Params {
		if param.IsStruct {
			finalParams[i] = paramVars[i].VarName()
		} else {
			finalParams[i] = fmt.Sprintf("%s(%s)", param.TypeName,
				paramVars[i].VarName())
		}
	}

	f.AddLine("return %s.%s(%s)", rcvVar.VarName(), m.Name,
		strings.Join(finalParams, ", "))

	return nil
}
func (p *parameter) OutputParseArgument(f simprogtext.SimProgFile,
	v simprogtext.DynSSAVar, argVar, errVar simprogtext.Var) error {
	if p.IsStruct {
		currentName := v.VarName()
		f.AddLine("%s := &%s{}", v.Next(), p.TypeName)
		f.AddLine("%s = %s.UnmarshalJSON(%s.TokenContent)", errVar.VarName(),
			currentName, argVar)
	} else {
		switch p.TypeName[:3] {
		case "uin", "int", "byt":
			f.AddLine("%s, %s := %s.ToInt64()", v.NextType("int64"),
				errVar.VarName(), argVar.VarName())
		case "flo", "com":
			f.AddLine("%s, %s := %s.ToFloat64()", v.NextType("float64"),
				errVar.VarName(), argVar.VarName())
		case "boo":
			f.AddLine("%s, %s := %s.ToBool()", v.NextType("bool"),
				errVar.VarName(), argVar.VarName())
		case "str":
			f.AddLine("%s, %s := %s.ToString()", v.NextType("string"),
				argVar.VarName())
		default:
			return fmt.Errorf("Unsupport type: %s", p.TypeName)
		}
	}
	return nil
}