code: function computeOffsets (types, stateDefinitions, contractName, location) {
    var ret = []
    var storagelocation = {
      offset: 0,
      slot: 0
    }
    for (var i in types) {
      var variable = types[i]
      var type = parseType(variable.attributes.type, stateDefinitions, contractName, location)
      if (!type) {
        console.log('unable to retrieve decode info of ' + variable.attributes.type)
        return null
      }
      if (!variable.attributes.constant && storagelocation.offset + type.storageBytes > 32) {
        storagelocation.slot++
        storagelocation.offset = 0
      }
      ret.push({
        name: variable.attributes.name,
        type: type,
        constant: variable.attributes.constant,
        storagelocation: {
          offset: variable.attributes.constant ? 0 : storagelocation.offset,
          slot: variable.attributes.constant ? 0 : storagelocation.slot
        }
      })
      if (!variable.attributes.constant) {
        if (type.storageSlots === 1 && storagelocation.offset + type.storageBytes <= 32) {
          storagelocation.offset += type.storageBytes
        } else {
          storagelocation.slot += type.storageSlots
          storagelocation.offset = 0
        }
      }
    }
    if (storagelocation.offset > 0) {
      storagelocation.slot++
    }
    return {
      typesOffsets: ret,
      endLocation: storagelocation
    }
  }
docs: compute offset (slot offset and byte offset of the @arg list of types)
  
  @param {Array} types - list of types
  @param {Object} stateDefinitions - all state definitions given by the AST (including struct and enum type declaration) for all contracts
  @param {String} contractName - contract the @args typeName belongs to
  @param {String} location - location of the data (storage ref| storage pointer| memory| calldata)
  @return {Array} - return an array of types item: {name, type, location}. location defines the byte offset and slot offset