void
SymbolTable::add_struct_field (const TypeSpec &type, ustring name)
{
    StructSpec *s = current_struct();
    ASSERT (s && "add_struct_field couldn't find a current struct");
    s->add_field (type, name);
}
void
OSOReaderToMaster::hint (string_view hintstring)
{
    std::string h (hintstring);   // FIXME -- use string_view ops here
    if (extract_prefix (h, "%filename{\"")) {
        m_sourcefile = readuntil (h, "\"");
        return;
    }
    if (extract_prefix (h, "%line{")) {
        m_sourceline = atoi (h.c_str());
        return;
    }
    if (extract_prefix (h, "%structfields{")) {
        ASSERT (m_master->m_symbols.size() && "structfields hint but no sym");
        Symbol &sym (m_master->m_symbols.back());
        StructSpec *structspec = sym.typespec().structspec();
        if (structspec->numfields() == 0) {
            while (1) {
                std::string afield = readuntil (h, ",}", true);
                if (! afield.length())
                    break;
//                std::cerr << " struct field " << afield << "\n";
                structspec->add_field (TypeSpec(), ustring(afield));
            }
        }
        return;
    }
    if (extract_prefix (h, "%mystructfield{")) {
        ASSERT (m_master->m_symbols.size() && "mystructfield hint but no sym");
        Symbol &sym (m_master->m_symbols.back());
        sym.fieldid (atoi(h.c_str()+15));
        return;
    }
    if (extract_prefix (h, "%read{")) {
        ASSERT (m_master->m_symbols.size() && "read hint but no sym");
        Symbol &sym (m_master->m_symbols.back());
        int first, last;
        sscanf (h.c_str(), "%d,%d", &first, &last);
        sym.set_read (first, last);
        return;
    }
    if (extract_prefix (h, "%write{")) {
        ASSERT (m_master->m_symbols.size() && "write hint but no sym");
        Symbol &sym (m_master->m_symbols.back());
        int first, last;
        sscanf (h.c_str(), "%d,%d", &first, &last);
        sym.set_write (first, last);
        return;
    }
    if (extract_prefix(h, "%argrw{")) {
        const char* str = h.c_str();
        ASSERT(*str == '\"');
        str++; // skip open quote
        size_t i = 0;
        for (; *str != '\"'; i++, str++) {
            ASSERT(*str == 'r' || *str == 'w' || *str == 'W' || *str == '-');
            m_master->m_ops.back().argwrite(i, *str == 'w' || *str =='W');
            m_master->m_ops.back().argread(i, *str == 'r' || *str =='W');
        }
        ASSERT(m_nargs == i);
        // Fix old bug where oslc forgot to mark getmatrix last arg as write
        static ustring getmatrix("getmatrix");
        if (m_master->m_ops.back().opname() == getmatrix)
            m_master->m_ops.back().argwrite(m_nargs-1, true);
    }
    if (extract_prefix(h, "%argderivs{")) {
        while (1) {
            std::string afield = readuntil (h, ",}", true);
            if (! afield.length())
                break;
            int arg = atoi (afield.c_str());
            if (arg >= 0)
                m_master->m_ops.back().argtakesderivs (arg, true);
        }
    }
    if (extract_prefix (h, "%meta{") && m_master->m_symbols.size()) {
        Symbol &sym (m_master->m_symbols.back());
        int lockval = -1;
        int ok = sscanf (h.c_str(), " int , lockgeom , %d", &lockval);
        if (ok)
            sym.lockgeom (lockval);
    }
}