better string semantics and an reworked and verified namespace handling almost finished'

parent 2446243d
......@@ -1900,12 +1900,8 @@ The known deviations are
@subsection function/arity
In prolog the module + function/arity combination identifies the actual predicate. Scheme does not have such a distinction and in order to keep a tight interface between scheme functions and prolog functions a function is identified with its module + name only. This can create problems for certain prolog programs.
@subsection 'nm' is not nessesary atoms.
The logic is currently,
@code{'nm'(x,...)}, here @code{nm} is translated to an atom.
@code{f(...,'nm',....)}, here @code{nm} is translated to a scheme string. and likewise for list arguments. There is a distinction here because characters in prolog is also atoms and then the namespacing mechanism currently used, makes prolog code a headache to use if we translated everything to atoms directly (an 'a' in one module would not be an 'a' in another module). In stead it is possible to call with a string in which case the current module is used for lookup. And unification of a string 'a' and a atom a is always true whatever the module is involved. (two atoms does not translate well). This is again a tweak to support modules sanely and it is expected to always work. To note, it is possible to namespace a @code{'nm'} item by forcing a namespace on it. The story is a bit complex, the main thing to remember is to explicitly sigil a @code{'nm'} with the namespace operator if one want and atom and in case one suspect a string is gotten as an argument, it is possible to make an operator through a unification with a namespaced variable.
@subsection @code{"string"} is not atoms.
The logic is currently, that to specifiy an atom with general characters we use as in is prolog @code{'atom-+-'}. But some functions returns a string and they will not be translated to atoms unless there is a module cast or at the final application of an string as an goal, where it will be translated to the current module. The reason for this complexity is to have non module objects or to allow for creation of module objects through construction of strings. We choose a composable method of ideoms that control the namespaces of prolog objects (se the modules chapter) and strings. Strings can be specified directly via @code{"string"}. Also a unification of an atom with a string will unify on the name of the string. This means that character handling in guile prolog becomes a smooth experience if one learn the ideoms.
@subsection closed files
Closed files cannot be gotten through a general seek of streams.
......@@ -1918,7 +1914,11 @@ there is some effort to standardize modules but its unclear how to choose, we th
@node modules
@section Module system and prolog
We support @code{@@} and @code{@@@@} operators to resolve atoms module meaning. The syntax is @code{name@@module} which names files in a special module directory in the guile namespace @code{(language prolog modules)}. @code{@@} is refering to symbols in the public interface and @code{@@@@} refers to symbols in the whole private module namespace. We also support a guile-log reference through e.g. @code{name@@(logic,guile-log,iso-prolog)}. atoms can either be namespaced in or are strings, that will be namespaces as soon it touches a construct with a namespace in, e.g. @code{X@@module = Y} will make sure that if @code{X} gets bounded, it will if @code{Y} is a string, try to produced a namespaced item. Managing modules will either be done by the scheme wrapper or by inlined scheme expression.
We support @code{@@} and @code{@@@@} operators to resolve atoms module meaning. The syntax is @code{name@@module} which names files in a special module directory in the guile namespace @code{(language prolog modules)}. @code{@@} is refering to symbols in the public interface and @code{@@@@} refers to symbols in the whole private module namespace. We also support a guile-log reference through e.g. @code{name@@(logic,guile-log,iso-prolog)}. As a short cut to specify the module that issues a compilation of a prolog part we have the @code{atom@@} and @code{atom@@@@}, in principle this forces the module to the lexical module the code belongs to which is handy when we translate strings to atoms via the namespacing mechanism. compound objects can be specified belonging to a namespace which forces the objects inside the lexical atoms and strings to be namespaced to that namespace e.g. @code{[a,'a-b',"axa"]@@mod_a} will translate all atoms inside the list to objects inside the public interface of module @code{mod_a}. The general rule is that lexical translation of objects outside the current module will need to be defined, the current module though will be created if it does not exist. For dynamic creation of atoms, we allow the objects to be created under some constraints.
prolog objects can be namespaced and contain namespace wrappers, which are transparent in the unification, but for logical variables that are namespaced if the matching object is a string, the variable will be located in the namespace if it exists or it will be constructed under some constraints.
We do not define a full prolog api for module handling, but refere to the usual scheme module system in guile and suggest that the user use the scheme stubs that can be inserted into guile prolog.
@subsection Example
@verbatim
......@@ -1928,7 +1928,7 @@ We support @code{@@} and @code{@@@@} operators to resolve atoms module meaning.
@end verbatim
@subsection module aware unification,
Strings will only in proven goals be translated to an atom in the module defining the string, else a string representation will remain. Still the evaluator understands that a string term shouled be represented by a procedure representing the predicat. The algorithm is to search in the current module runtime. But one may whish to explicitly translate strings to a correct module located predicate. The mechansim to achieve this is through the unification. The unification with respect to modules can also be used to verify that data adheres to a certain module convention. The rules for this is essentially
Strings will only in proven goals be translated to an atom in the module defining the string, else a string representation will remain. Still the evaluator understands that a string term shouled be represented by a procedure representing the predicate. The algorithm is to search in the current module runtime. But one may whish to explicitly translate strings to a correct module located predicate. The mechansim to achieve this is through the unification. The unification with respect to modules can also be used to verify that data adheres to a certain module convention. The rules for this is essentially
1) A variable in a module will if the other one is a string bind to a term/predicate found/defined in that module.
......@@ -1940,19 +1940,30 @@ Strings will only in proven goals be translated to an atom in the module definin
subsubsection Example
@verbatim
X@@module_a = 'alpha',
[X,Y,Z@@module_b]@@module_a = ['alpha','beta','gamma']. % this may fail
X@@module_a = ``alpha'',
[X,Y,Z@@module_b]@@module_a = [``alpha'',''beta'',''gamma'']. % this may fail
@end verbatim
@subsection Controling module unification
Sigilling a variable with @code{X@@module_a} meas that we will validate the curent data of the variable. It is desireable e.g. in sandboxing, that the module environment cannot change. To control this we can use the api
Sigilling a variable with @code{X@@module_a} means that we will validate the curent data of the variable. It is desireable e.g. in sandboxing, that the module environment cannot change. To control this we can use the api
@code{prolog fail_on_namespace_switch/0, ok_on_namespece_switch/0}, with the obvious semantic.
@code{prolog error_on_namespace_switch/0, fail_on_namespace_switch/0, ok_on_namespece_switch/0}, with the obvious semantic.
Also to get an handle to restrict and guard this information one may use,
@code{get_namespace_switch_handle(Handle)}, then if handle can be used by the dynamic features framework and make sure that we will never success although we move from state to state friously and a value can be guaranteed to be fixed inside a code segment.
It's possible to specify a whitelist to handle if one allow changes of namespaces in a unification that include namespacing e.g.
@code{prolog set_no_whitelist/0}
@code{prolog namespace_white_list_set([[Local, RW, dir, ...] ...])}
@code{prolog namespace_white_list_ref(ListOfList)}
@code{prolog namespace_white_list_handle(Handle)}
Here @code{Local = true/0 or false/0} specifies that the directory is allows referencing local defines or not, and @code{RW = true/0 or false/0} specifies if the directory allow writing or not. If @code{dir} ends with @code{"*"} then any directories after that is included in the spec.
@node scheme
@section hooking in scheme expressions,
......
......@@ -27,6 +27,7 @@
x)))
#:use-module (logic guile-log prolog names)
#:use-module (logic guile-log prolog namespace)
#:use-module (ice-9 match)
#:use-module (ice-9 pretty-print)
#:replace (catch throw)
......@@ -363,8 +364,14 @@ ceiling(x) (ceiling x)
floor(x) (floor x)
|#
(define (project@ s x)
(if (namespace? x)
(project@ s (namespace-val (gp-lookup x s)))
x))
(<define> (func=.. x y)
(<let> ((x (<lookup> x))
(<let> ((xx (<lookup> x))
(x (project@ S x))
(y (<scm> y)))
(cond
((or (number? x) (null? x))
......@@ -390,10 +397,10 @@ floor(x) (floor x)
(vector `(,divide ,f
,(length (<scm> u))))))))
(else
(<=> l y))))))
(<=> xx ,(vector y)))))))
(y
(<cut>
(<=> l y))))))
(<=> xx ,(vector y)))))))
(_ (type_error 'compound x)))))
......@@ -409,20 +416,11 @@ floor(x) (floor x)
(<cut>
(<let> ((f (<lookup> f)))
(cond
((procedure? f)
(<=> x ,(vector (cons f l))))
((string? f)
(<let> ((g (module-ref (current-module) (string->symbol f))))
(if (procedure? g)
(<=> x ,(vector (cons g l)))
(existence_error
procedure
(vector `(,divide ,f
,(length (<scm> l))))))))
((or (procedure? f) (string? f))
(<=> xx ,(vector (cons f l))))
((and (number? f) (null? (<lookup> l)))
(<=> x f))
(<=> xx f))
((number? f)
(type_error atom f))
......
......@@ -451,6 +451,20 @@
((a . b)
(format #f "~a| ~a" (lp a) (lp b)))))
(define (gen@ ll a)
(match ll
(('language 'prolog 'modules x)
(format #f "~a@@~a"
(procedure-name a) x))
(("language" "prolog" "modules" x)
(format #f "~a@@~a"
(procedure-name a) x))
((_ . _)
(format #f "~a@@(~a~{, ~a~})"
(procedure-name a) (car ll) (cdr ll)))
(_
(format #f "~a" (procedure-name a)))))
(define (lp x)
(umatch (#:mode - #:status s) (x)
(#((f a . l))
......@@ -481,14 +495,12 @@
(lp a) (map lp (gp->scm l s)))
(let ((ll (map (lambda (x) (format #f "'~a'" x))
(get-attached-module f ns?))))
(if (pair? ll)
(format #f "~a@@(~a~{, ~a~})(~a~{, ~a~})"
(procedure-name f) (car ll) (cdr ll)
(lp a) (map lp (gp->scm l s)))
(format #f "~a(~a~{, ~a~})"
(procedure-name f)
(lp a) (map lp (gp->scm l s)))))))))))
(format #f "~a(~a~{, ~a~})"
(gen@ ll f)
(lp a) (map lp (gp->scm l s))))))))))
(#((f))
(let ((f (gp-lookup f s)))
(cond
((string? f)
(format #f "'~a'" f))
......@@ -510,11 +522,8 @@
(else
(let ((ll (map (lambda (x) (format #f "'~a'" x))
(get-attached-module f ns?))))
(if (pair? ll)
(format #f "~a@@(~a~{, ~a~})"
(procedure-name f) (car ll) (cdr ll))
(format #f "~a" (procedure-name f)))))))
(format #f "~a@@(~a~{, ~a~})"
(gen@ ll f) (car ll) (cdr ll)))))))
((a . l)
(format #f "[~a]" (list-it x)))
......@@ -546,18 +555,7 @@
(symbol->string x)
x))
(get-attached-module a ns?))))
(match ll
(('language 'prolog 'modules x)
(format #f "~a@@~a"
(procedure-name a) x))
(("language" "prolog" "modules" x)
(format #f "~a@@~a"
(procedure-name a) x))
((_ . _)
(format #f "~a@@(~a~{, ~a~})"
(procedure-name a) (car ll) (cdr ll)))
(_
(format #f "~a" (procedure-name a))))))
(gen@ ll a)))
((struct? a)
(cond
......
......@@ -70,7 +70,8 @@ Two things will happen
(define fail-when-new-namespace? (make-fluid #f))
(define (comp-fail? ns1 local1? ns2 local2? binary?)
(let ((fail (fluid-ref fail-when-new-namespace?)))
(let ((fail (fluid-ref fail-when-new-namespace?))
(wl (fluid-ref white-list-namespaces)))
(if (and (equal? ns1 ns2) (or local1? (not local2?)))
#f
(if binary?
......@@ -78,9 +79,9 @@ Two things will happen
(if fail
(if (eq? fail #t)
#t
(let lp-wl ((l fail))
(let lp-wl ((l wl))
(match l
(((local? . dir) . l)
(((local? rw? . dir) . l)
(if (or local? (not local2?))
(let lp ((dir dir) (ns ns2))
(match dir
......@@ -327,6 +328,7 @@ Two things will happen
(let lp ((s s) (y (gp-lookup y s)) (x (gp-lookup x s)) (y-lex? y-lex?)
(ns ns) (lx? lx?))
(pp 'imp y x)
(if (or (gp-var? x s) (pair? x))
(let ((f (lambda ()
(cond
((vector? y)
......@@ -334,7 +336,17 @@ Two things will happen
(ly (vector->list y))
(lx (map (lambda (x) (gp-var! s)) ly)))
(if y-lex?
(lp s ly lx y-lex? ns lx?)
(let lp2 ((s s) (llx lx) (lly ly))
(if (pair? llx)
(lp2 (lp s
(gp-lookup (car lly) s)
(gp-lookup (car llx) s)
y-lex? ns lx?)
(cdr llx)
(cdr lly))
(gp-set! x (list->vector
(map (lambda (x) (gp-lookup x s)) lx))
s)))
(let ((s (validate y ns lx? s)))
(if s
(gp-set! x y s)
......@@ -411,7 +423,8 @@ Two things will happen
y-lex? ns lx?)
s)))))
(_ (f))))))
(_ (f))))
s)))
(setup-namespace <namespace-type> ns-unify)
......@@ -269,7 +269,9 @@
(<p-cc> (mk-list (mk-string "language")
(mk-string "prolog")
(mk-string "modules")
(mk-string (list-ref cx 1)))))))))
(mk-string (list-ref cx 1)))))
(<p-cc> (module-name (current-module)))))))
(define @tag
(let ((@ (f-tag "@"))
(@@ (f-tag "@@")))
......@@ -283,6 +285,7 @@
(.. (cx) (@tag-body c))
(.. (c) (ws c))
(<p-cc> `(@@ ,cx)))
(<and>
(.. (c) (@ c))
(.. (cx) (@tag-body c))
......@@ -292,9 +295,7 @@
(define string
(p-freeze 'string
(let ((@ (f-tag "@"))
(@@ (f-tag "@@"))
(l (f-tag "("))
(let ((l (f-tag "("))
(r (f-tag ")")))
(<p-lambda> (c)
(.. (c) (ws c))
......@@ -308,7 +309,8 @@
(<p-cc> (if u
`(#:atom ,(string->symbol c*)
,(car u) ,(cadr u) ,n ,m)
`(#:string ,c* ,n ,m))))))
`(#:atom ,(string->symbol c*) #f #f
,n ,m))))))
mk-id))
(define dstring
......@@ -322,9 +324,11 @@
(.. (c) (ws c))
(.. (u) (@tag c))
(<p-cc>
(let ((r `(#:dstring ,c* ,n ,m)))
(let ((r `(#:string ,c* ,n ,m)))
(if u
`(#:@ ,r ,@u)
`(#:atom
,(string->symbol c*)
,(car u) ,(cadr u) ,n ,m)
r)))))
mk-id))
......@@ -397,7 +401,7 @@
(<p-lambda> (c)
(.. (c0) (ws c))
(<let> ((n N) (m M))
(.. (c1) (atom c0 ))
(xx (c1) (<or> (.. (atom c0)) (.. (string c0))))
(.. (c2) (l c1))
(.. (c3) ((f-or expr ws) c2))
(.. (c4) (r c3))
......@@ -546,7 +550,7 @@
(<p-lambda> (c)
(.. (c0) (ws c))
(<let> ((n N) (m M))
(.. (c1) (string c0))
(.. (c1) (dstring c0))
(.. (c2) (l c1))
(.. (c3) ((f-or expr ws) c2))
(.. (c4) (r c3))
......
......@@ -39,10 +39,17 @@
(x (list (f x)))))
(define (get-binding x stx opify)
(define (get-binding mod local? x stx opify)
(define (wrap x)
(if mod
(if local?
`(@@ ,mod ,x)
`(@ ,mod ,x))
x))
(match x
((#:atom f #f #f n m)
(datum->syntax stx (opify f)))
(datum->syntax stx (wrap (opify f))))
((#:atom f amp (#:string a . _) n m)
#`(#,(datum->syntax stx amp) (#,(datum->syntax stx (string->symbol a)))
......@@ -81,10 +88,14 @@
(set-procedure-property! f 'module (module-name mod)))
(define* (get-attached-module f #:optional (not-pretty? #t))
(define (st l) (map symbol->string l))
(define mod (procedure-property f 'module))
(if (and (not not-pretty?)
(symbol? (procedure-name f))
(module-defined?
(current-module) (procedure-name f)))
(if mod
(eq? (resolve-module mod) (current-module))
(module-defined?
(current-module) (procedure-name f))))
'()
(let ((x (procedure-property f 'module)))
(if x
......
......@@ -13,19 +13,21 @@
(define syms (make-fluid vlist-null))
(define (clear-syms)
(fluid-set! syms vlist-null))
(define (add-sym sym)
(define (add-sym mod local? sym)
(when (not mod)
(match sym
((#:atom f #f #f n m)
(fluid-set! syms (vhash-consq f #t (fluid-ref syms))))
((#:atom f amp (and atom ((or #:string #:atom) a . _)) n m)
(add-sym `(#:atom ,f ,amp (,atom) ,n ,m)))
(add-sym mod local? `(#:atom ,f ,amp (,atom) ,n ,m)))
((#:atom f amp l n m)
(let ((l (map
(lambda (x)
(match x
((#:atom a _ _ n m) a)
((#:string a . _) (string->symbol a))
(_ (error "wrong @ argument in ~a" (get-refstr n m)))))
(_
(error "wrong @ argument in ~a" (get-refstr n m)))))
(get... l))))
(let ((mod (resolve-module l)))
(cond
......@@ -39,7 +41,8 @@
(fluid-set! syms (vhash-consq f #t (fluid-ref syms)))))))
(s (if (symbol? s)
(fluid-set! syms (vhash-consq s #t (fluid-ref syms)))))))
(fluid-set! syms (vhash-consq s
#t (fluid-ref syms))))))))
(define (rem-sym sym)
(fluid-set! syms (vhash-delq sym (fluid-ref syms))))
......
This diff is collapsed.
......@@ -1622,7 +1622,13 @@ static SCM gp_unify(SCM *id1, SCM *id2, int raw, int gp_plus_unify, SCM *l, stru
else
{
SCM s = gp_make_s(ci,l);
s = scm_call_3(namespace_fkn,s,scm2,scm1);
SCM bang = SCM_BOOL_T;
if(!gp_plus_unify)
{
bang = SCM_BOOL_F;
}
s = scm_call_4(namespace_fkn,s,scm2,scm1,bang);
if(scm_is_false(s))
return (SCM) 0;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment