forked from GitHub/comp-syntax-gu-mlt
114 lines
3.3 KiB
Python
114 lines
3.3 KiB
Python
import sys
|
|
import json
|
|
import pgf
|
|
|
|
# we assume this abstract syntax
|
|
ABSMODULE = "Query"
|
|
|
|
# data file with laureates
|
|
DATAFILE = '../data/query.json'
|
|
|
|
WIKIDATA_PREFIX = 'http://www.wikidata.org/entity/'
|
|
|
|
# the domain of quantification is the list of laureates with their properties, built from the query result
|
|
with open(DATAFILE) as file:
|
|
data = json.load(file)
|
|
|
|
|
|
def listNames(ds):
|
|
return [d['personLabel'] for d in ds]
|
|
|
|
|
|
def funQID(fun):
|
|
return WIKIDATA_PREFIX + str(fun).split('_')[0]
|
|
|
|
def age(d):
|
|
return int(d['date'][:4]) - int(d['birthDate'][:4])
|
|
|
|
|
|
def answer(tree):
|
|
"top level Query interpreter"
|
|
|
|
match tree.unpack():
|
|
case ("QWhich", [kind, property]):
|
|
return listNames([x for x in data if predicate(kind)(x) and predicate(property)(x)])
|
|
case ("QHowMany", [kind, property]):
|
|
return len([x for x in data if predicate(kind)(x) and predicate(property)(x)])
|
|
case ( "QWhether", [term, property]):
|
|
return quantifier(term)(predicate(property))
|
|
case ( "QWhat", [element]):
|
|
return value(element)
|
|
|
|
print('not yet', str(tree))
|
|
|
|
|
|
def predicate(tree):
|
|
"takes Property or Kind to int -> bool"
|
|
|
|
match tree.unpack():
|
|
case ("PCountry", [fun]):
|
|
return lambda d: d['country'] == funQID(fun)
|
|
case ("PMale", []):
|
|
return lambda d: d['sexLabel'] == 'male'
|
|
case ("PFemale", []):
|
|
return lambda d: d['sexLabel'] == 'female'
|
|
case ("KProperty", [property, kind]):
|
|
return lambda d: predicate(property)(d) and predicate(kind)(d)
|
|
case ("KLaureate", []):
|
|
return lambda d: True
|
|
case ("KMan", []):
|
|
return lambda d: d['sexLabel'] == 'male'
|
|
case ("KWoman", []):
|
|
return lambda d: d['sexLabel'] == 'female'
|
|
|
|
print('not yet', str(tree))
|
|
|
|
|
|
def quantifier(term):
|
|
"takes Term to (int -> bool) -> bool"
|
|
match term.unpack():
|
|
case ("TElement", element):
|
|
return lambda p: p(value(element))
|
|
case ("TAll", [kind]):
|
|
return lambda p: all(lambda x: not predicate(kind)(x) or p(x), data)
|
|
case ("TAny", [kind]):
|
|
return lambda p: any(lambda x: predicate(kind)(x) and p(x), data)
|
|
|
|
print('not yet', str(tree))
|
|
|
|
|
|
def value(element):
|
|
"takes Element to a laureate record"
|
|
|
|
match element.unpack():
|
|
case ('ELaureate', [name]):
|
|
_, string = name.unpack
|
|
return [d for d in data if d['personLabel'] == string][0] ## uncertain !
|
|
case ('EYoungest', [kind]):
|
|
return min([d for d in data if predicate(kind)(d)], key = age)
|
|
case ('EOldest', [kind]):
|
|
return max([d for d in data if predicate(kind)(d)], key = age)
|
|
|
|
print('not yet', str(tree))
|
|
|
|
|
|
def main():
|
|
"main function to be called from stdio, language code as optional argument"
|
|
|
|
# read in the grammar, set up the input language
|
|
grammar = pgf.readPGF(ABSMODULE + ".pgf")
|
|
LANG = ABSMODULE + sys.argv[1]
|
|
lang = grammar.languages[LANG]
|
|
|
|
# read a line of input, parse in lang, return answer
|
|
line = input("")
|
|
parseresult = lang.parse(line)
|
|
prob,tree = parseresult.__next__()
|
|
print('#', tree) ## debugging
|
|
print(answer(tree))
|
|
for r in parseresult:
|
|
print("WARNING: ambiguous")
|
|
|
|
|
|
main()
|