// parts_of_speech.sy -- The 10 parts of speech as native Scyla.
//
// Every word in English has a grammatical role. That role determines where
// the word can sit in a sentence (subject, object, predicate, modifier,
// connector, marker, standalone). Scyla encodes each part of speech as a
// native addressable record with its name, sentence-slot permissions,
// typical function, and examples.
//
// This is the grammatical foundation for head-scoped word lookup: when the
// compiled_lang router looks up "bank" in the business head, the word record
// carries a POS address that tells the sentence parser "this is a noun, it
// goes in a subject/object/complement slot." Grammar is not a library call.
// Grammar is a row in a compiled database, addressable at compile time.
//
// Sources:
//   - Huddleston & Pullum, "The Cambridge Grammar of the English Language"
//   - Crystal, "The Cambridge Encyclopedia of the English Language"
//   - Traditional Latinate classification (noun/verb/adjective/...)
//
// Marjorie McCubbins + Aether, April 2026
// Patent pending: 64/034,536 (continuation-in-part)

// ═══════════════════════════════════════════════════════
// STRUCT
// ═══════════════════════════════════════════════════════

struct PartOfSpeech {
    address: Int,
    name: String,
    slots: String,          // pipe-separated: "subject|object|complement"
    function: String,       // grammatical function summary
    examples: String,       // pipe-separated examples
    open_class: Bool,       // true for noun/verb/adj/adv (new words added freely)
}

fn pos(a: Int, n: String, s: String, f: String, e: String, o: Bool) -> PartOfSpeech {
    return PartOfSpeech { address: a, name: n, slots: s, function: f, examples: e, open_class: o }
}

fn unknown_pos() -> PartOfSpeech {
    return pos(0, "unknown", "", "", "", false)
}

// ═══════════════════════════════════════════════════════
// LOOKUP BY ADDRESS (1 - 10)
// ═══════════════════════════════════════════════════════

fn lookup_pos(addr: Int) -> PartOfSpeech {
    if addr == 1  { return pos(1,  "noun",         "subject|object|complement|object-of-preposition", "names a person, place, thing, or idea",              "dog|freedom|Marjorie|insulin",         true) }
    if addr == 2  { return pos(2,  "verb",         "predicate",                                        "expresses an action, occurrence, or state",          "run|be|compile|recommend",             true) }
    if addr == 3  { return pos(3,  "adjective",    "modifier-of-noun|complement",                      "modifies or describes a noun",                       "red|tall|compiled|mandatory",          true) }
    if addr == 4  { return pos(4,  "adverb",       "modifier-of-verb|modifier-of-adjective|modifier-of-adverb|modifier-of-sentence", "modifies a verb, adjective, another adverb, or whole sentence", "quickly|very|deterministically|however", true) }
    if addr == 5  { return pos(5,  "pronoun",      "subject|object|complement",                        "substitutes for a noun",                             "he|they|it|who|this",                   false) }
    if addr == 6  { return pos(6,  "preposition",  "connector-spatial|connector-temporal|connector-relational", "expresses relationship of a noun to another element", "in|on|before|according-to|within",     false) }
    if addr == 7  { return pos(7,  "conjunction",  "connector-clause|connector-phrase|connector-word", "joins words, phrases, or clauses",                   "and|but|because|although|while",       false) }
    if addr == 8  { return pos(8,  "interjection", "standalone",                                       "expresses emotion or reaction, grammatically independent", "oh|wow|hey|ouch|please",             false) }
    if addr == 9  { return pos(9,  "determiner",   "marker-of-noun",                                   "specifies or limits a noun",                         "the|a|this|some|every|my",             false) }
    if addr == 10 { return pos(10, "numeral",      "counter|modifier-of-noun|subject|object",          "indicates number, quantity, or order",               "one|first|100|dozen|several",          false) }
    return unknown_pos()
}

// ═══════════════════════════════════════════════════════
// LOOKUP BY NAME (case-sensitive lowercase)
// ═══════════════════════════════════════════════════════

fn pos_by_name(name: String) -> PartOfSpeech {
    if name == "noun"         { return lookup_pos(1) }
    if name == "verb"         { return lookup_pos(2) }
    if name == "adjective"    { return lookup_pos(3) }
    if name == "adverb"       { return lookup_pos(4) }
    if name == "pronoun"      { return lookup_pos(5) }
    if name == "preposition"  { return lookup_pos(6) }
    if name == "conjunction"  { return lookup_pos(7) }
    if name == "interjection" { return lookup_pos(8) }
    if name == "determiner"   { return lookup_pos(9) }
    if name == "numeral"      { return lookup_pos(10) }
    return unknown_pos()
}

// ═══════════════════════════════════════════════════════
// SLOT-COMPATIBILITY CHECK
// ═══════════════════════════════════════════════════════
// Does this POS fit in the declared sentence slot?
// Compiler can use this to reject a program that tries to put a verb in a subject slot.

fn pos_fits_slot(p: PartOfSpeech, slot: String) -> Bool {
    // Simple substring match on the pipe-separated slots field.
    // Example: pos.slots = "subject|object|complement", slot = "subject" → true
    return str_contains(p.slots, slot)
}

// ═══════════════════════════════════════════════════════
// QUICK-ACCESS HELPERS
// ═══════════════════════════════════════════════════════

fn pos_count() -> Int {
    return 10
}

fn is_valid_pos_address(addr: Int) -> Bool {
    return addr >= 1 and addr <= 10
}

fn is_open_class(p: PartOfSpeech) -> Bool {
    // Open classes (noun, verb, adjective, adverb) accept new vocabulary freely.
    // Closed classes (pronoun, preposition, conjunction, interjection, determiner, numeral)
    // have a bounded and historically stable inventory.
    return p.open_class
}
