ref: 4fba3e66dce0d167d2031a0d1f1f6f4571cbd981
dir: /module.c/
#include <u.h>
#include <libc.h>
#include <bio.h>
#include "dat.h"
#include "fns.h"
void handleopdirective(Term *, Module *);
void
initmodules(void)
{
addemptymodule(L"user");
if(!addtousermod("/sys/lib/prolog/system.pl")){
print("Can't load /sys/lib/prolog/system.pl\n");
exits(nil);
}
if(!addtousermod("/sys/lib/prolog/loader.pl")){
print("Can't load /sys/lib/prolog/loader.pl\n");
exits(nil);
}
}
int
addtousermod(char *file)
{
Biobuf *bio = Bopen(file, OREAD);
if(bio == nil)
return 0;
Module *usermodule = getmodule(L"user");
Predicate *currentpred = nil;
Term *t;
VarName *varnames;
while(t = parse(bio, usermodule, &varnames)){
Clause *cl = gmalloc(sizeof(Clause));
int arity;
cl->clausenr = 0;
cl->next = nil;
if(t->tag == CompoundTerm && runestrcmp(t->text, L":-") == 0 && t->arity == 1){
Term *body = t->children;
if(runestrcmp(body->text, L"op") == 0 && body->arity == 3)
handleopdirective(body->children, usermodule);
continue;
}else if(t->tag == CompoundTerm && runestrcmp(t->text, L":-") == 0 && t->arity == 2){
cl->head = t->children;
cl->body = t->children->next;
}else{
cl->head = t;
cl->body = mkatom(L"true");
}
if(cl->head->tag == AtomTerm)
arity = 0;
else
arity = cl->head->arity;
/* Figure out if this clause goes into the latest predicate, or if it is the start of a new one */
if(currentpred == nil || runestrcmp(cl->head->text, currentpred->name) != 0 || arity != currentpred->arity){
usermodule->predicates = appendpredicate(currentpred, usermodule->predicates);
currentpred = gmalloc(sizeof(Predicate));
currentpred->name = cl->head->text;
currentpred->arity = arity;
currentpred->clauses = cl;
currentpred->public = 1; /* everything is public for now */
currentpred->builtin = 0;
currentpred->dynamic = 1; /* everything is dynamic for now */
currentpred->next = nil;
}else
currentpred->clauses = appendclause(currentpred->clauses, cl);
}
usermodule->predicates = appendpredicate(currentpred, usermodule->predicates);
Bterm(bio);
return 1;
}
Module *
getmodule(Rune *name)
{
Module *m;
for(m = modules; m != nil; m = m->next){
if(runestrcmp(m->name, name) == 0)
return m;
}
return nil;
}
Module *
addemptymodule(Rune *name)
{
Module *m = gmalloc(sizeof(Module));
m->name = name;
m->next = modules;
m->predicates = nil;
memset(m->operators, 0, sizeof(m->operators));
Module *systemmodule = getmodule(L"system");
if(systemmodule != nil){
int level;
Operator *op;
for(level = 0; level < PrecedenceLevels; level++){
for(op = systemmodule->operators[level]; op != nil; op = op->next)
addoperator(op->level, op->type, op->spelling, m);
}
}
modules = m;
return m;
}
void
removemodule(Rune *name)
{
Module *m;
Module *prev = nil;
for(m = modules; m != nil; m = m->next){
if(runestrcmp(m->name, name) != 0)
prev = m;
else{
if(prev == nil)
modules = m->next;
else
prev->next = m->next;
return;
}
}
}
Clause *
appendclause(Clause *clauses, Clause *new)
{
Clause *tmp;
if(clauses == nil)
return new;
for(tmp = clauses; tmp->next != nil; tmp = tmp->next);
tmp->next = new;
return clauses;
}
Predicate *
appendpredicate(Predicate *preds, Predicate *new)
{
Predicate *tmp;
if(preds == nil)
return new;
for(tmp = preds; tmp->next != nil; tmp = tmp->next);
tmp->next = new;
return preds;
}
Operator *
getoperator(Rune *spelling, Module *mod)
{
Operator *op = nil;
int level;
if(spelling == nil || mod == nil)
return nil;
for(level = 0; level < PrecedenceLevels && op == nil; level++){
Operator *tmp;
for(tmp = mod->operators[level]; tmp != nil; tmp = tmp->next){
if(runestrcmp(tmp->spelling, spelling) == 0){
if(op == nil){
op = gmalloc(sizeof(Operator));
memcpy(op, tmp, sizeof(Operator));
}else
op->type |= tmp->type;
}
}
}
return op;
}
void
addoperator(int level, int type, Rune *spelling, Module *mod)
{
if(mod == nil)
return;
/* the operator table is never garbage collected, so just use normal malloc */
Operator *op = malloc(sizeof(Operator));
op->type = type;
op->level = level;
op->spelling = spelling;
op->next = mod->operators[level-1];
mod->operators[level-1] = op;
}
void
handleopdirective(Term *args, Module *mod)
{
Term *levelt = args;
Term *typet = levelt->next;
Term *opt = typet->next;
if(levelt->tag == IntegerTerm
&& levelt->ival >= 0
&& levelt->ival <= PrecedenceLevels
&& typet->tag == AtomTerm
&& opt->tag == AtomTerm){
int level = levelt->ival;
Rune *spelling = opt->text;
int type = 0;
if(runestrcmp(typet->text, L"xf") == 0)
type = Xf;
else if(runestrcmp(typet->text, L"yf") == 0)
type = Yf;
else if(runestrcmp(typet->text, L"xfx") == 0)
type = Xfx;
else if(runestrcmp(typet->text, L"xfy") == 0)
type = Xfy;
else if(runestrcmp(typet->text, L"yfx") == 0)
type = Yfx;
else if(runestrcmp(typet->text, L"fy") == 0)
type = Fy;
else if(runestrcmp(typet->text, L"fx") == 0)
type = Fx;
if(type != 0){
addoperator(level, type, spelling, mod);
return;
}
}
print("Malformed op directive with level=%S, type=%S, op=%S\n",
prettyprint(levelt, 0, 0, 0, mod),
prettyprint(typet, 0, 0, 0, mod),
prettyprint(opt, 0, 0, 0, mod));
}