This commit is contained in:
Vitor Santos Costa 2018-07-18 17:36:01 +01:00
parent e5748f3c9f
commit abc11dcfaa
12 changed files with 728 additions and 273 deletions

View File

@ -152,7 +152,6 @@ Yap_AtomInUse(const char *atom) { /* lookup atom in atom table */
uint64_t hash;
const unsigned char *p;
Atom a, na = NIL;
AtomEntry *ae;
size_t sz = AtomHashTableSize;
/* compute hash */
@ -165,7 +164,6 @@ Yap_AtomInUse(const char *atom) { /* lookup atom in atom table */
a = HashChain[hash].Entry;
/* search atom in chain */
na = SearchAtom(p, a);
ae = RepAtom(na);
if (na != NIL ) {
READ_UNLOCK(HashChain[hash].AERWLock);
return (na);
@ -211,7 +209,11 @@ LookupAtom(const unsigned char *atom) { /* lookup atom in atom table */
}
#endif
/* add new atom to start of chain */
sz = strlen((const char *)atom);
if (atom[0] == '\0') {
sz = YAP_ALIGN;
} else {
sz = strlen((const char *)atom);
}
size_t asz = (sizeof *ae) + ( sz+1);
ae = malloc(asz);
if (ae == NULL) {
@ -249,7 +251,8 @@ Atom Yap_LookupAtomWithLength(const char *atom,
return NIL;
memmove(ptr, atom, len0);
ptr[len0] = '\0';
at = LookupAtom(ptr);
if (atom[0] '\0') {
at = LookupAtom(ptr);
Yap_FreeCodeSpace(ptr);
return at;
}

View File

@ -1,4 +1,4 @@
/*************************************************************************
/*************************************************************************
* *
* YAP Prolog *
* *

502
C/text.c
View File

@ -91,11 +91,11 @@ void *pop_output_text_stack__(int i, const void *export) {
while (p) {
struct mblock *np = p->next;
if (p + 1 == export) {
size_t sz = p->sz - sizeof(struct mblock);
memmove(p, p + 1, sz);
export = p;
size_t sz = p->sz - sizeof(struct mblock);
memmove(p, p + 1, sz);
export = p;
} else {
free(p);
free(p);
}
p = np;
}
@ -229,9 +229,9 @@ static Term Globalize(Term v USES_REGS) {
}
static void *codes2buf(Term t0, void *b0, bool get_codes,
bool fixed USES_REGS) {
bool fixed USES_REGS) {
unsigned char *st0, *st, ar[16];
Term t = t0;
Term t = Deref(t0);
size_t length = 0;
if (t == TermNil) {
@ -247,7 +247,7 @@ static void *codes2buf(Term t0, void *b0, bool get_codes,
if (get_codes != codes && fixed) {
if (codes) {
Yap_ThrowError(TYPE_ERROR_INTEGER, HeadOfTerm(t),
"scanning list of codes");
"scanning list of codes");
} else {
Yap_ThrowError(TYPE_ERROR_ATOM, HeadOfTerm(t), "scanning list of atoms");
}
@ -256,55 +256,55 @@ static void *codes2buf(Term t0, void *b0, bool get_codes,
while (IsPairTerm(t)) {
Term hd = HeadOfTerm(t);
if (IsVarTerm(hd)) {
Yap_ThrowError(INSTANTIATION_ERROR, hd, "scanning list of codes");
return NULL;
Yap_ThrowError(INSTANTIATION_ERROR, hd, "scanning list of codes");
return NULL;
}
if (!IsIntegerTerm(hd)) {
Yap_ThrowError(TYPE_ERROR_CHARACTER_CODE, hd, "scanning list of codes");
return NULL;
Yap_ThrowError(TYPE_ERROR_CHARACTER_CODE, hd, "scanning list of codes");
return NULL;
}
Int code = IntegerOfTerm(hd);
if (code < 0) {
Yap_ThrowError(REPRESENTATION_ERROR_CHARACTER_CODE, hd,
"scanning list of character codes, found %d", code);
return NULL;
Yap_ThrowError(REPRESENTATION_ERROR_CHARACTER_CODE, hd,
"scanning list of character codes, found %d", code);
return NULL;
}
length += put_utf8(ar, code);
t = TailOfTerm(t);
if (IsVarTerm(t)) {
Yap_ThrowError(INSTANTIATION_ERROR, t, "scanning list of codes");
return NULL;
Yap_ThrowError(INSTANTIATION_ERROR, t, "scanning list of codes");
return NULL;
}
if (!IsPairTerm(t) && t != TermNil) {
Yap_ThrowError(TYPE_ERROR_LIST, t, "scanning list of codes");
return NULL;
Yap_ThrowError(TYPE_ERROR_LIST, t, "scanning list of codes");
return NULL;
}
}
} else {
while (IsPairTerm(t)) {
Term hd = HeadOfTerm(t);
if (IsVarTerm(hd)) {
Yap_ThrowError(INSTANTIATION_ERROR, hd, "scanning list of codes");
return NULL;
Yap_ThrowError(INSTANTIATION_ERROR, hd, "scanning list of codes");
return NULL;
}
if (!IsAtomTerm(hd)) {
Yap_ThrowError(TYPE_ERROR_CHARACTER, hd, "scanning list of texts");
return NULL;
Yap_ThrowError(TYPE_ERROR_CHARACTER, hd, "scanning list of texts");
return NULL;
}
const char *code = RepAtom(AtomOfTerm(hd))->StrOfAE;
if (code < 0) {
Yap_ThrowError(TYPE_ERROR_CHARACTER, hd, "scanning list of atoms");
return NULL;
Yap_ThrowError(TYPE_ERROR_CHARACTER, hd, "scanning list of atoms");
return NULL;
}
length += strlen(code);
t = TailOfTerm(t);
if (IsVarTerm(t)) {
Yap_ThrowError(INSTANTIATION_ERROR, t, "scanning list of codes");
return NULL;
Yap_ThrowError(INSTANTIATION_ERROR, t, "scanning list of codes");
return NULL;
}
if (!IsPairTerm(t) && t != TermNil) {
Yap_ThrowError(TYPE_ERROR_LIST, t, "scanning list of codes");
return NULL;
Yap_ThrowError(TYPE_ERROR_LIST, t, "scanning list of codes");
return NULL;
}
}
}
@ -374,33 +374,33 @@ static unsigned char *wchar2utf8(seq_tv_t *inp) {
static void *slice(size_t min, size_t max, const unsigned char *buf USES_REGS);
static unsigned char *Yap_ListOfCodesToBuffer(unsigned char *buf, Term t,
seq_tv_t *inp USES_REGS) {
seq_tv_t *inp USES_REGS) {
bool codes = true, fixed = true;
unsigned char *nbuf = codes2buf(t, buf, codes, fixed PASS_REGS);
return nbuf;
}
static unsigned char *Yap_ListOfAtomsToBuffer(unsigned char *buf, Term t,
seq_tv_t *inp USES_REGS) {
seq_tv_t *inp USES_REGS) {
bool codes = false;
unsigned char *nbuf = codes2buf(t, buf, codes, true PASS_REGS);
return nbuf;
}
static unsigned char *Yap_ListToBuffer(unsigned char *buf, Term t,
seq_tv_t *inp USES_REGS) {
seq_tv_t *inp USES_REGS) {
return codes2buf(t, buf, NULL, false PASS_REGS);
}
#if USE_GEN_TYPE_ERROR
static yap_error_number gen_type_error(int flags) {
if ((flags & (YAP_STRING_STRING | YAP_STRING_ATOM | YAP_STRING_INT |
YAP_STRING_FLOAT | YAP_STRING_ATOMS_CODES | YAP_STRING_BIG)) ==
YAP_STRING_FLOAT | YAP_STRING_ATOMS_CODES | YAP_STRING_BIG)) ==
(YAP_STRING_STRING | YAP_STRING_ATOM | YAP_STRING_INT | YAP_STRING_FLOAT |
YAP_STRING_ATOMS_CODES | YAP_STRING_BIG))
return TYPE_ERROR_TEXT;
if ((flags & (YAP_STRING_STRING | YAP_STRING_ATOM | YAP_STRING_INT |
YAP_STRING_FLOAT | YAP_STRING_BIG)) ==
YAP_STRING_FLOAT | YAP_STRING_BIG)) ==
(YAP_STRING_STRING | YAP_STRING_ATOM | YAP_STRING_INT | YAP_STRING_FLOAT |
YAP_STRING_BIG))
return TYPE_ERROR_ATOMIC;
@ -417,149 +417,183 @@ static yap_error_number gen_type_error(int flags) {
}
#endif
// static int cnt;
static yap_error_number type_error(seq_tv_t *inp) {
if ((inp->type & YAP_STRING_ATOMS_CODES) == YAP_STRING_ATOMS_CODES)
{
return TYPE_ERROR_IN_CHARACTER;
}
if ((inp->type & YAP_STRING_ATOMS) == YAP_STRING_ATOMS) {
return TYPE_ERROR_CHARACTER;
}
if ((inp->type & YAP_STRING_CODES) == YAP_STRING_CODES) {
return TYPE_ERROR_CHARACTER_CODE;
}
if ((inp->type & YAP_STRING_STRING) == YAP_STRING_STRING) {
return TYPE_ERROR_IN_CHARACTER;
}
if ((inp->type & YAP_STRING_CODES) == YAP_STRING_CODES) {
return TYPE_ERROR_IN_CHARACTER;
}
if ((inp->type & (YAP_STRING_ATOM|YAP_STRING_STRING)) == (YAP_STRING_ATOM|YAP_STRING_STRING)) {
return TYPE_ERROR_ATOMIC;
}
if ((inp->type & YAP_STRING_ATOM) == YAP_STRING_ATOM) {
return TYPE_ERROR_IN_CHARACTER;
}
return SYSTEM_ERROR_INTERNAL;
}
/// @brief translate anything to bufffer UTF-8
///
/// @arg input descriptor
unsigned char *Yap_readText(seq_tv_t *inp USES_REGS) {
#define POPRET(x) return pop_output_text_stack(lvl, x)
int lvl = push_text_stack();
char *out = NULL;
yap_error_number err0 = LOCAL_Error_TYPE;
/* we know what the term is */
if (!(inp->type & (YAP_STRING_CHARS | YAP_STRING_WCHARS))) {
if (!(inp->type & YAP_STRING_TERM)) {
if (IsVarTerm(inp->val.t)) {
LOCAL_Error_TYPE = INSTANTIATION_ERROR;
} else if (!IsAtomTerm(inp->val.t) && inp->type == YAP_STRING_ATOM) {
LOCAL_Error_TYPE = TYPE_ERROR_ATOM;
} else if (!IsStringTerm(inp->val.t) && inp->type == YAP_STRING_STRING) {
LOCAL_Error_TYPE = TYPE_ERROR_STRING;
} else if (!IsPairOrNilTerm(inp->val.t) && !IsStringTerm(inp->val.t) &&
inp->type == (YAP_STRING_ATOMS_CODES | YAP_STRING_STRING)) {
LOCAL_ActiveError->errorRawTerm = inp->val.t;
} else if (!IsPairOrNilTerm(inp->val.t) && !IsStringTerm(inp->val.t) &&
!IsAtomTerm(inp->val.t) && !(inp->type & YAP_STRING_DATUM)) {
LOCAL_Error_TYPE = TYPE_ERROR_TEXT;
if ((inp->type & (YAP_STRING_CHARS | YAP_STRING_WCHARS))) {
//> buffer processing
//> must convert:
if (inp->type & YAP_STRING_CHARS) {
//> - ASCII to UTF-8
if (inp->enc == ENC_ISO_ASCII) {
pop_text_stack(lvl);
return inp->val.uc;
}
//> - ISO-LATIN-1 to UTF-8
if (inp->enc == ENC_ISO_LATIN1) {
POPRET( (char*)latin2utf8(inp));
}
//> - assume UTF-8
if (inp->enc == ENC_ISO_UTF8) {
pop_text_stack(lvl);
return inp->val.uc;
}
}
if (err0 != LOCAL_Error_TYPE) {
Yap_ThrowError(LOCAL_Error_TYPE, inp->val.t, "while reading text in");
if (inp->type & YAP_STRING_WCHARS) {
// printf("%S\n",inp->val.w);
//> wide includes everything else
POPRET( (char *)wchar2utf8(inp) );
}
}
if (IsAtomTerm(inp->val.t) && inp->type & YAP_STRING_ATOM) {
// this is a term, extract to a buffer, and representation is wide
// Yap_DebugPlWriteln(inp->val.t);
Atom at = AtomOfTerm(inp->val.t);
if (RepAtom(at)->UStrOfAE[0] == 0) {
out = Malloc(4);
memset(out, 0, 4);
POPRET( out );
}
if (inp->type & YAP_STRING_WITH_BUFFER) {
} else {
if (inp->type & YAP_STRING_TERM) {
//> term: anything goes
pop_text_stack(lvl);
return at->UStrOfAE;
return (unsigned char *)Yap_TermToBuffer(inp->val.t, 0);
}
{
size_t sz = strlen(at->StrOfAE);
out = Malloc(sz + 1);
strcpy(out, at->StrOfAE);
POPRET( out );
if (IsVarTerm(inp->val.t)) {
Yap_ThrowError(INSTANTIATION_ERROR, inp->val.t, NULL);
}
}
if (IsStringTerm(inp->val.t) && inp->type & YAP_STRING_STRING) {
// this is a term, extract to a buffer, and representation is wide
// Yap_DebugPlWriteln(inp->val.t);
const char *s = StringOfTerm(inp->val.t);
if (s[0] == 0) {
out = Malloc(4);
memset(out, 0, 4);
POPRET( out );
if (IsPairOrNilTerm(inp->val.t)) {
if (((inp->type & (YAP_STRING_CODES | YAP_STRING_ATOMS)) ==
(YAP_STRING_CODES | YAP_STRING_ATOMS))) {
// Yap_DebugPlWriteln(inp->val.t);
out = (char *)Yap_ListToBuffer(NULL, inp->val.t, inp PASS_REGS);
POPRET( out );
// this is a term, extract to a sfer, and representation is wide
}
if (inp->type & YAP_STRING_CODES) {
// Yap_DebugPlWriteln(inp->val.t);
out = (char *)Yap_ListOfCodesToBuffer(NULL, inp->val.t, inp PASS_REGS);
// this is a term, extract to a sfer, and representation is wide
POPRET( out );
}
if (inp->type & YAP_STRING_ATOMS) {
// Yap_DebugPlWriteln(inp->val.t);
out = (char *)Yap_ListOfAtomsToBuffer(NULL, inp->val.t, inp PASS_REGS);
// this is a term, extract to a buffer, and representation is wide
POPRET( out );
}
}
if (inp->type & YAP_STRING_WITH_BUFFER) {
pop_text_stack(lvl);
return (unsigned char *)UStringOfTerm(inp->val.t);
}
{
inp->type |= YAP_STRING_IN_TMP;
size_t sz = strlen(s);
out = Malloc(sz + 1);
strcpy(out, s);
POPRET( out );
}
} else if (IsPairOrNilTerm(inp->val.t)) {
if (((inp->type & (YAP_STRING_CODES | YAP_STRING_ATOMS)) ==
(YAP_STRING_CODES | YAP_STRING_ATOMS))) {
// Yap_DebugPlWriteln(inp->val.t);
out = (char *)Yap_ListToBuffer(NULL, inp->val.t, inp PASS_REGS);
POPRET( out );
// this is a term, extract to a sfer, and representation is wide
}
if (inp->type & YAP_STRING_CODES) {
// Yap_DebugPlWriteln(inp->val.t);
out = (char *)Yap_ListOfCodesToBuffer(NULL, inp->val.t, inp PASS_REGS);
// this is a term, extract to a sfer, and representation is wide
POPRET( out );
}
if (inp->type & YAP_STRING_ATOMS) {
// Yap_DebugPlWriteln(inp->val.t);
out = (char *)Yap_ListOfAtomsToBuffer(NULL, inp->val.t, inp PASS_REGS);
if (IsStringTerm(inp->val.t)) {
if(!(inp->type & (YAP_STRING_STRING))) {
Yap_ThrowError(type_error(inp), inp->val.t, NULL);
}
// this is a term, extract to a buffer, and representation is wide
// Yap_DebugPlWriteln(inp->val.t);
const char *s = StringOfTerm(inp->val.t);
if (s[0] == 0) {
out = Malloc(4);
memset(out, 0, 4);
POPRET( out );
}
if (inp->type & YAP_STRING_WITH_BUFFER) {
pop_text_stack(lvl);
return (unsigned char *)UStringOfTerm(inp->val.t);
}
{
inp->type |= YAP_STRING_IN_TMP;
size_t sz = strlen(s);
out = Malloc(sz + 1);
strcpy(out, s);
POPRET( out );
}
}
if (IsAtomTerm(inp->val.t)) {
if(!(inp->type & (YAP_STRING_ATOM))) {
Yap_ThrowError(type_error(inp), inp->val.t, NULL);
}
// this is a term, extract to a buffer, and representation is wide
// Yap_DebugPlWriteln(inp->val.t);
Atom at = AtomOfTerm(inp->val.t);
if (RepAtom(at)->UStrOfAE[0] == '\0') {
out = Malloc(4);
memset(out, 0, 4);
POPRET( out );
}
if (inp->type & YAP_STRING_WITH_BUFFER) {
pop_text_stack(lvl);
return at->UStrOfAE;
} else
{
size_t sz = strlen(at->StrOfAE);
out = Malloc(sz + 1);
strcpy(out, at->StrOfAE);
POPRET( out );
}
}
if (inp->type & YAP_STRING_INT && IsIntegerTerm(inp->val.t)) {
if(!(inp->type & (YAP_STRING_INT))) {
Yap_ThrowError(type_error(inp), inp->val.t, NULL);
} // ASCII, so both LATIN1 and UTF-8
// Yap_DebugPlWriteln(inp->val.t);
out = Malloc(2 * MaxTmp(PASS_REGS1));
if (snprintf(out, MaxTmp(PASS_REGS1) - 1, Int_FORMAT,
IntegerOfTerm(inp->val.t)) < 0) {
AUX_ERROR(inp->val.t, 2 * MaxTmp(PASS_REGS1), out, char);
}
POPRET( out );
}
}
if (inp->type & YAP_STRING_INT && IsIntegerTerm(inp->val.t)) {
// ASCII, so both LATIN1 and UTF-8
// Yap_DebugPlWriteln(inp->val.t);
out = Malloc(2 * MaxTmp(PASS_REGS1));
if (snprintf(out, MaxTmp(PASS_REGS1) - 1, Int_FORMAT,
IntegerOfTerm(inp->val.t)) < 0) {
AUX_ERROR(inp->val.t, 2 * MaxTmp(PASS_REGS1), out, char);
if (inp->type & YAP_STRING_FLOAT && IsFloatTerm(inp->val.t)) {
if(!(inp->type & (YAP_STRING_FLOAT))) {
Yap_ThrowError(type_error(inp), inp->val.t, NULL);
} // ASCII, so both LATIN1 and UTF-8
out = Malloc(2 * MaxTmp(PASS_REGS1));
if (!Yap_FormatFloat(FloatOfTerm(inp->val.t), &out, 1024)) {
pop_text_stack(lvl);
return NULL;
}
POPRET(out);
}
POPRET( out );
}
if (inp->type & YAP_STRING_FLOAT && IsFloatTerm(inp->val.t)) {
out = Malloc(2 * MaxTmp(PASS_REGS1));
if (!Yap_FormatFloat(FloatOfTerm(inp->val.t), &out, 1024)) {
pop_text_stack(lvl);
return NULL;
}
POPRET(out);
}
#if USE_GMP
if (inp->type & YAP_STRING_BIG && IsBigIntTerm(inp->val.t)) {
// Yap_DebugPlWriteln(inp->val.t);
out = Malloc(MaxTmp());
if (!Yap_mpz_to_string(Yap_BigIntOfTerm(inp->val.t), out, MaxTmp() - 1,
10)) {
AUX_ERROR(inp->val.t, MaxTmp(PASS_REGS1), out, char);
if ( IsBigIntTerm(inp->val.t)) {
if(!(inp->type & (YAP_STRING_BIG))) {
Yap_ThrowError(type_error(inp), inp->val.t, NULL);
} // ASCII, so both LATIN1 and UTF-8
// Yap_DebugPlWriteln(inp->val.t);
out = Malloc(MaxTmp());
if (!Yap_mpz_to_string(Yap_BigIntOfTerm(inp->val.t), out, MaxTmp() - 1,
10)) {
AUX_ERROR(inp->val.t, MaxTmp(PASS_REGS1), out, char);
}
POPRET(out);
}
POPRET(out);
}
#endif
if (inp->type & YAP_STRING_TERM) {
pop_text_stack(lvl);
return Yap_TermToBuffer(inp->val.t, 0);
}
if (inp->type & YAP_STRING_CHARS) {
if (inp->enc == ENC_ISO_ASCII) {
pop_text_stack(lvl);
return inp->val.uc;
}
if (inp->enc == ENC_ISO_LATIN1) {
POPRET( (char*)latin2utf8(inp));
}
if (inp->enc == ENC_ISO_UTF8) {
pop_text_stack(lvl);
return inp->val.c;
}
}
if (inp->type & YAP_STRING_WCHARS) {
// printf("%S\n",inp->val.w);
POPRET( (char *)wchar2utf8(inp) );
}
pop_text_stack(lvl);
Yap_ThrowError(type_error(inp), inp->val.t, NULL);
return NULL;
}
@ -727,11 +761,11 @@ void *write_buffer(unsigned char *s0, seq_tv_t *out USES_REGS) {
utf8proc_int32_t chr;
int off = get_utf8(cp, -1, &chr);
if (off <= 0 || chr > 255) {
pop_text_stack(l);
return NULL;
pop_text_stack(l);
return NULL;
}
if (off == max)
break;
break;
cp += off;
*buf++ = chr;
}
@ -739,10 +773,10 @@ void *write_buffer(unsigned char *s0, seq_tv_t *out USES_REGS) {
*buf++ = '\0';
else
while (max < min) {
utf8proc_int32_t chr;
max++;
cp += get_utf8(cp, -1, &chr);
*buf++ = chr;
utf8proc_int32_t chr;
max++;
cp += get_utf8(cp, -1, &chr);
*buf++ = chr;
}
} else if (out->enc == ENC_WCHAR) {
unsigned char *s = s0, *lim = s + (max = strnlen((char *)s0, max));
@ -763,10 +797,10 @@ void *write_buffer(unsigned char *s0, seq_tv_t *out USES_REGS) {
*buf++ = '\0';
else
while (max < min) {
utf8proc_int32_t chr;
max++;
cp += get_utf8(cp, -1, &chr);
*buf++ = chr;
utf8proc_int32_t chr;
max++;
cp += get_utf8(cp, -1, &chr);
*buf++ = chr;
}
*buf = '\0';
} else {
@ -783,7 +817,7 @@ static size_t write_length(const unsigned char *s0, seq_tv_t *out USES_REGS) {
}
static Term write_number(unsigned char *s, seq_tv_t *out,
bool error_on USES_REGS) {
bool error_on USES_REGS) {
Term t;
LOCAL_delay = !error_on;
t = Yap_StringToNumberTerm((char *)s, &out->enc, error_on);
@ -812,7 +846,7 @@ bool write_Text(unsigned char *inp, seq_tv_t *out USES_REGS) {
if (out->type & (YAP_STRING_INT | YAP_STRING_FLOAT | YAP_STRING_BIG)) {
if ((out->val.t = write_number(
inp, out, !(out->type & YAP_STRING_ATOM) PASS_REGS)) != 0L) {
inp, out, !(out->type & YAP_STRING_ATOM) PASS_REGS)) != 0L) {
// Yap_DebugPlWriteln(out->val.t);
return true;
@ -825,7 +859,7 @@ bool write_Text(unsigned char *inp, seq_tv_t *out USES_REGS) {
if ((out->val.a = write_atom(inp, out PASS_REGS)) != NIL) {
Atom at = out->val.a;
if (at && (out->type & YAP_STRING_OUTPUT_TERM))
out->val.t = MkAtomTerm(at);
out->val.t = MkAtomTerm(at);
// Yap_DebugPlWriteln(out->val.t);
return at != NIL;
}
@ -925,12 +959,12 @@ bool Yap_CVT_Text(seq_tv_t *inp, seq_tv_t *out USES_REGS) {
size_t leng = strlen_utf8(buf);
if (out->type & (YAP_STRING_NCHARS | YAP_STRING_TRUNC)) {
if (out->max < leng) {
const unsigned char *ptr = skip_utf8(buf, out->max);
size_t diff = (ptr - buf);
char *nbuf = Malloc(diff + 1);
memmove(nbuf, buf, diff);
nbuf[diff] = '\0';
leng = diff;
const unsigned char *ptr = skip_utf8(buf, out->max);
size_t diff = (ptr - buf);
char *nbuf = Malloc(diff + 1);
memmove(nbuf, buf, diff);
nbuf[diff] = '\0';
leng = diff;
}
// else if (out->type & YAP_STRING_NCHARS &&
// const unsigned char *ptr = skip_utf8(buf)
@ -938,32 +972,32 @@ bool Yap_CVT_Text(seq_tv_t *inp, seq_tv_t *out USES_REGS) {
if (out->type & (YAP_STRING_UPCASE | YAP_STRING_DOWNCASE)) {
if (out->type & YAP_STRING_UPCASE) {
if (!upcase(buf, out)) {
pop_text_stack(l);
return false;
}
if (!upcase(buf, out)) {
pop_text_stack(l);
return false;
}
}
if (out->type & YAP_STRING_DOWNCASE) {
if (!downcase(buf, out)) {
pop_text_stack(l);
return false;
}
if (!downcase(buf, out)) {
pop_text_stack(l);
return false;
}
}
}
}
rc = write_Text(buf, out PASS_REGS);
/* fprintf(stderr, " -> ");
if (!rc) fprintf(stderr, "NULL");
else if (out->type &
(YAP_STRING_TERM|YAP_STRING_ATOMS_CODES
|YAP_STRING_STRING)) //Yap_DebugPlWrite(out->val.t);
else if (out->type &
YAP_STRING_ATOM) //Yap_DebugPlWriteln(MkAtomTerm(out->val.a));
else if (out->type & YAP_STRING_WCHARS) fprintf(stderr, "%S",
out->val.w);
else
fprintf(stderr, "%s", out->val.c);
fprintf(stderr, "\n]\n"); */
if (!rc) fprintf(stderr, "NULL");
else if (out->type &
(YAP_STRING_TERM|YAP_STRING_ATOMS_CODES
|YAP_STRING_STRING)) //Yap_DebugPlWrite(out->val.t);
else if (out->type &
YAP_STRING_ATOM) //Yap_DebugPlWriteln(MkAtomTerm(out->val.a));
else if (out->type & YAP_STRING_WCHARS) fprintf(stderr, "%S",
out->val.w);
else
fprintf(stderr, "%s", out->val.c);
fprintf(stderr, "\n]\n"); */
pop_text_stack(l);
return rc;
}
@ -1049,7 +1083,7 @@ bool Yap_Concat_Text(int tot, seq_tv_t inp[], seq_tv_t *out USES_REGS) {
//
bool Yap_Splice_Text(int n, size_t cuts[], seq_tv_t *inp,
seq_tv_t outv[] USES_REGS) {
seq_tv_t outv[] USES_REGS) {
int lvl = push_text_stack();
const unsigned char *buf;
size_t b_l, u_l;
@ -1072,46 +1106,46 @@ bool Yap_Splice_Text(int n, size_t cuts[], seq_tv_t *inp,
unsigned char *buf0, *buf1;
if (outv[0].val.t) {
buf0 = Yap_readText(outv PASS_REGS);
if (!buf0) {
return false;
}
b_l0 = strlen((const char *)buf0);
if (memcmp(buf, buf0, b_l0) != 0) {
pop_text_stack(lvl);
return false;
}
u_l0 = strlen_utf8(buf0);
u_l1 = u_l - u_l0;
buf0 = Yap_readText(outv PASS_REGS);
if (!buf0) {
return false;
}
b_l0 = strlen((const char *)buf0);
if (memcmp(buf, buf0, b_l0) != 0) {
pop_text_stack(lvl);
return false;
}
u_l0 = strlen_utf8(buf0);
u_l1 = u_l - u_l0;
b_l1 = b_l - b_l0;
buf1 = slice(u_l0, u_l, buf PASS_REGS);
b_l1 = strlen((const char *)buf1);
bool rc = write_Text(buf1, outv + 1 PASS_REGS);
pop_text_stack(lvl);
if (!rc) {
return false;
}
return rc;
b_l1 = b_l - b_l0;
buf1 = slice(u_l0, u_l, buf PASS_REGS);
b_l1 = strlen((const char *)buf1);
bool rc = write_Text(buf1, outv + 1 PASS_REGS);
pop_text_stack(lvl);
if (!rc) {
return false;
}
return rc;
} else /* if (outv[1].val.t) */ {
buf1 = Yap_readText(outv + 1 PASS_REGS);
if (!buf1) {
pop_text_stack(lvl);
return false;
}
b_l1 = strlen((char *)buf1);
u_l1 = strlen_utf8(buf1);
b_l0 = b_l - b_l1;
u_l0 = u_l - u_l1;
if (memcmp(skip_utf8((const unsigned char *)buf, b_l0), buf1, b_l1) !=
0) {
pop_text_stack(lvl);
return false;
}
buf0 = slice(0, u_l0, buf PASS_REGS);
buf0 = pop_output_text_stack(lvl, buf0);
bool rc = write_Text(buf0, outv PASS_REGS);
return rc;
buf1 = Yap_readText(outv + 1 PASS_REGS);
if (!buf1) {
pop_text_stack(lvl);
return false;
}
b_l1 = strlen((char *)buf1);
u_l1 = strlen_utf8(buf1);
b_l0 = b_l - b_l1;
u_l0 = u_l - u_l1;
if (memcmp(skip_utf8((const unsigned char *)buf, b_l0), buf1, b_l1) !=
0) {
pop_text_stack(lvl);
return false;
}
buf0 = slice(0, u_l0, buf PASS_REGS);
buf0 = pop_output_text_stack(lvl, buf0);
bool rc = write_Text(buf0, outv PASS_REGS);
return rc;
}
}
}
@ -1147,7 +1181,7 @@ bool Yap_Splice_Text(int n, size_t cuts[], seq_tv_t *inp,
*/
const char *Yap_PredIndicatorToUTF8String(PredEntry *ap) {
CACHE_REGS
Atom at;
Atom at;
arity_t arity = 0;
Functor f;
char *s, *smax, *s0;
@ -1179,7 +1213,7 @@ const char *Yap_PredIndicatorToUTF8String(PredEntry *ap) {
} else if (ap->PredFlags & AtomDBPredFlag) {
at = (Atom)(ap->FunctorOfPred);
if (!stpcpy(s, Yap_AtomToUTF8Text(at)))
return NULL;
return NULL;
} else {
f = ap->FunctorOfPred;
at = NameOfFunctor(f);

View File

@ -472,7 +472,7 @@ static inline Term Yap_AtomicToListOfCodes(Term t0 USES_REGS) {
seq_tv_t inp, out;
inp.val.t = t0;
inp.type = YAP_STRING_STRING | YAP_STRING_ATOM | YAP_STRING_INT |
YAP_STRING_FLOAT | YAP_STRING_BIG | YAP_STRING_TERM;
YAP_STRING_FLOAT | YAP_STRING_BIG ;
out.val.uc = NULL;
out.type = YAP_STRING_CODES;
if (!Yap_CVT_Text(&inp, &out PASS_REGS))
@ -522,8 +522,7 @@ static inline Term Yap_AtomSWIToListOfAtoms(Term t0 USES_REGS) {
inp.val.t = t0;
inp.type = YAP_STRING_ATOM | YAP_STRING_STRING | YAP_STRING_INT |
YAP_STRING_FLOAT | YAP_STRING_BIG | YAP_STRING_ATOMS_CODES |
YAP_STRING_TERM;
YAP_STRING_FLOAT | YAP_STRING_BIG | YAP_STRING_ATOMS_CODES;
out.val.uc = NULL;
out.type = YAP_STRING_ATOMS;

View File

@ -204,7 +204,7 @@ int Yap_open_buf_write_stream(encoding_t enc, memBufSource src) {
st = GLOBAL_Stream + sno;
st->status = Output_Stream_f | InMemory_Stream_f;
if (st->nbuf)
if (src)
st->status |= FreeOnClose_Stream_f;
st->linepos = 0;
st->charcount = 0;
@ -224,6 +224,7 @@ int Yap_open_buf_write_stream(encoding_t enc, memBufSource src) {
#else
st->file = fmemopen((void *)st->nbuf, st->nsize, "w+");
#endif
st->vfs = NULL;
Yap_DefaultStreamOps(st);
UNLOCK(st->streamlock);
return sno;

View File

@ -1973,3 +1973,4 @@ void Yap_InitSysPreds(void) {
Yap_InitCPred("sleep", 1, p_sleep, SyncPredFlag);
Yap_InitCPred("make_directory", 1, make_directory, SyncPredFlag);
}

View File

@ -51,6 +51,8 @@ class JupyterEngine( Engine ):
Engine.__init__(self, args)
self.errors = None
self.goal(set_prolog_flag('verbose', 'silent'),True)
self.goal(compile(library('verify')), True)
self.goal(compile(library('complete')), True)
self.goal(compile(library('jupyter')), True)
self.goal(set_prolog_flag('verbose', 'normal'), True)

View File

@ -1,3 +1,4 @@
/**
* @file jupyter.yap4py
*
@ -16,10 +17,10 @@
:- use_module(library(lists)).
:- use_module(library(maplist)).
:- use_module(library(python)).
:- use_module(library(yapi)).
:- use_module(library(complete)).
:- use_module(library(verify)).
:- reexport(library(python)).
:- reexport(library(yapi)).
:- reexport(library(complete)).
:- reexport(library(verify)).
:- python_import(sys).

View File

@ -6,7 +6,7 @@
:- module( verify,
[errors/2,
[errors/2,q
ready/2]
).
:- use_module(library(hacks)).
@ -22,7 +22,7 @@
ready( Engine, Query) :-
errors( Engine , Cell ),
Es := Engine.errors,
Es == [].
not Es == [].
@ -30,7 +30,7 @@ errors( _Engine , Text ) :-
blank(Text).
!.
errors( Engine , Text ) :-
b_setval(jupyter, Engine),
jupyter..shell := Engine,
setup_call_cleanup(
open_esh( Engine , Text, Stream, Name ),
esh(Engine , Name, Stream),
@ -46,23 +46,26 @@ open_esh(Engine , Text, Stream, Name) :-
open_mem_read_stream( Text, Stream ).
esh(Engine , Name, Stream) :-
b_setval(code,python),
repeat,
catch(
read_clause(Stream, Cl,[]),
E=error(C,E),
p_message(C,E)
),
( read_clause(Stream, Cl, [ syntax_errors(fail)]),
writeln(cl:Cl),
error(C,E),
p_message(C,E)
Cl == end_of_file,
!.
user:print_message() :- p_message
close_esh( _Engine , Stream ) :-
b_delete
close(Stream).
p_message(Severity, Error) :-
writeln((Severity->Error)),
catch( b_getval(jupyter, Engine), _, fail ),
p_message(Severity, Engine, Error).
p_message( _Severity, Engine, error(syntax_error(Cause),info(between(_,LN,_), _FileName, CharPos, Details))) :-

View File

@ -113,9 +113,424 @@ class YAPInputSplitter(InputSplitter):
return True
if not line:
line = text.rstrip()
self.errors = []
engine.mgoal(errors(self, line),"verify",True)
return self.errors != []
engine.errors = []
engine.goal(errors(engine, text),True)
print(engine.errors)
return engine.errors != []
def reset(self):
"""Reset the input buffer and associated state."""
#super(YAPInputSplitter, self).reset()
self._buffer_raw[:] = []
self.source_raw = ''
self.transformer_accumulating = False
for t in self.transforms:
try:
t.reset()
except SyntaxError:
# Nothing that calls reset() expects to handle transformer
# errors
pass
def flush_transformers(self):
def _flush(transform, outs):
"""yield transformed lines
always strings, never None
transform: the current transform
outs: an iterable of previously transformed inputs.
Each may be multiline, which will be passed
one line at a time to transform.
"""
for out in outs:
for line in out.splitlines():
# push one line at a time
tmp = transform.push(line)
if tmp is not None:
yield tmp
# reset the transform
tmp = transform.reset()
if tmp is not None:
yield tmp
out = []
for t in self.transforms:
out = _flush(t, out)
out = list(out)
if out:
self._store('\n'.join(out))
def raw_reset(self):
"""Return raw input only and perform a full reset.
"""
out = self.source_raw
self.reset()
return out
def source_reset(self):
try:
self.flush_transformers()
return self.source
finally:
self.reset()
def push_accepts_more(self):
if self.transformer_accumulating:
return True
else:
return self.validQuery(self.source, engine, self.shell)
def transform_cell(self, cell):
"""Process and translate a cell of input.
"""
self.reset()
try:
self.push(cell)
self.flush_transformers()
return self.source
finally:
self.reset()
def push(self, lines):
"""Push one or more lines of yap_ipython input.
This stores the given lines and returns a status code indicating
whether the code forms a complete Python block or not, after processing
all input lines for special yap_ipython syntax.
Any exceptions generated in compilation are swallowed, but if an
exception was produced, the method returns True.
Parameters
----------
lines : string
One or more lines of Python input.
Returns
-------
is_complete : boolean
True if the current input source (the result of the current input
plus prior inputs) forms a complete Python execution block. Note that
this value is also stored as a private attribute (_is_complete), so it
can be queried at any time.
"""
# We must ensure all input is pure unicode
lines = cast_unicode(lines, self.encoding)
# ''.splitlines() --> [], but we need to push the empty line to transformers
lines_list = lines.splitlines()
if not lines_list:
lines_list = ['']
# Store raw source before applying any transformations to it. Note
# that this must be done *after* the reset() call that would otherwise
# flush the buffer.
self._store(lines, self._buffer_raw, 'source_raw')
transformed_lines_list = []
for line in lines_list:
transformed = self._transform_line(line)
if transformed is not None:
transformed_lines_list.append(transformed)
if transformed_lines_list:
transformed_lines = '\n'.join(transformed_lines_list)
else:
# Got nothing back from transformers - they must be waiting for
# more input.
return False
def _transform_line(self, line):
"""Push a line of input code through the various transformers.
Returns any output from the transformers, or None if a transformer
is accumulating lines.
Sets self.transformer_accumulating as a side effect.
"""
def _accumulating(dbg):
#print(dbg)
self.transformer_accumulating = True
return None
for transformer in self.physical_line_transforms:
line = transformer.push(line)
if line is None:
return _accumulating(transformer)
for transformer in self.logical_line_transforms:
line = transformer.push(line)
if line is None:
return _accumulating(transformer)
#print("transformers clear") #debug
self.transformer_accumulating = False
return line
class YAPCompleter(Completer):
greedy = Bool(False,
help="""Activate greedy completion
PENDING DEPRECTION. this is now mostly taken care of with Jedi.
This will enable completion on elements of lists, self.results of function calls, etc.,
but can be unsafe because the code is actually evaluated on TAB.
"""
).tag(config=True)
debug = Bool(default_value=False,
help='Enable debug for the Completer. Mostly print extra '
'information for experimental jedi integration.') \
.tag(config=True)
backslash_combining_completions = Bool(True,
help="Enable unicode completions, e.g. \\alpha<tab> . "
"Includes completion of latex commands, unicode names, and expanding "
"unicode characters back to latex commands.").tag(config=True)
def __init__(self, namespace=None, global_namespace=None, shell=None, **kwargs):
"""Create a new completer for the command line.
Completer(namespace=ns, global_namespace=ns2) -> completer instance.
"""
self.shell = shell
self.magic_escape = ESC_MAGIC
super(Completer, self).__init__(**kwargs)
def complete(self, text, line=None, cursor_pos=None):
"""Return the completed text and a list of completions.
Parameters
----------
text : string
A string of text to be completed on. It can be given as empty and
instead a line/position pair are given. In this case, the
completer itself will split the line like readline does.
This is called successively with state == 0, 1, 2, ... until it
returns None. The completion should begin with 'text'.
line : string, optional
The complete line that text is part of.
cursor_pos : int, optional
The position of the cursor on the input line.
Returns
-------
text : string
The actual text that was completed.
matches : list
A sorted list with all possible completions.
The optional arguments allow the completion to take more context into
account, and are part of the low-level completion API.
This is a wrapper around the completion mechanism, similar to what
readline does at the command line when the TAB key is hit. By
exposing it as a method, it can be used by other non-readline
environments (such as GUIs) for text completion.
Simple usage example:
In [1]: x = 'hello'
In [2]: _ip.complete('x.l')
Out[2]: ('x.l', ['x.ljust', 'x.lower', 'x.lstrip'])
"""
if not text:
text = line[:cursor_pos]
return self.completions(text, cursor_pos)
def magic_matches(self, text):
"""Match magics"""
# Get all shell magics now rather than statically, so magics loaded at
# runtime show up too.
lsm = self.shell.magics_manager.lsmagic()
line_magics = lsm['line']
cell_magics = lsm['cell']
pre = self.magic_escape
pre2 = pre+pre
explicit_magic = text.startswith(pre)
# Completion logic:
# - user gives %%: only do cell magics
# - user gives %: do both line and cell magics
# - no prefix: do both
# In other words, line magics are skipped if the user gives %% explicitly
#
# We also exclude magics that match any currently visible names:
# https://github.com/ipython/ipython/issues/4877, unless the user has
# typed a %:
# https://github.com/ipython/ipython/issues/10754
bare_text = text.lstrip(pre)
global_matches = []
if not explicit_magic:
def matches(magic):
"""
Filter magics, in particular remove magics that match
a name present in global namespace.
"""
return ( magic.startswith(bare_text) and
magic not in global_matches )
else:
def matches(magic):
return magic.startswith(bare_text)
comp = [ pre2+m for m in cell_magics if matches(m)]
if not text.startswith(pre2):
comp += [ pre+m for m in line_magics if matches(m)]
return comp
def magic_config_matches(self, text): #:str) -> List[str]:
""" Match class names and attributes for %config magic """
texts = text.strip().split()
if len(texts) > 0 and (texts[0] == 'config' or texts[0] == '%config'):
# get all configuration classes
classes = sorted(set([ c for c in self.shell.configurables
if c.__class__.class_traits(config=True)
]), key=lambda x: x.__class__.__name__)
classnames = [ c.__class__.__name__ for c in classes ]
# return all classnames if config or %config is given
if len(texts) == 1:
return classnames
# match classname
classname_texts = texts[1].split('.')
classname = classname_texts[0]
classname_matches = [ c for c in classnames
if c.startswith(classname) ]
# return matched classes or the matched class with attributes
if texts[1].find('.') < 0:
return classname_matches
elif len(classname_matches) == 1 and \
classname_matches[0] == classname:
cls = classes[classnames.index(classname)].__class__
help = cls.class_get_help()
# strip leading '--' from cl-args:
help = re.sub(re.compile(r'^--', re.MULTILINE), '', help)
return [ attr.split('=')[0]
for attr in help.strip().splitlines()
if attr.startswith(texts[1]) ]
return []
def magic_color_matches(self, text): #:str) -> List[str] :
""" Match color schemes for %colors magic"""
texts = text.split()
if text.endswith(' '):
# .split() strips off the trailing whitespace. Add '' back
# so that: '%colors ' -> ['%colors', '']
texts.append('')
if len(texts) == 2 and (texts[0] == 'colors' or texts[0] == '%colors'):
prefix = texts[1]
return [ color for color in InspectColors.keys()
if color.startswith(prefix) ]
return []
def completions(self, text, offset):
"""
Returns an iterator over the possible completions
.. warning:: Unstable
This function is unstable, API may change without warning.
It will also raise unless use in proper context manager.
Parameters
----------
text:str
Full text of the current input, multi line string.
offset:int
Integer representing the position of the cursor in ``text``. Offset
is 0-based indexed.
Yields
------
:any:`Completion` object
The cursor on a text can either be seen as being "in between"
characters or "On" a character depending on the interface visible to
the user. For consistency the cursor being on "in between" characters X
and Y is equivalent to the cursor being "on" character Y, that is to say
the character the cursor is on is considered as being after the cursor.
Combining characters may span more that one position in the
text.
.. note::
If ``IPCompleter.debug`` is :any:`True` will yield a ``--jedi/ipython--``
fake Completion token to distinguish completion returned by Jedi
and usual yap_ipython completion.
.. note::
Completions are not completely deduplicated yet. If identical
completions are coming from different sources this function does not
ensure that each completion object will only be present once.
"""
self.matches = []
prolog_res = self.shell.yapeng.goal(completions(text, self),True)
if self.matches:
return text, self.matches
magic_res = self.magic_matches(text)
return text, magic_res
class YAPRun:
"""An enhanced, interactive shell for YAP."""
def __init__(self, shell):
self.shell = shell
self.yapeng = JupyterEngine()
global engine
engine = self.yapeng
self.query = None
self.os = None
self.it = None
self.shell.yapeng = self.yapeng
self._get_exc_info = shell._get_exc_info
def syntaxErrors(self, text):
"""Return whether a legal query
"""
if not text:
return []
if text == self.os:
return self.yapeng.errors
(text,_,_,_) = self.clean_end(text)
self.yapeng.goal(errors(self.yapeng,text),True)
print( self.yapeng.errors )
return self.yapeng.errors != []
def reset(self):
@ -496,7 +911,7 @@ class YAPCompleter(Completer):
ensure that each completion object will only be present once.
"""
self.matches = []
prolog_res = self.shell.yapeng.mgoal(completions(text, self), "user",True)
prolog_res = self.shell.yapeng.goal(completions(text, self),True)
if self.matches:
return text, self.matches
magic_res = self.magic_matches(text)
@ -525,11 +940,11 @@ class YAPRun:
if not text:
return []
if text == self.os:
return self.errors
self.errors=[]
return self.yapeng.errors
(text,_,_,_) = self.clean_end(text)
self.yapeng.mgoal(errors(self,text),"verify",True)
return self.errors
self.yapeng.goal(errors(self.yapeng,text),True)
print( self.yapeng.errors )
return self.yapeng.errors
def jupyter_query(self, s):
#
@ -612,7 +1027,6 @@ class YAPRun:
# you can print it out, the left-side is the variable name,
# the right side wraps a handle to a variable
#import pdb; pdb.set_trace()
# #pdb.set_trace()
# atom match either symbols, or if no symbol exists, strings, In this case
# variable names should match strings
# ask = True
@ -653,8 +1067,9 @@ class YAPRun:
# except SyntaxError:
# preprocessing_exc_tuple = self.shell.syntax_error() # sys.exc_info()
cell = raw_cell # cell has to exist so it can be stored/logged
self.yapeng.mgoal(streams(True),"jupyter", True)
for i in self.syntaxErrors(raw_cell):
self.yapeng.goal(streams(True), True)
errors = self.syntaxErrors(raw_cell)
for i in errors:
try:
(what,lin,_,text) = i
e = SyntaxError(what, ("<string>", lin, 1, text))
@ -733,9 +1148,9 @@ class YAPRun:
except Exception as e:
has_raised = True
self.result.result = False
self.yapeng.mgoal(streams(False),"jupyter", True)
self.yapeng.goal(streams(False), True)
self.yapeng.mgoal(streams(False),"jupyter", True)
self.yapeng.goal(ODstreams(False), True)
self.shell.last_execution_succeeded = not has_raised
# Reset this so later displayed values do not modify the

View File

@ -216,10 +216,6 @@ static void
{
yap_error_number en = e.getID();
std::cerr << e.text() << "\n";
return;
switch (e.getErrorClass()) {
case YAPC_NO_ERROR:
break;

View File

@ -125,7 +125,7 @@ Call goal _H_ once per each solution of goal _H_. If goal
_H_ has no solutions, call goal _I_.
The built-in `if/3` is similar to `->/3`, with the difference
that it will backtrack over the test https://wiki.python.org/moin/HandlingExceptionsgoal. Consider the following
that it will backtrack over the test. Consider the following
small data-base:
~~~~~{.prolog}