2015-06-18 01:47:23 +01:00
|
|
|
|
|
|
|
#include "pl-ctype.h"
|
|
|
|
#include "pl-dtoa.h"
|
2016-12-04 18:52:42 +00:00
|
|
|
#include "pl-incl.h"
|
|
|
|
#include "pl-umap.c" /* Unicode map */
|
|
|
|
#include "pl-utf8.h"
|
2015-06-18 01:47:23 +01:00
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
#include "pl-read.h" /* read structure */
|
2015-06-18 01:47:23 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @defgroup ReadTerm Read Term from Streams
|
|
|
|
* @ingroup InputOutput
|
|
|
|
* @{
|
|
|
|
*/
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
static bool isStringStream(IOSTREAM *s) {
|
|
|
|
return s->functions == &Sstringfunctions;
|
2015-06-18 01:47:23 +01:00
|
|
|
}
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
void init_read_data(ReadData _PL_rd, IOSTREAM *in ARG_LD) {
|
|
|
|
CACHE_REGS
|
|
|
|
memset(_PL_rd, 0, sizeof(*_PL_rd)); /* optimise! */
|
2015-06-18 01:47:23 +01:00
|
|
|
|
|
|
|
_PL_rd->magic = RD_MAGIC;
|
|
|
|
_PL_rd->varnames = 0;
|
|
|
|
_PL_rd->module = Yap_GetModuleEntry(CurrentModule);
|
|
|
|
_PL_rd->exception = 0;
|
|
|
|
_PL_rd->stream = in;
|
|
|
|
_PL_rd->has_exception = 0;
|
|
|
|
_PL_rd->module = MODULE_parse;
|
2016-12-04 18:52:42 +00:00
|
|
|
_PL_rd->flags = _PL_rd->module->flags; /* change for options! */
|
2015-06-18 01:47:23 +01:00
|
|
|
_PL_rd->styleCheck = LOCAL_debugstatus.styleCheck;
|
|
|
|
_PL_rd->on_error = AtomError;
|
|
|
|
_PL_rd->backquoted_string = truePrologFlag(PLFLAG_BACKQUOTED_STRING);
|
|
|
|
}
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
void free_read_data(ReadData _PL_rd) {}
|
2015-06-18 01:47:23 +01:00
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
static int read_term(term_t t, ReadData _PL_rd ARG_LD) {
|
2015-06-18 01:47:23 +01:00
|
|
|
return Yap_read_term(t, rb.stream, _PL_rd);
|
|
|
|
}
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
static void addUTF8Buffer(Buffer b, int c);
|
2015-06-18 01:47:23 +01:00
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
static void addUTF8Buffer(Buffer b, int c) {
|
|
|
|
if (c >= 0x80) {
|
|
|
|
char buf[6];
|
|
|
|
char *p, *end;
|
2015-06-18 01:47:23 +01:00
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
end = utf8_put_char(buf, c);
|
|
|
|
for (p = buf; p < end; p++) {
|
|
|
|
addBuffer(b, *p & 0xff, char);
|
2015-06-18 01:47:23 +01:00
|
|
|
}
|
2016-12-04 18:52:42 +00:00
|
|
|
} else {
|
|
|
|
addBuffer(b, c, char);
|
|
|
|
}
|
2015-06-18 01:47:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*******************************
|
|
|
|
* UNICODE CLASSIFIERS *
|
|
|
|
*******************************/
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
#define CharTypeW(c, t, w) \
|
|
|
|
((unsigned)(c) <= 0xff ? (_PL_char_types[(unsigned)(c)] t) \
|
|
|
|
: (uflagsW(c) & (w)))
|
|
|
|
|
|
|
|
#define PlBlankW(c) CharTypeW(c, == SP, U_SEPARATOR)
|
|
|
|
#define PlUpperW(c) CharTypeW(c, == UC, U_UPPERCASE)
|
|
|
|
#define PlIdStartW(c) \
|
|
|
|
(c <= 0xff ? (isLower(c) || isUpper(c) || c == '_') : uflagsW(c) & U_ID_START)
|
|
|
|
#define PlIdContW(c) CharTypeW(c, >= UC, U_ID_CONTINUE)
|
|
|
|
#define PlSymbolW(c) CharTypeW(c, == SY, U_SYMBOL)
|
|
|
|
#define PlPunctW(c) CharTypeW(c, == PU, 0)
|
|
|
|
#define PlSoloW(c) CharTypeW(c, == SO, U_OTHER)
|
|
|
|
#define PlInvalidW(c) (uflagsW(c) == 0)
|
|
|
|
|
|
|
|
int f_is_prolog_var_start(wint_t c) {
|
|
|
|
return PlIdStartW(c) && (PlUpperW(c) || c == '_');
|
2015-06-18 01:47:23 +01:00
|
|
|
}
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
int f_is_prolog_atom_start(wint_t c) { return PlIdStartW(c) != 0; }
|
2015-06-18 01:47:23 +01:00
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
int f_is_prolog_identifier_continue(wint_t c) {
|
|
|
|
return PlIdContW(c) || c == '_';
|
2015-06-18 01:47:23 +01:00
|
|
|
}
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
int f_is_prolog_symbol(wint_t c) { return PlSymbolW(c) != 0; }
|
2015-06-18 01:47:23 +01:00
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
int unicode_separator(pl_wchar_t c) { return PlBlankW(c); }
|
2015-06-18 01:47:23 +01:00
|
|
|
|
|
|
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
FALSE return false
|
|
|
|
TRUE redo
|
|
|
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
static int reportReadError(ReadData rd) {
|
|
|
|
if (rd->on_error == ATOM_error)
|
2015-06-18 01:47:23 +01:00
|
|
|
return PL_raise_exception(rd->exception);
|
2016-12-04 18:52:42 +00:00
|
|
|
if (rd->on_error != ATOM_quiet)
|
2015-06-18 01:47:23 +01:00
|
|
|
printMessage(ATOM_error, PL_TERM, rd->exception);
|
|
|
|
PL_clear_exception();
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
if (rd->on_error == ATOM_dec10)
|
2015-06-18 01:47:23 +01:00
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static int */
|
2016-12-04 18:52:42 +00:00
|
|
|
/* reportSingletons(ReadData rd, singletons, Atom amod, Atom aname, UInt arity)
|
|
|
|
*/
|
2015-06-18 01:47:23 +01:00
|
|
|
/* { */
|
|
|
|
/* printMessage(ATOM_warning, PL_FUNCTOR_CHARS, */
|
|
|
|
/* "singletons", 2, */
|
|
|
|
/* PL_TERM, singletons, */
|
|
|
|
/* PL_TERM, mod, */
|
|
|
|
/* PL_FUNCTOR_divide2, */
|
|
|
|
/* PL_ATOM, name, */
|
|
|
|
/* PL_INT, arity); */
|
|
|
|
|
|
|
|
/* return FALSE; */
|
|
|
|
/* } */
|
|
|
|
|
|
|
|
/********************************
|
|
|
|
* RAW READING *
|
|
|
|
*********************************/
|
|
|
|
|
|
|
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
Scan the input, give prompts when necessary and return a char * holding
|
|
|
|
a stripped version of the next term. Contiguous white space is mapped
|
|
|
|
on a single space, block and % ... \n comment is deleted. Memory is
|
|
|
|
claimed automatically en enlarged if necessary.
|
|
|
|
|
|
|
|
(char *) NULL is returned on a syntax error.
|
|
|
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
#define syntaxError(what, rd) \
|
|
|
|
{ \
|
|
|
|
errorWarning(what, 0, rd); \
|
|
|
|
fail; \
|
|
|
|
}
|
2015-06-18 01:47:23 +01:00
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
static term_t makeErrorTerm(const char *id_str, term_t id_term,
|
|
|
|
ReadData _PL_rd) {
|
|
|
|
GET_LD
|
|
|
|
term_t ex, loc = 0; /* keep compiler happy */
|
2015-06-18 01:47:23 +01:00
|
|
|
unsigned char const *s, *ll = NULL;
|
|
|
|
int rc = TRUE;
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
if (!(ex = PL_new_term_ref()) || !(loc = PL_new_term_ref()))
|
2015-06-18 01:47:23 +01:00
|
|
|
rc = FALSE;
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
if (rc && !id_term) {
|
|
|
|
if (!(id_term = PL_new_term_ref()) || !PL_put_atom_chars(id_term, id_str))
|
|
|
|
rc = FALSE;
|
|
|
|
}
|
2015-06-18 01:47:23 +01:00
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
if (rc)
|
|
|
|
rc = PL_unify_term(ex, PL_FUNCTOR, FUNCTOR_error2, PL_FUNCTOR,
|
|
|
|
FUNCTOR_syntax_error1, PL_TERM, id_term, PL_TERM, loc);
|
2015-06-18 01:47:23 +01:00
|
|
|
|
|
|
|
source_char_no += last_token_start - rdbase;
|
2016-12-04 18:52:42 +00:00
|
|
|
for (s = rdbase; s < last_token_start; s++) {
|
|
|
|
if (*s == '\n') {
|
|
|
|
source_line_no++;
|
|
|
|
ll = s + 1;
|
2015-06-18 01:47:23 +01:00
|
|
|
}
|
2016-12-04 18:52:42 +00:00
|
|
|
}
|
2015-06-18 01:47:23 +01:00
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
if (ll) {
|
|
|
|
int lp = 0;
|
|
|
|
|
|
|
|
for (s = ll; s < last_token_start; s++) {
|
|
|
|
switch (*s) {
|
|
|
|
case '\b':
|
|
|
|
if (lp > 0)
|
|
|
|
lp--;
|
|
|
|
break;
|
|
|
|
case '\t':
|
|
|
|
lp |= 7;
|
|
|
|
default:
|
|
|
|
lp++;
|
|
|
|
}
|
2015-06-18 01:47:23 +01:00
|
|
|
}
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
source_line_pos = lp;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rc) {
|
|
|
|
if (ReadingSource) /* reading a file */
|
|
|
|
{
|
|
|
|
rc = PL_unify_term(loc, PL_FUNCTOR, FUNCTOR_file4, PL_ATOM,
|
|
|
|
source_file_name, PL_INT, source_line_no, PL_INT,
|
|
|
|
source_line_pos, PL_INT64, source_char_no);
|
|
|
|
} else if (isStringStream(rb.stream)) {
|
|
|
|
size_t pos;
|
|
|
|
|
|
|
|
pos = utf8_strlen((char *)rdbase, last_token_start - rdbase);
|
|
|
|
|
|
|
|
rc = PL_unify_term(loc, PL_FUNCTOR, FUNCTOR_string2, PL_UTF8_STRING,
|
|
|
|
rdbase, PL_INT, (int)pos);
|
|
|
|
} else /* any stream */
|
|
|
|
{
|
|
|
|
term_t stream;
|
|
|
|
|
|
|
|
if (!(stream = PL_new_term_ref()) ||
|
|
|
|
!PL_unify_stream_or_alias(stream, rb.stream) ||
|
|
|
|
!PL_unify_term(loc, PL_FUNCTOR, FUNCTOR_stream4, PL_TERM, stream,
|
|
|
|
PL_INT, source_line_no, PL_INT, source_line_pos,
|
|
|
|
PL_INT64, source_char_no))
|
|
|
|
rc = FALSE;
|
2015-06-18 01:47:23 +01:00
|
|
|
}
|
2016-12-04 18:52:42 +00:00
|
|
|
}
|
2015-06-18 01:47:23 +01:00
|
|
|
|
|
|
|
return (rc ? ex : (term_t)0);
|
|
|
|
}
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
static bool errorWarning(const char *id_str, term_t id_term, ReadData _PL_rd) {
|
|
|
|
GET_LD
|
|
|
|
term_t ex;
|
2015-06-18 01:47:23 +01:00
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
LD->exception.processing = TRUE; /* allow using spare stack */
|
2015-06-18 01:47:23 +01:00
|
|
|
|
|
|
|
ex = makeErrorTerm(id_str, id_term, _PL_rd);
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
if (_PL_rd) {
|
|
|
|
_PL_rd->has_exception = TRUE;
|
|
|
|
if (ex)
|
|
|
|
PL_put_term(_PL_rd->exception, ex);
|
|
|
|
else
|
|
|
|
PL_put_term(_PL_rd->exception, exception_term);
|
|
|
|
} else {
|
|
|
|
if (ex)
|
|
|
|
PL_raise_exception(ex);
|
|
|
|
}
|
2015-06-18 01:47:23 +01:00
|
|
|
|
|
|
|
fail;
|
|
|
|
}
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
static void clearBuffer(ReadData _PL_rd) {
|
|
|
|
if (rb.size == 0) {
|
|
|
|
rb.base = rb.fast;
|
|
|
|
rb.size = sizeof(rb.fast);
|
|
|
|
}
|
2015-06-18 01:47:23 +01:00
|
|
|
rb.end = rb.base + rb.size;
|
|
|
|
rdbase = rb.here = rb.base;
|
|
|
|
|
|
|
|
_PL_rd->posp = rdbase;
|
|
|
|
_PL_rd->posi = 0;
|
|
|
|
}
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
static void growToBuffer(int c, ReadData _PL_rd) {
|
|
|
|
if (rb.base == rb.fast) /* intptr_t clause: jump to use malloc() */
|
|
|
|
{
|
|
|
|
rb.base = PL_malloc(FASTBUFFERSIZE * 2);
|
|
|
|
memcpy(rb.base, rb.fast, FASTBUFFERSIZE);
|
|
|
|
} else
|
|
|
|
rb.base = PL_realloc(rb.base, rb.size * 2);
|
2015-06-18 01:47:23 +01:00
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
DEBUG(8, Sdprintf("Reallocated read buffer at %ld\n", (intptr_t)rb.base));
|
2015-06-18 01:47:23 +01:00
|
|
|
_PL_rd->posp = rdbase = rb.base;
|
|
|
|
rb.here = rb.base + rb.size;
|
|
|
|
rb.size *= 2;
|
2016-12-04 18:52:42 +00:00
|
|
|
rb.end = rb.base + rb.size;
|
2015-06-18 01:47:23 +01:00
|
|
|
_PL_rd->posi = 0;
|
|
|
|
|
|
|
|
*rb.here++ = c;
|
|
|
|
}
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
static inline void addByteToBuffer(int c, ReadData _PL_rd) {
|
|
|
|
c &= 0xff;
|
2015-06-18 01:47:23 +01:00
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
if (rb.here >= rb.end)
|
2015-06-18 01:47:23 +01:00
|
|
|
growToBuffer(c, _PL_rd);
|
|
|
|
else
|
|
|
|
*rb.here++ = c;
|
|
|
|
}
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
static void addToBuffer(int c, ReadData _PL_rd) {
|
|
|
|
if (c <= 0x7f) {
|
|
|
|
addByteToBuffer(c, _PL_rd);
|
|
|
|
} else {
|
|
|
|
char buf[10];
|
|
|
|
char *s, *e;
|
2015-06-18 01:47:23 +01:00
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
e = utf8_put_char(buf, c);
|
|
|
|
for (s = buf; s < e; s++)
|
|
|
|
addByteToBuffer(*s, _PL_rd);
|
|
|
|
}
|
2015-06-18 01:47:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#if __YAP_PROLOG__
|
2016-12-04 18:52:42 +00:00
|
|
|
void Yap_setCurrentSourceLocation(void *rd) {
|
2015-06-18 01:47:23 +01:00
|
|
|
GET_LD
|
2016-12-04 18:52:42 +00:00
|
|
|
setCurrentSourceLocation(rd PASS_LD);
|
2015-06-18 01:47:23 +01:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
static inline int getchr__(ReadData _PL_rd) {
|
|
|
|
int c = Sgetcode(rb.stream);
|
2015-06-18 01:47:23 +01:00
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
if (!_PL_rd->char_conversion_table || c < 0 || c >= 256)
|
2015-06-18 01:47:23 +01:00
|
|
|
return c;
|
|
|
|
|
|
|
|
return _PL_rd->char_conversion_table[c];
|
|
|
|
}
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
#define getchr() getchr__(_PL_rd)
|
2015-06-18 01:47:23 +01:00
|
|
|
#define getchrq() Sgetcode(rb.stream)
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
#define ensure_space(c) \
|
|
|
|
{ \
|
|
|
|
if (something_read && (c == '\n' || !isBlank(rb.here[-1]))) \
|
|
|
|
addToBuffer(c, _PL_rd); \
|
2015-06-18 01:47:23 +01:00
|
|
|
}
|
2016-12-04 18:52:42 +00:00
|
|
|
#define set_start_line \
|
|
|
|
{ \
|
|
|
|
if (!something_read) { \
|
|
|
|
setCurrentSourceLocation(_PL_rd PASS_LD); \
|
|
|
|
something_read++; \
|
|
|
|
} \
|
2015-06-18 01:47:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef O_QUASIQUOTATIONS
|
|
|
|
/** '$qq_open'(+QQRange, -Stream) is det.
|
|
|
|
|
|
|
|
Opens a quasi-quoted memory range.
|
|
|
|
|
|
|
|
@arg QQRange is a term '$quasi_quotation'(ReadData, Start, Length)
|
|
|
|
@arg Stream is a UTF-8 encoded string, whose position indication
|
|
|
|
reflects the location in the real file.
|
|
|
|
*/
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
static PRED_IMPL("$qq_open", 2, qq_open, 0) {
|
|
|
|
PRED_LD
|
|
|
|
|
|
|
|
if (PL_is_functor(A1, FUNCTOR_dquasi_quotation3)) {
|
|
|
|
void *ptr;
|
|
|
|
char *start;
|
|
|
|
size_t len;
|
|
|
|
term_t arg = PL_new_term_ref();
|
|
|
|
IOSTREAM *s;
|
|
|
|
|
|
|
|
if (PL_get_arg(1, A1, arg) && PL_get_pointer_ex(arg, &ptr) &&
|
|
|
|
PL_get_arg(2, A1, arg) && PL_get_intptr(arg, (intptr_t *)&start) &&
|
|
|
|
PL_get_arg(3, A1, arg) &&
|
|
|
|
PL_get_intptr(arg, (intptr_t *)&len)) { // source_location pos;
|
|
|
|
if ((s = Sopenmem(&start, &len, "r")))
|
|
|
|
s->encoding = ENC_UTF8;
|
|
|
|
|
|
|
|
return PL_unify_stream(A2, s);
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
PL_type_error("read_context", A1);
|
2015-06-18 01:47:23 +01:00
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
static int parse_quasi_quotations(ReadData _PL_rd ARG_LD) {
|
|
|
|
if (_PL_rd->qq_tail) {
|
|
|
|
term_t av;
|
|
|
|
int rc;
|
2015-06-18 01:47:23 +01:00
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
if (!PL_unify_nil(_PL_rd->qq_tail))
|
|
|
|
return FALSE;
|
2015-06-18 01:47:23 +01:00
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
if (!_PL_rd->quasi_quotations) {
|
|
|
|
if ((av = PL_new_term_refs(2)) && PL_put_term(av + 0, _PL_rd->qq) &&
|
2015-06-18 01:47:23 +01:00
|
|
|
#if __YAP_PROLOG__
|
2016-12-04 18:52:42 +00:00
|
|
|
PL_put_atom(av + 1, YAP_SWIAtomFromAtom(_PL_rd->module->AtomOfME)) &&
|
2015-06-18 01:47:23 +01:00
|
|
|
#else
|
2016-12-04 18:52:42 +00:00
|
|
|
PL_put_atom(av + 1, _PL_rd->module->name) &&
|
2015-06-18 01:47:23 +01:00
|
|
|
#endif
|
2016-12-04 18:52:42 +00:00
|
|
|
PL_cons_functor_v(av, FUNCTOR_dparse_quasi_quotations2, av)) {
|
|
|
|
term_t ex;
|
|
|
|
rc = callProlog(MODULE_system, av + 0, PL_Q_CATCH_EXCEPTION, &ex);
|
|
|
|
if (rc)
|
|
|
|
return TRUE;
|
|
|
|
_PL_rd->exception = ex;
|
|
|
|
_PL_rd->has_exception = TRUE;
|
|
|
|
}
|
|
|
|
return FALSE;
|
2015-06-18 01:47:23 +01:00
|
|
|
} else
|
2016-12-04 18:52:42 +00:00
|
|
|
return TRUE;
|
|
|
|
} else if (_PL_rd->quasi_quotations) /* user option, but no quotes */
|
|
|
|
{
|
|
|
|
return PL_unify_nil(_PL_rd->quasi_quotations);
|
|
|
|
} else
|
2015-06-18 01:47:23 +01:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /*O_QUASIQUOTATIONS*/
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
#define rawSyntaxError(what) \
|
|
|
|
{ \
|
|
|
|
addToBuffer(EOS, _PL_rd); \
|
|
|
|
rdbase = rb.base, last_token_start = rb.here - 1; \
|
|
|
|
syntaxError(what, _PL_rd); \
|
2015-06-18 01:47:23 +01:00
|
|
|
}
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
static int raw_read_quoted(int q, ReadData _PL_rd) {
|
|
|
|
int newlines = 0;
|
2015-06-18 01:47:23 +01:00
|
|
|
int c;
|
|
|
|
|
|
|
|
addToBuffer(q, _PL_rd);
|
2016-12-04 18:52:42 +00:00
|
|
|
while ((c = getchrq()) != EOF && c != q) {
|
|
|
|
if (c == '\\' && DO_CHARESCAPE) {
|
|
|
|
int base;
|
2015-06-18 01:47:23 +01:00
|
|
|
addToBuffer(c, _PL_rd);
|
2016-12-04 18:52:42 +00:00
|
|
|
|
|
|
|
switch ((c = getchrq())) {
|
|
|
|
case EOF:
|
|
|
|
goto eofinstr;
|
|
|
|
case 'u': /* \uXXXX */
|
|
|
|
case 'U': /* \UXXXXXXXX */
|
|
|
|
addToBuffer(c, _PL_rd);
|
|
|
|
continue;
|
|
|
|
case 'x': /* \xNN\ */
|
|
|
|
addToBuffer(c, _PL_rd);
|
|
|
|
c = getchrq();
|
|
|
|
if (c == EOF)
|
|
|
|
goto eofinstr;
|
|
|
|
if (digitValue(16, c) >= 0) {
|
|
|
|
base = 16;
|
|
|
|
addToBuffer(c, _PL_rd);
|
|
|
|
|
|
|
|
xdigits:
|
|
|
|
c = getchrq();
|
|
|
|
while (digitValue(base, c) >= 0) {
|
|
|
|
addToBuffer(c, _PL_rd);
|
|
|
|
c = getchrq();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (c == EOF)
|
|
|
|
goto eofinstr;
|
|
|
|
addToBuffer(c, _PL_rd);
|
|
|
|
if (c == q)
|
|
|
|
return TRUE;
|
|
|
|
continue;
|
|
|
|
default:
|
|
|
|
addToBuffer(c, _PL_rd);
|
|
|
|
if (digitValue(8, c) >= 0) /* \NNN\ */
|
|
|
|
{
|
|
|
|
base = 8;
|
|
|
|
goto xdigits;
|
|
|
|
} else if (c == '\n') /* \<newline> */
|
|
|
|
{
|
|
|
|
c = getchrq();
|
|
|
|
if (c == EOF)
|
|
|
|
goto eofinstr;
|
|
|
|
addToBuffer(c, _PL_rd);
|
|
|
|
if (c == q)
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
continue; /* \symbolic-control-char */
|
|
|
|
}
|
|
|
|
} else if (c == '\n' && newlines++ > MAXNEWLINES &&
|
|
|
|
(_PL_rd->styleCheck & LONGATOM_CHECK)) {
|
|
|
|
rawSyntaxError("long_string");
|
2015-06-18 01:47:23 +01:00
|
|
|
}
|
2016-12-04 18:52:42 +00:00
|
|
|
addToBuffer(c, _PL_rd);
|
|
|
|
}
|
|
|
|
if (c == EOF) {
|
|
|
|
eofinstr:
|
|
|
|
rawSyntaxError("end_of_file_in_string");
|
|
|
|
}
|
2015-06-18 01:47:23 +01:00
|
|
|
addToBuffer(c, _PL_rd);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
static int add_comment(Buffer b, IOPOS *pos, ReadData _PL_rd ARG_LD) {
|
|
|
|
term_t head = PL_new_term_ref();
|
2015-06-18 01:47:23 +01:00
|
|
|
|
|
|
|
assert(_PL_rd->comments);
|
2016-12-04 18:52:42 +00:00
|
|
|
if (!PL_unify_list(_PL_rd->comments, head, _PL_rd->comments))
|
2015-06-18 01:47:23 +01:00
|
|
|
return FALSE;
|
2016-12-04 18:52:42 +00:00
|
|
|
if (pos) {
|
|
|
|
if (!PL_unify_term(head, PL_FUNCTOR, FUNCTOR_minus2, PL_FUNCTOR,
|
|
|
|
FUNCTOR_stream_position4, PL_INT64, pos->charno, PL_INT,
|
|
|
|
pos->lineno, PL_INT, pos->linepos, PL_INT, 0,
|
|
|
|
PL_UTF8_STRING, baseBuffer(b, char)))
|
|
|
|
return FALSE;
|
|
|
|
} else {
|
|
|
|
if (!PL_unify_term(head, PL_FUNCTOR, FUNCTOR_minus2, ATOM_minus,
|
|
|
|
PL_UTF8_STRING, baseBuffer(b, char)))
|
|
|
|
return FALSE;
|
|
|
|
}
|
2015-06-18 01:47:23 +01:00
|
|
|
|
|
|
|
PL_reset_term_refs(head);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
static void setErrorLocation(IOPOS *pos, ReadData _PL_rd) {
|
|
|
|
if (pos) {
|
|
|
|
GET_LD
|
2015-06-18 01:47:23 +01:00
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
source_char_no = pos->charno;
|
|
|
|
source_line_pos = pos->linepos;
|
|
|
|
source_line_no = pos->lineno;
|
|
|
|
}
|
|
|
|
rb.here = rb.base + 1; /* see rawSyntaxError() */
|
2015-06-18 01:47:23 +01:00
|
|
|
}
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
static unsigned char *raw_read2(ReadData _PL_rd ARG_LD) {
|
|
|
|
int c;
|
2015-06-18 01:47:23 +01:00
|
|
|
bool something_read = FALSE;
|
|
|
|
bool dotseen = FALSE;
|
2016-12-04 18:52:42 +00:00
|
|
|
IOPOS pbuf; /* comment start */
|
2015-06-18 01:47:23 +01:00
|
|
|
IOPOS *pos;
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
clearBuffer(_PL_rd); /* clear input buffer */
|
2015-06-18 01:47:23 +01:00
|
|
|
_PL_rd->strictness = truePrologFlag(PLFLAG_ISO);
|
|
|
|
source_line_no = -1;
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
for (;;) {
|
|
|
|
c = getchr();
|
|
|
|
|
|
|
|
handle_c:
|
|
|
|
switch (c) {
|
|
|
|
case EOF:
|
|
|
|
if (isStringStream(rb.stream)) /* do not require '. ' when */
|
|
|
|
{
|
|
|
|
addToBuffer(' ', _PL_rd); /* reading from a string */
|
|
|
|
addToBuffer('.', _PL_rd);
|
|
|
|
addToBuffer(' ', _PL_rd);
|
|
|
|
addToBuffer(EOS, _PL_rd);
|
|
|
|
return rb.base;
|
|
|
|
}
|
|
|
|
if (something_read) {
|
|
|
|
if (dotseen) /* term.<EOF> */
|
|
|
|
{
|
|
|
|
if (rb.here - rb.base == 1)
|
|
|
|
rawSyntaxError("end_of_clause");
|
|
|
|
ensure_space(' ');
|
|
|
|
addToBuffer(EOS, _PL_rd);
|
|
|
|
return rb.base;
|
|
|
|
}
|
|
|
|
rawSyntaxError("end_of_file");
|
|
|
|
}
|
|
|
|
if (Sfpasteof(rb.stream)) {
|
|
|
|
term_t stream;
|
|
|
|
|
|
|
|
LD->exception.processing = TRUE;
|
|
|
|
stream = PL_new_term_ref();
|
|
|
|
PL_unify_stream_or_alias(stream, rb.stream);
|
|
|
|
PL_error(NULL, 0, NULL, ERR_PERMISSION, ATOM_input,
|
|
|
|
ATOM_past_end_of_stream, stream);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
set_start_line;
|
|
|
|
strcpy((char *)rb.base, "end_of_file. ");
|
|
|
|
rb.here = rb.base + 14;
|
|
|
|
return rb.base;
|
|
|
|
case '/':
|
|
|
|
if (rb.stream->position) {
|
|
|
|
pbuf = *rb.stream->position;
|
|
|
|
pbuf.charno--;
|
|
|
|
pbuf.linepos--;
|
|
|
|
pos = &pbuf;
|
|
|
|
} else
|
|
|
|
pos = NULL;
|
|
|
|
|
|
|
|
c = getchr();
|
|
|
|
if (c == '*') {
|
|
|
|
int last;
|
|
|
|
int level = 1;
|
|
|
|
union {
|
|
|
|
tmp_buffer ctmpbuf;
|
|
|
|
buffer tmpbuf;
|
|
|
|
} u;
|
|
|
|
Buffer cbuf;
|
|
|
|
|
|
|
|
if (_PL_rd->comments) {
|
|
|
|
initBuffer(&u.ctmpbuf);
|
|
|
|
cbuf = &u.tmpbuf;
|
|
|
|
addUTF8Buffer(cbuf, '/');
|
|
|
|
addUTF8Buffer(cbuf, '*');
|
|
|
|
} else {
|
|
|
|
cbuf = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((last = getchr()) == EOF) {
|
|
|
|
if (cbuf)
|
|
|
|
discardBuffer(cbuf);
|
|
|
|
setErrorLocation(pos, _PL_rd);
|
|
|
|
rawSyntaxError("end_of_file_in_block_comment");
|
|
|
|
}
|
|
|
|
if (cbuf)
|
|
|
|
addUTF8Buffer(cbuf, last);
|
|
|
|
|
|
|
|
if (something_read) {
|
|
|
|
addToBuffer(' ', _PL_rd); /* positions */
|
|
|
|
addToBuffer(' ', _PL_rd);
|
|
|
|
addToBuffer(last == '\n' ? last : ' ', _PL_rd);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
c = getchr();
|
|
|
|
|
|
|
|
if (cbuf)
|
|
|
|
addUTF8Buffer(cbuf, c);
|
|
|
|
|
|
|
|
switch (c) {
|
|
|
|
case EOF:
|
|
|
|
if (cbuf)
|
|
|
|
discardBuffer(cbuf);
|
|
|
|
setErrorLocation(pos, _PL_rd);
|
|
|
|
rawSyntaxError("end_of_file_in_block_comment");
|
2015-06-18 01:47:23 +01:00
|
|
|
#ifndef __YAP_PROLOG__
|
2016-12-04 18:52:42 +00:00
|
|
|
/* YAP does not support comment levels in original scanner */
|
|
|
|
case '*':
|
|
|
|
if (last == '/')
|
|
|
|
level++;
|
|
|
|
break;
|
2015-06-18 01:47:23 +01:00
|
|
|
#endif
|
2016-12-04 18:52:42 +00:00
|
|
|
case '/':
|
|
|
|
if (last == '*' && (--level == 0 || _PL_rd->strictness)) {
|
|
|
|
if (cbuf) {
|
|
|
|
addUTF8Buffer(cbuf, EOS);
|
|
|
|
if (!add_comment(cbuf, pos, _PL_rd PASS_LD)) {
|
|
|
|
discardBuffer(cbuf);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
discardBuffer(cbuf);
|
|
|
|
}
|
|
|
|
c = ' ';
|
|
|
|
goto handle_c;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (something_read)
|
|
|
|
addToBuffer(c == '\n' ? c : ' ', _PL_rd);
|
|
|
|
last = c;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
set_start_line;
|
|
|
|
addToBuffer('/', _PL_rd);
|
|
|
|
if (isSymbolW(c)) {
|
|
|
|
while (c != EOF && isSymbolW(c) &&
|
|
|
|
!(c == '`' && _PL_rd->backquoted_string)) {
|
|
|
|
addToBuffer(c, _PL_rd);
|
|
|
|
c = getchr();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
dotseen = FALSE;
|
|
|
|
goto handle_c;
|
|
|
|
}
|
|
|
|
case '%':
|
|
|
|
if (something_read)
|
|
|
|
addToBuffer(' ', _PL_rd);
|
|
|
|
if (_PL_rd->comments) {
|
|
|
|
union {
|
|
|
|
tmp_buffer ctmpbuf;
|
|
|
|
buffer uctmpbuf;
|
|
|
|
} u;
|
|
|
|
Buffer cbuf;
|
|
|
|
|
|
|
|
if (rb.stream->position) {
|
|
|
|
pbuf = *rb.stream->position;
|
|
|
|
pbuf.charno--;
|
|
|
|
pbuf.linepos--;
|
|
|
|
pos = &pbuf;
|
|
|
|
} else
|
|
|
|
pos = NULL;
|
|
|
|
|
|
|
|
initBuffer(&u.ctmpbuf);
|
|
|
|
cbuf = (Buffer)&u.uctmpbuf;
|
|
|
|
addUTF8Buffer(cbuf, '%');
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
while ((c = getchr()) != EOF && c != '\n') {
|
|
|
|
addUTF8Buffer(cbuf, c);
|
|
|
|
if (something_read) /* record positions */
|
|
|
|
addToBuffer(' ', _PL_rd);
|
|
|
|
}
|
|
|
|
if (c == '\n') {
|
|
|
|
int c2 = Speekcode(rb.stream);
|
|
|
|
|
|
|
|
if (c2 == '%') {
|
|
|
|
if (something_read) {
|
|
|
|
addToBuffer(c, _PL_rd);
|
|
|
|
addToBuffer(' ', _PL_rd);
|
|
|
|
}
|
|
|
|
addUTF8Buffer(cbuf, c);
|
|
|
|
c = Sgetcode(rb.stream);
|
|
|
|
assert(c == c2);
|
|
|
|
addUTF8Buffer(cbuf, c);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
addUTF8Buffer(cbuf, EOS);
|
|
|
|
if (!add_comment(cbuf, pos, _PL_rd PASS_LD)) {
|
|
|
|
discardBuffer(cbuf);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
discardBuffer(cbuf);
|
|
|
|
} else {
|
|
|
|
while ((c = getchr()) != EOF && c != '\n') {
|
|
|
|
if (something_read) /* record positions */
|
|
|
|
addToBuffer(' ', _PL_rd);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
goto handle_c; /* is the newline */
|
|
|
|
case '\'':
|
|
|
|
if (rb.here > rb.base && isDigit(rb.here[-1])) {
|
|
|
|
cucharp bs = &rb.here[-1];
|
|
|
|
|
|
|
|
if (bs > rb.base && isDigit(bs[-1]))
|
|
|
|
bs--;
|
|
|
|
if (bs > rb.base && isSign(bs[-1]))
|
|
|
|
bs--;
|
|
|
|
|
|
|
|
if (bs == rb.base || !PlIdContW(bs[-1])) {
|
|
|
|
int base;
|
|
|
|
|
|
|
|
if (isSign(bs[0]))
|
|
|
|
bs++;
|
|
|
|
base = atoi((char *)bs);
|
|
|
|
|
|
|
|
if (base <= 36) {
|
|
|
|
if (base == 0) /* 0'<c> */
|
|
|
|
{
|
|
|
|
addToBuffer(c, _PL_rd);
|
|
|
|
{
|
|
|
|
if ((c = getchr()) != EOF) {
|
|
|
|
addToBuffer(c, _PL_rd);
|
|
|
|
if (c == '\\') /* 0'\<c> */
|
|
|
|
{
|
|
|
|
if ((c = getchr()) != EOF)
|
|
|
|
addToBuffer(c, _PL_rd);
|
|
|
|
} else if (c == '\'') /* 0'' */
|
|
|
|
{
|
|
|
|
if ((c = getchr()) != EOF) {
|
|
|
|
if (c == '\'')
|
|
|
|
addToBuffer(c, _PL_rd);
|
|
|
|
else
|
|
|
|
goto handle_c;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
rawSyntaxError("end_of_file");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
int c2 = Speekcode(rb.stream);
|
|
|
|
|
|
|
|
if (c2 != EOF) {
|
|
|
|
if (digitValue(base, c2) >= 0) {
|
|
|
|
addToBuffer(c, _PL_rd);
|
|
|
|
c = Sgetcode(rb.stream);
|
|
|
|
addToBuffer(c, _PL_rd);
|
|
|
|
dotseen = FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
goto sqatom;
|
|
|
|
}
|
|
|
|
rawSyntaxError("end_of_file");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sqatom:
|
|
|
|
set_start_line;
|
|
|
|
if (!raw_read_quoted(c, _PL_rd))
|
|
|
|
fail;
|
|
|
|
dotseen = FALSE;
|
|
|
|
break;
|
|
|
|
case '"':
|
|
|
|
set_start_line;
|
|
|
|
if (!raw_read_quoted(c, _PL_rd))
|
|
|
|
fail;
|
|
|
|
dotseen = FALSE;
|
|
|
|
break;
|
|
|
|
case '.':
|
|
|
|
addToBuffer(c, _PL_rd);
|
|
|
|
set_start_line;
|
|
|
|
dotseen++;
|
|
|
|
c = getchr();
|
|
|
|
if (isSymbolW(c)) {
|
|
|
|
while (c != EOF && isSymbolW(c) &&
|
|
|
|
!(c == '`' && _PL_rd->backquoted_string)) {
|
|
|
|
addToBuffer(c, _PL_rd);
|
|
|
|
c = getchr();
|
|
|
|
}
|
|
|
|
dotseen = FALSE;
|
|
|
|
}
|
|
|
|
goto handle_c;
|
|
|
|
case '`':
|
|
|
|
if (_PL_rd->backquoted_string) {
|
|
|
|
set_start_line;
|
|
|
|
if (!raw_read_quoted(c, _PL_rd))
|
|
|
|
fail;
|
|
|
|
dotseen = FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/*FALLTHROUGH*/
|
|
|
|
default:
|
|
|
|
if (c < 0xff) {
|
|
|
|
switch (_PL_char_types[c]) {
|
|
|
|
case SP:
|
|
|
|
case CT:
|
|
|
|
blank:
|
|
|
|
if (dotseen) {
|
|
|
|
if (rb.here - rb.base == 1)
|
|
|
|
rawSyntaxError("end_of_clause");
|
|
|
|
ensure_space(c);
|
|
|
|
addToBuffer(EOS, _PL_rd);
|
|
|
|
return rb.base;
|
|
|
|
}
|
|
|
|
do {
|
|
|
|
if (something_read) /* positions, \0 --> ' ' */
|
|
|
|
addToBuffer(c ? c : ' ', _PL_rd);
|
|
|
|
else
|
|
|
|
ensure_space(c);
|
|
|
|
c = getchr();
|
|
|
|
} while (c != EOF && PlBlankW(c));
|
|
|
|
goto handle_c;
|
|
|
|
case SY:
|
|
|
|
set_start_line;
|
|
|
|
do {
|
|
|
|
addToBuffer(c, _PL_rd);
|
|
|
|
c = getchr();
|
|
|
|
if (c == '`' && _PL_rd->backquoted_string)
|
|
|
|
break;
|
|
|
|
} while (c != EOF && c <= 0xff && isSymbol(c));
|
|
|
|
/* TBD: wide symbols? */
|
|
|
|
dotseen = FALSE;
|
|
|
|
goto handle_c;
|
|
|
|
case LC:
|
|
|
|
case UC:
|
|
|
|
set_start_line;
|
|
|
|
do {
|
|
|
|
addToBuffer(c, _PL_rd);
|
|
|
|
c = getchr();
|
|
|
|
} while (c != EOF && PlIdContW(c));
|
|
|
|
dotseen = FALSE;
|
|
|
|
goto handle_c;
|
|
|
|
default:
|
|
|
|
addToBuffer(c, _PL_rd);
|
|
|
|
dotseen = FALSE;
|
|
|
|
set_start_line;
|
|
|
|
}
|
|
|
|
} else /* > 255 */
|
|
|
|
{
|
|
|
|
if (PlIdStartW(c)) {
|
|
|
|
set_start_line;
|
|
|
|
do {
|
|
|
|
addToBuffer(c, _PL_rd);
|
|
|
|
c = getchr();
|
|
|
|
} while (c != EOF && PlIdContW(c));
|
|
|
|
dotseen = FALSE;
|
|
|
|
goto handle_c;
|
|
|
|
} else if (PlBlankW(c)) {
|
|
|
|
goto blank;
|
|
|
|
} else {
|
|
|
|
addToBuffer(c, _PL_rd);
|
|
|
|
dotseen = FALSE;
|
|
|
|
set_start_line;
|
|
|
|
}
|
|
|
|
}
|
2015-06-18 01:47:23 +01:00
|
|
|
}
|
2016-12-04 18:52:42 +00:00
|
|
|
}
|
2015-06-18 01:47:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
Raw reading returns a string in UTF-8 notation of the a Prolog term.
|
|
|
|
Comment inside the term is replaced by spaces or newline to ensure
|
|
|
|
proper reconstruction of source locations. Comment before the term is
|
|
|
|
skipped.
|
|
|
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
static unsigned char *raw_read(ReadData _PL_rd, unsigned char **endp ARG_LD) {
|
|
|
|
unsigned char *s;
|
2015-06-18 01:47:23 +01:00
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
if ((rb.stream->flags & SIO_ISATTY) && Sfileno(rb.stream) >= 0) {
|
|
|
|
ttybuf tab;
|
2015-06-18 01:47:23 +01:00
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
PushTty(rb.stream, &tab, TTY_SAVE); /* make sure tty is sane */
|
|
|
|
PopTty(rb.stream, &ttytab, FALSE);
|
|
|
|
s = raw_read2(_PL_rd PASS_LD);
|
|
|
|
PopTty(rb.stream, &tab, TRUE);
|
|
|
|
} else {
|
|
|
|
s = raw_read2(_PL_rd PASS_LD);
|
|
|
|
}
|
2015-06-18 01:47:23 +01:00
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
if (endp)
|
2015-06-18 01:47:23 +01:00
|
|
|
*endp = _PL_rd->_rb.here;
|
|
|
|
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
static void callCommentHook(term_t comments, term_t tpos, term_t term) {
|
|
|
|
GET_LD
|
|
|
|
fid_t fid;
|
2015-06-18 01:47:23 +01:00
|
|
|
term_t av;
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
if ((fid = PL_open_foreign_frame()) && (av = PL_new_term_refs(3))) {
|
|
|
|
qid_t qid;
|
2015-06-18 01:47:23 +01:00
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
PL_put_term(av + 0, comments);
|
|
|
|
PL_put_term(av + 1, tpos);
|
|
|
|
PL_put_term(av + 2, term);
|
2015-06-18 01:47:23 +01:00
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
if ((qid = PL_open_query(NULL, PL_Q_NODEBUG | PL_Q_CATCH_EXCEPTION,
|
|
|
|
(predicate_t)PredCommentHook, av))) {
|
|
|
|
term_t ex;
|
2015-06-18 01:47:23 +01:00
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
if (!PL_next_solution(qid) && (ex = PL_exception(qid)))
|
|
|
|
printMessage(ATOM_error, PL_TERM, ex);
|
2015-06-18 01:47:23 +01:00
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
PL_close_query(qid);
|
2015-06-18 01:47:23 +01:00
|
|
|
}
|
2016-12-04 18:52:42 +00:00
|
|
|
PL_discard_foreign_frame(fid);
|
|
|
|
}
|
2015-06-18 01:47:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/********************************
|
|
|
|
* PROLOG CONNECTION *
|
|
|
|
*********************************/
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
static unsigned char *backSkipUTF8(unsigned const char *start,
|
|
|
|
unsigned const char *end, int *chr) {
|
|
|
|
const unsigned char *s;
|
2015-06-18 01:47:23 +01:00
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
for (s = end - 1; s > start && (*s & 0x80); s--)
|
2015-06-18 01:47:23 +01:00
|
|
|
;
|
2016-12-04 18:52:42 +00:00
|
|
|
utf8_get_char((char *)s, chr);
|
2015-06-18 01:47:23 +01:00
|
|
|
|
|
|
|
return (unsigned char *)s;
|
|
|
|
}
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
static unsigned char *backSkipBlanks(const unsigned char *start,
|
|
|
|
const unsigned char *end) {
|
|
|
|
const unsigned char *s;
|
2015-06-18 01:47:23 +01:00
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
for (; end > start; end = s) {
|
|
|
|
unsigned char *e;
|
|
|
|
int chr;
|
2015-06-18 01:47:23 +01:00
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
for (s = end - 1; s > start && ISUTF8_CB(*s); s--)
|
|
|
|
;
|
|
|
|
e = (unsigned char *)utf8_get_char((char *)s, &chr);
|
|
|
|
assert(e == end);
|
|
|
|
if (!PlBlankW(chr))
|
|
|
|
return (unsigned char *)end;
|
|
|
|
}
|
2015-06-18 01:47:23 +01:00
|
|
|
|
|
|
|
return (unsigned char *)start;
|
|
|
|
}
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
static inline ucharp skipSpaces(cucharp in) {
|
|
|
|
int chr;
|
2015-06-18 01:47:23 +01:00
|
|
|
ucharp s;
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
for (; *in; in = s) {
|
|
|
|
s = utf8_get_uchar(in, &chr);
|
2015-06-18 01:47:23 +01:00
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
if (!PlBlankW(chr))
|
|
|
|
return (ucharp)in;
|
|
|
|
}
|
2015-06-18 01:47:23 +01:00
|
|
|
|
|
|
|
return (ucharp)in;
|
|
|
|
}
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
word pl_raw_read2(term_t from, term_t term) {
|
|
|
|
GET_LD
|
|
|
|
unsigned char *s, *e, *t2, *top;
|
2015-06-18 01:47:23 +01:00
|
|
|
read_data rd;
|
|
|
|
word rval;
|
|
|
|
IOSTREAM *in;
|
|
|
|
int chr;
|
|
|
|
PL_chars_t txt;
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
if (!getTextInputStream(from, &in))
|
2015-06-18 01:47:23 +01:00
|
|
|
fail;
|
|
|
|
|
|
|
|
init_read_data(&rd, in PASS_LD);
|
2016-12-04 18:52:42 +00:00
|
|
|
if (!(s = raw_read(&rd, &e PASS_LD))) {
|
|
|
|
rval = PL_raise_exception(rd.exception);
|
|
|
|
goto out;
|
|
|
|
}
|
2015-06-18 01:47:23 +01:00
|
|
|
|
|
|
|
/* strip the input from blanks */
|
2016-12-04 18:52:42 +00:00
|
|
|
top = backSkipBlanks(s, e - 1);
|
2015-06-18 01:47:23 +01:00
|
|
|
t2 = backSkipUTF8(s, top, &chr);
|
2016-12-04 18:52:42 +00:00
|
|
|
if (chr == '.')
|
2015-06-18 01:47:23 +01:00
|
|
|
top = backSkipBlanks(s, t2);
|
|
|
|
/* watch for "0' ." */
|
2016-12-04 18:52:42 +00:00
|
|
|
if (top < e && top - 2 >= s && top[-1] == '\'' && top[-2] == '0')
|
2015-06-18 01:47:23 +01:00
|
|
|
top++;
|
|
|
|
*top = EOS;
|
|
|
|
s = skipSpaces(s);
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
txt.text.t = (char *)s;
|
|
|
|
txt.length = top - s;
|
|
|
|
txt.storage = PL_CHARS_HEAP;
|
|
|
|
txt.encoding = ENC_UTF8;
|
2015-06-18 01:47:23 +01:00
|
|
|
txt.canonical = FALSE;
|
|
|
|
|
|
|
|
rval = PL_unify_text(term, 0, &txt, PL_ATOM);
|
|
|
|
LD->read_varnames = rd.varnames;
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
out:
|
2015-06-18 01:47:23 +01:00
|
|
|
free_read_data(&rd);
|
2016-12-04 18:52:42 +00:00
|
|
|
if (Sferror(in))
|
2015-06-18 01:47:23 +01:00
|
|
|
return streamStatus(in);
|
|
|
|
else
|
|
|
|
PL_release_stream(in);
|
|
|
|
|
|
|
|
return rval;
|
|
|
|
}
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
static int unify_read_term_position(term_t tpos ARG_LD) {
|
|
|
|
if (tpos && source_line_no > 0) {
|
|
|
|
return PL_unify_term(tpos, PL_FUNCTOR, FUNCTOR_stream_position4, PL_INT64,
|
|
|
|
source_char_no, PL_INT, source_line_no, PL_INT,
|
|
|
|
source_line_pos, PL_INT64, source_byte_no);
|
|
|
|
} else {
|
|
|
|
return TRUE;
|
|
|
|
}
|
2015-06-18 01:47:23 +01:00
|
|
|
}
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
static const opt_spec read_clause_options[] = {
|
|
|
|
{ATOM_variable_names, OPT_TERM},
|
|
|
|
{ATOM_term_position, OPT_TERM},
|
|
|
|
{ATOM_subterm_positions, OPT_TERM},
|
|
|
|
{ATOM_process_comment, OPT_BOOL},
|
|
|
|
{ATOM_comments, OPT_TERM},
|
|
|
|
{ATOM_syntax_errors, OPT_ATOM},
|
|
|
|
{NULL_ATOM, 0}};
|
2015-06-18 01:47:23 +01:00
|
|
|
|
|
|
|
/** read_clause(+Stream:stream, -Clause:clause, +Options:list)
|
|
|
|
|
|
|
|
Like read_term/3, but uses current compiler options.
|
|
|
|
|
|
|
|
Options:
|
|
|
|
* variable_names(-Names)
|
|
|
|
* process_comment(+Boolean)
|
|
|
|
* comments(-List)
|
|
|
|
* syntax_errors(+Atom)
|
|
|
|
* term_position(-Position)
|
|
|
|
* subterm_positions(-Layout)
|
|
|
|
*/
|
2016-12-04 18:52:42 +00:00
|
|
|
static int read_clause(IOSTREAM *s, term_t term, term_t options ARG_LD) {
|
2015-06-18 01:47:23 +01:00
|
|
|
read_data rd;
|
|
|
|
int rval;
|
|
|
|
fid_t fid;
|
|
|
|
term_t tpos = 0;
|
|
|
|
term_t comments = 0;
|
|
|
|
term_t opt_comments = 0;
|
|
|
|
int process_comment;
|
|
|
|
atom_t syntax_errors = ATOM_dec10;
|
|
|
|
|
|
|
|
{
|
|
|
|
OPCODE ophook = PredCommentHook->OpcodeOfPred;
|
|
|
|
if (ophook == UNDEF_OPCODE || ophook == FAIL_OPCODE)
|
|
|
|
process_comment = FALSE;
|
|
|
|
else
|
|
|
|
process_comment = TRUE;
|
|
|
|
}
|
2016-12-04 18:52:42 +00:00
|
|
|
if (!(fid = PL_open_foreign_frame()))
|
2015-06-18 01:47:23 +01:00
|
|
|
return FALSE;
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
retry:
|
2015-06-18 01:47:23 +01:00
|
|
|
init_read_data(&rd, s PASS_LD);
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
if (options &&
|
|
|
|
!scan_options(options, 0, ATOM_read_option, read_clause_options,
|
|
|
|
&rd.varnames, &tpos, &rd.subtpos, &process_comment,
|
|
|
|
&opt_comments, &syntax_errors)) {
|
|
|
|
PL_close_foreign_frame(fid);
|
|
|
|
return FALSE;
|
|
|
|
}
|
2015-06-18 01:47:23 +01:00
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
if (opt_comments) {
|
|
|
|
comments = PL_new_term_ref();
|
|
|
|
} else if (process_comment) {
|
|
|
|
if (!tpos)
|
|
|
|
tpos = PL_new_term_ref();
|
|
|
|
comments = PL_new_term_ref();
|
|
|
|
}
|
2015-06-18 01:47:23 +01:00
|
|
|
|
|
|
|
REGS_FROM_LD
|
2016-12-04 18:52:42 +00:00
|
|
|
rd.module = Yap_GetModuleEntry(LOCAL_SourceModule);
|
|
|
|
if (comments)
|
2015-06-18 01:47:23 +01:00
|
|
|
rd.comments = PL_copy_term_ref(comments);
|
|
|
|
rd.on_error = syntax_errors;
|
|
|
|
rd.singles = rd.styleCheck & SINGLETON_CHECK ? 1 : 0;
|
2016-12-04 18:52:42 +00:00
|
|
|
if ((rval = read_term(term, &rd PASS_LD)) &&
|
|
|
|
(!tpos || (rval = unify_read_term_position(tpos PASS_LD)))) {
|
|
|
|
PredEntry *ap;
|
|
|
|
LD->read_varnames = rd.varnames;
|
|
|
|
|
|
|
|
if (rd.singles) {
|
|
|
|
// warning, singletons([X=_A],f(X,Y,Z), pos).
|
|
|
|
printMessage(ATOM_warning, PL_FUNCTOR_CHARS, "singletons", 3, PL_TERM,
|
|
|
|
rd.singles, PL_TERM, term, PL_TERM, tpos);
|
|
|
|
}
|
|
|
|
ap = Yap_PredFromClause(Yap_GetFromSlot(term) PASS_REGS);
|
|
|
|
if (rd.styleCheck & (DISCONTIGUOUS_STYLE | MULTIPLE_CHECK) && ap != NULL) {
|
|
|
|
if (rd.styleCheck & (DISCONTIGUOUS_STYLE) &&
|
|
|
|
Yap_discontiguous(ap PASS_REGS)) {
|
|
|
|
printMessage(ATOM_warning, PL_FUNCTOR_CHARS, "discontiguous", 2,
|
|
|
|
PL_TERM, term, PL_TERM, tpos);
|
2015-06-18 01:47:23 +01:00
|
|
|
}
|
2016-12-04 18:52:42 +00:00
|
|
|
if (rd.styleCheck & (MULTIPLE_CHECK) && Yap_multiple(ap PASS_REGS)) {
|
|
|
|
printMessage(ATOM_warning, PL_FUNCTOR_CHARS, "multiple", 3, PL_TERM,
|
|
|
|
term, PL_TERM, tpos, PL_ATOM,
|
|
|
|
YAP_SWIAtomFromAtom(ap->src.OwnerFile));
|
2015-06-18 01:47:23 +01:00
|
|
|
}
|
|
|
|
}
|
2016-12-04 18:52:42 +00:00
|
|
|
if (rd.comments && (rval = PL_unify_nil(rd.comments))) {
|
|
|
|
if (opt_comments)
|
|
|
|
rval = PL_unify(opt_comments, comments);
|
|
|
|
else if (!PL_get_nil(comments))
|
|
|
|
callCommentHook(comments, tpos, term);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (rd.has_exception && reportReadError(&rd)) {
|
|
|
|
PL_rewind_foreign_frame(fid);
|
|
|
|
free_read_data(&rd);
|
|
|
|
goto retry;
|
|
|
|
}
|
|
|
|
}
|
2015-06-18 01:47:23 +01:00
|
|
|
free_read_data(&rd);
|
|
|
|
|
|
|
|
return rval;
|
|
|
|
}
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
static PRED_IMPL("read_clause", 3, read_clause, 0) {
|
|
|
|
PRED_LD
|
|
|
|
int rc;
|
2015-06-18 01:47:23 +01:00
|
|
|
IOSTREAM *s;
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
if (!getTextInputStream(A1, &s))
|
2015-06-18 01:47:23 +01:00
|
|
|
return FALSE;
|
|
|
|
rc = read_clause(s, A2, A3 PASS_LD);
|
2016-12-04 18:52:42 +00:00
|
|
|
if (Sferror(s))
|
2015-06-18 01:47:23 +01:00
|
|
|
return streamStatus(s);
|
|
|
|
else
|
|
|
|
PL_release_stream(s);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
word pl_raw_read(term_t term) { return pl_raw_read2(0, term); }
|
2015-06-18 01:47:23 +01:00
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
static const opt_spec read_term_options[] = {
|
|
|
|
{ATOM_variable_names, OPT_TERM},
|
|
|
|
{ATOM_variables, OPT_TERM},
|
|
|
|
{ATOM_singletons, OPT_TERM},
|
|
|
|
{ATOM_term_position, OPT_TERM},
|
2015-06-18 01:47:23 +01:00
|
|
|
// { ATOM_subterm_positions, OPT_TERM },
|
2016-12-04 18:52:42 +00:00
|
|
|
{ATOM_character_escapes, OPT_BOOL},
|
|
|
|
{ATOM_double_quotes, OPT_ATOM},
|
|
|
|
{ATOM_module, OPT_ATOM},
|
|
|
|
{ATOM_syntax_errors, OPT_ATOM},
|
|
|
|
{ATOM_backquoted_string, OPT_BOOL},
|
|
|
|
{ATOM_comments, OPT_TERM},
|
|
|
|
{ATOM_process_comment, OPT_BOOL},
|
2015-06-18 01:47:23 +01:00
|
|
|
#ifdef O_QUASIQUOTATIONS
|
2016-12-04 18:52:42 +00:00
|
|
|
{ATOM_quasi_quotations, OPT_TERM},
|
2015-06-18 01:47:23 +01:00
|
|
|
#endif
|
2016-12-04 18:52:42 +00:00
|
|
|
{ATOM_cycles, OPT_BOOL},
|
|
|
|
{NULL_ATOM, 0}};
|
2015-06-18 01:47:23 +01:00
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
static foreign_t read_term_from_stream(IOSTREAM *s, term_t term,
|
|
|
|
term_t options ARG_LD) {
|
|
|
|
term_t tpos = 0;
|
2015-06-18 01:47:23 +01:00
|
|
|
term_t comments = 0;
|
|
|
|
term_t opt_comments = 0;
|
|
|
|
int process_comment;
|
|
|
|
int rval;
|
|
|
|
atom_t w;
|
|
|
|
read_data rd;
|
|
|
|
int charescapes = -1;
|
|
|
|
atom_t dq = NULL_ATOM;
|
|
|
|
atom_t mname = NULL_ATOM;
|
|
|
|
fid_t fid = PL_open_foreign_frame();
|
|
|
|
|
|
|
|
if (!fid)
|
|
|
|
return FALSE;
|
2016-12-04 18:52:42 +00:00
|
|
|
retry:
|
2015-06-18 01:47:23 +01:00
|
|
|
init_read_data(&rd, s PASS_LD);
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
if (!scan_options(options, 0, ATOM_read_option, read_term_options,
|
|
|
|
&rd.varnames, &rd.variables, &rd.singles, &tpos,
|
|
|
|
// &rd.subtpos,
|
|
|
|
&charescapes, &dq, &mname, &rd.on_error,
|
|
|
|
&rd.backquoted_string, &opt_comments, &process_comment,
|
2015-06-18 01:47:23 +01:00
|
|
|
#ifdef O_QUASIQUOTATIONS
|
2016-12-04 18:52:42 +00:00
|
|
|
&rd.quasi_quotations,
|
2015-06-18 01:47:23 +01:00
|
|
|
#endif
|
2016-12-04 18:52:42 +00:00
|
|
|
&rd.cycles)) {
|
2015-06-18 01:47:23 +01:00
|
|
|
PL_discard_foreign_frame(fid);
|
|
|
|
free_read_data(&rd);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// yap specific, do not call process comment if undefined
|
|
|
|
if (process_comment) {
|
|
|
|
OPCODE ophook = PredCommentHook->OpcodeOfPred;
|
|
|
|
if (ophook == UNDEF_OPCODE || ophook == FAIL_OPCODE)
|
|
|
|
process_comment = FALSE;
|
|
|
|
}
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
if (opt_comments) {
|
|
|
|
comments = PL_new_term_ref();
|
|
|
|
} else if (process_comment) {
|
|
|
|
if (!tpos)
|
|
|
|
tpos = PL_new_term_ref();
|
|
|
|
comments = PL_new_term_ref();
|
|
|
|
}
|
2015-06-18 01:47:23 +01:00
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
if (mname) {
|
|
|
|
rd.module = lookupModule(mname);
|
|
|
|
rd.flags = rd.module->flags;
|
|
|
|
}
|
2015-06-18 01:47:23 +01:00
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
if (charescapes != -1) {
|
|
|
|
if (charescapes)
|
|
|
|
set(&rd, M_CHARESCAPE);
|
|
|
|
else
|
|
|
|
clear(&rd, M_CHARESCAPE);
|
|
|
|
}
|
|
|
|
if (dq) {
|
|
|
|
if (!setDoubleQuotes(dq, &rd.flags))
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
if (rd.singles && PL_get_atom(rd.singles, &w) && w == ATOM_warning)
|
2015-06-18 01:47:23 +01:00
|
|
|
rd.singles = 1;
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
if (comments)
|
2015-06-18 01:47:23 +01:00
|
|
|
rd.comments = PL_copy_term_ref(comments);
|
|
|
|
|
|
|
|
rval = read_term(term, &rd PASS_LD);
|
2016-12-04 18:52:42 +00:00
|
|
|
if (Sferror(s)) {
|
2015-06-18 01:47:23 +01:00
|
|
|
free_read_data(&rd);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
LD->read_varnames = rd.varnames;
|
|
|
|
#ifdef O_QUASIQUOTATIONS
|
2016-12-04 18:52:42 +00:00
|
|
|
if (rval)
|
2015-06-18 01:47:23 +01:00
|
|
|
rval = parse_quasi_quotations(&rd PASS_LD);
|
|
|
|
#endif
|
2016-12-04 18:52:42 +00:00
|
|
|
if (rval) {
|
|
|
|
if (tpos)
|
|
|
|
rval = unify_read_term_position(tpos PASS_LD);
|
|
|
|
if (rval) {
|
|
|
|
if (opt_comments)
|
|
|
|
rval = PL_unify(opt_comments, comments);
|
|
|
|
else if (comments && !PL_get_nil(comments))
|
|
|
|
callCommentHook(comments, tpos, term);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (rd.has_exception && reportReadError(&rd)) {
|
|
|
|
PL_rewind_foreign_frame(fid);
|
|
|
|
free_read_data(&rd);
|
|
|
|
goto retry;
|
|
|
|
}
|
2015-06-18 01:47:23 +01:00
|
|
|
}
|
|
|
|
free_read_data(&rd);
|
|
|
|
|
|
|
|
return rval;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @pred read_term(+ _Stream_,- _T_,+ _Options_) is iso
|
|
|
|
|
|
|
|
Reads term _T_ from stream _Stream_ with execution controlled by the
|
|
|
|
same options as read_term/2.
|
|
|
|
|
|
|
|
|
|
|
|
*/
|
2016-12-04 18:52:42 +00:00
|
|
|
static PRED_IMPL("read_term", 3, read_term, PL_FA_ISO) {
|
|
|
|
PRED_LD
|
|
|
|
IOSTREAM *s;
|
2015-06-18 01:47:23 +01:00
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
if (getTextInputStream(A1, &s)) {
|
|
|
|
if (read_term_from_stream(s, A2, A3 PASS_LD))
|
|
|
|
return PL_release_stream(s);
|
|
|
|
if (Sferror(s))
|
|
|
|
return streamStatus(s);
|
|
|
|
PL_release_stream(s);
|
|
|
|
return FALSE;
|
|
|
|
}
|
2015-06-18 01:47:23 +01:00
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** read_term(-Term, +Options) is det.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/** @pred read_term(- _T_,+ _Options_) is iso
|
|
|
|
|
|
|
|
|
|
|
|
Reads term _T_ from the current input stream with execution
|
|
|
|
controlled by the following options:
|
|
|
|
|
|
|
|
+ comments(- _Comments_)
|
|
|
|
|
|
|
|
Unify _Comments_ with a list of string terms including comments before
|
|
|
|
and within the term.
|
|
|
|
|
|
|
|
+ module( + _Module_)
|
|
|
|
|
|
|
|
Read term using _Module_ as source module.
|
|
|
|
|
|
|
|
+ quasi_quotations(-List)
|
|
|
|
|
|
|
|
Unify _List_ with the quasi-quotations present in the term.
|
|
|
|
|
|
|
|
+ term_position(- _Position_)
|
|
|
|
|
|
|
|
Unify _Position_ with a term describing the position of the stream
|
|
|
|
at the start of parse. Use stream_position_data/3 to obtain extra
|
|
|
|
information.
|
|
|
|
|
|
|
|
+ singletons(- _Names_)
|
|
|
|
|
|
|
|
Unify _Names_ with a list of the form _Name=Var_, where
|
|
|
|
_Name_ is the name of a non-anonymous singleton variable in the
|
|
|
|
original term, and `Var` is the variable's representation in
|
|
|
|
YAP.
|
|
|
|
The variables occur in left-to-right traversal order.
|
|
|
|
|
|
|
|
+ syntax_errors(+ _Val_)
|
|
|
|
|
|
|
|
Control action to be taken after syntax errors. See yap_flag/2
|
|
|
|
for detailed information.
|
|
|
|
|
|
|
|
+ variables(- _Names_)
|
|
|
|
|
|
|
|
Unify _Names_ with a list of the form _Name=Var_, where _Name_ is
|
|
|
|
the name of a non-anonymous variable in the original term, and _Var_
|
|
|
|
is the variable's representation in YAP.
|
|
|
|
The variables occur in left-to-right traversal order.
|
|
|
|
|
|
|
|
|
|
|
|
*/
|
2016-12-04 18:52:42 +00:00
|
|
|
static PRED_IMPL("read_term", 2, read_term, PL_FA_ISO) {
|
|
|
|
PRED_LD
|
|
|
|
IOSTREAM *s;
|
2015-06-18 01:47:23 +01:00
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
if (getTextInputStream(0, &s)) {
|
|
|
|
if (read_term_from_stream(s, A1, A2 PASS_LD))
|
|
|
|
return PL_release_stream(s);
|
|
|
|
if (Sferror(s))
|
|
|
|
return streamStatus(s);
|
|
|
|
PL_release_stream(s);
|
|
|
|
return FALSE;
|
|
|
|
}
|
2015-06-18 01:47:23 +01:00
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*******************************
|
|
|
|
* TERM <->ATOM *
|
|
|
|
*******************************/
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
static int atom_to_term(term_t atom, term_t term, term_t bindings) {
|
|
|
|
GET_LD
|
|
|
|
PL_chars_t txt;
|
|
|
|
|
|
|
|
if (!bindings && PL_is_variable(atom)) /* term_to_atom(+, -) */
|
|
|
|
{
|
|
|
|
char buf[1024];
|
|
|
|
size_t bufsize = sizeof(buf);
|
|
|
|
int rval;
|
|
|
|
char *s = buf;
|
|
|
|
IOSTREAM *stream;
|
2015-06-18 01:47:23 +01:00
|
|
|
PL_chars_t txt;
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
stream = Sopenmem(&s, &bufsize, "w");
|
|
|
|
stream->encoding = ENC_UTF8;
|
|
|
|
PL_write_term(stream, term, 1200, PL_WRT_QUOTED);
|
|
|
|
Sflush(stream);
|
2015-06-18 01:47:23 +01:00
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
txt.text.t = s;
|
|
|
|
txt.length = bufsize;
|
|
|
|
txt.storage = PL_CHARS_HEAP;
|
|
|
|
txt.encoding = ENC_UTF8;
|
|
|
|
txt.canonical = FALSE;
|
|
|
|
rval = PL_unify_text(atom, 0, &txt, PL_ATOM);
|
2015-06-18 01:47:23 +01:00
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
Sclose(stream);
|
|
|
|
if (s != buf)
|
|
|
|
Sfree(s);
|
2015-06-18 01:47:23 +01:00
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
return rval;
|
|
|
|
}
|
2015-06-18 01:47:23 +01:00
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
if (PL_get_text(atom, &txt, CVT_ALL | CVT_EXCEPTION)) {
|
|
|
|
GET_LD
|
|
|
|
read_data rd;
|
|
|
|
int rval;
|
|
|
|
IOSTREAM *stream;
|
|
|
|
source_location oldsrc = LD->read_source;
|
2015-06-18 01:47:23 +01:00
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
stream = Sopen_text(&txt, "r");
|
|
|
|
|
|
|
|
init_read_data(&rd, stream PASS_LD);
|
|
|
|
if (bindings && (PL_is_variable(bindings) || PL_is_list(bindings)))
|
|
|
|
rd.varnames = bindings;
|
|
|
|
else if (bindings)
|
|
|
|
return PL_error(NULL, 0, NULL, ERR_TYPE, ATOM_list, bindings);
|
|
|
|
|
|
|
|
if (!(rval = read_term(term, &rd PASS_LD)) && rd.has_exception)
|
|
|
|
rval = PL_raise_exception(rd.exception);
|
|
|
|
free_read_data(&rd);
|
|
|
|
Sclose(stream);
|
|
|
|
LD->read_source = oldsrc;
|
|
|
|
|
|
|
|
// getchar();
|
|
|
|
return rval;
|
|
|
|
}
|
2015-06-18 01:47:23 +01:00
|
|
|
|
|
|
|
fail;
|
|
|
|
}
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
Term Yap_CharsToTerm(const char *s, size_t *lenp, Term *bindingsp) {
|
|
|
|
GET_LD;
|
2015-06-18 01:47:23 +01:00
|
|
|
read_data rd;
|
|
|
|
int rval;
|
|
|
|
IOSTREAM *stream;
|
|
|
|
source_location oldsrc = LD->read_source;
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
stream = Sopen_string(0, (char *)s, strlen(s), "r");
|
2015-06-18 01:47:23 +01:00
|
|
|
|
|
|
|
init_read_data(&rd, stream PASS_LD);
|
|
|
|
rd.varnames = bindings;
|
|
|
|
term_t tt = Yap_NewSlots(1);
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
if (!(rval = read_term(tt, &rd PASS_LD)) && rd.has_exception) {
|
2015-06-18 01:47:23 +01:00
|
|
|
rval = PL_raise_exception(rd.exception);
|
|
|
|
return 0L;
|
|
|
|
}
|
|
|
|
free_read_data(&rd);
|
|
|
|
Sclose(stream);
|
|
|
|
LD->read_source = oldsrc;
|
|
|
|
|
|
|
|
// getchar();
|
2016-12-04 18:52:42 +00:00
|
|
|
return Yap_GetFromSlot(tt);
|
2015-06-18 01:47:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/** @pred atom_to_term(+ _Atom_, - _Term_, - _Bindings_)
|
|
|
|
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
Use _Atom_ as input to read_term/2 using the option `variable_names` and
|
|
|
|
return the read term in _Term_ and the variable bindings in _Bindings_.
|
|
|
|
_Bindings_ is a list of `Name = Var` couples, thus providing access to the
|
|
|
|
actual variable names. See also read_term/2. If Atom has no valid syntax, a
|
|
|
|
syntax_error exception is raised.
|
2015-06-18 01:47:23 +01:00
|
|
|
|
|
|
|
|
|
|
|
*/
|
2016-12-04 18:52:42 +00:00
|
|
|
static PRED_IMPL("atom_to_term", 3, atom_to_term, 0) {
|
|
|
|
return atom_to_term(A1, A2, A3);
|
2015-06-18 01:47:23 +01:00
|
|
|
}
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
static PRED_IMPL("term_to_atom", 2, term_to_atom, 0) {
|
|
|
|
return atom_to_term(A2, A1, 0);
|
2015-06-18 01:47:23 +01:00
|
|
|
}
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
static PRED_IMPL("$context_variables", 1, context_variables, 0) {
|
|
|
|
CACHE_REGS
|
|
|
|
if (LOCAL_VarNames == (CELL)0)
|
|
|
|
return Yap_unify(TermNil, ARG1);
|
|
|
|
return Yap_unify(LOCAL_VarNames, ARG1);
|
2015-06-18 01:47:23 +01:00
|
|
|
}
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
static PRED_IMPL("$set_source", 2, set_source, 0) {
|
2015-06-18 01:47:23 +01:00
|
|
|
GET_LD
|
2016-12-04 18:52:42 +00:00
|
|
|
atom_t at;
|
2015-06-18 01:47:23 +01:00
|
|
|
term_t a = PL_new_term_ref();
|
|
|
|
|
|
|
|
if (!PL_get_atom(A1, &at))
|
|
|
|
return FALSE;
|
|
|
|
source_file_name = at;
|
|
|
|
if (!PL_get_arg(1, A2, a) || !PL_get_int64(a, &source_char_no) ||
|
|
|
|
!PL_get_arg(2, A2, a) || !PL_get_long(a, &source_line_no) ||
|
|
|
|
!PL_get_arg(3, A2, a) || !PL_get_long(a, &source_line_pos) ||
|
2016-12-04 18:52:42 +00:00
|
|
|
!PL_get_arg(4, A2, a) || !PL_get_int64(a, &source_byte_no)) {
|
2015-06-18 01:47:23 +01:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
int PL_chars_to_term(const char *s, term_t t) {
|
|
|
|
GET_LD
|
|
|
|
read_data rd;
|
2015-06-18 01:47:23 +01:00
|
|
|
int rval;
|
|
|
|
IOSTREAM *stream = Sopen_string(NULL, (char *)s, -1, "r");
|
|
|
|
source_location oldsrc = LD->read_source;
|
|
|
|
|
|
|
|
init_read_data(&rd, stream PASS_LD);
|
|
|
|
PL_put_variable(t);
|
2016-12-04 18:52:42 +00:00
|
|
|
if (!(rval = read_term(t, &rd PASS_LD)) && rd.has_exception)
|
2015-06-18 01:47:23 +01:00
|
|
|
PL_put_term(t, rd.exception);
|
|
|
|
LOCAL_VarNames = rd.varnames;
|
|
|
|
free_read_data(&rd);
|
|
|
|
Sclose(stream);
|
|
|
|
LD->read_source = oldsrc;
|
|
|
|
|
|
|
|
return rval;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*******************************
|
|
|
|
* PUBLISH PREDICATES *
|
|
|
|
*******************************/
|
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
BeginPredDefs(read) PRED_DEF("read_term", 3, read_term, PL_FA_ISO)
|
|
|
|
PRED_DEF("read_term", 2, read_term, PL_FA_ISO)
|
|
|
|
PRED_DEF("read_clause", 3, read_clause, 0)
|
|
|
|
PRED_DEF("atom_to_term", 3, atom_to_term, 0)
|
|
|
|
PRED_DEF("term_to_atom", 2, term_to_atom, 0)
|
|
|
|
PRED_DEF("$context_variables", 1, context_variables, 0)
|
|
|
|
PRED_DEF("$set_source", 2, set_source, 0)
|
2015-06-18 01:47:23 +01:00
|
|
|
#ifdef O_QUASIQUOTATIONS
|
2016-12-04 18:52:42 +00:00
|
|
|
PRED_DEF("$qq_open", 2, qq_open, 0)
|
2015-06-18 01:47:23 +01:00
|
|
|
#endif
|
2016-12-04 18:52:42 +00:00
|
|
|
EndPredDefs
|
2015-06-18 01:47:23 +01:00
|
|
|
|
2016-12-04 18:52:42 +00:00
|
|
|
//! @}
|