From 3f2dfe186bd3a203692a8832f3f29d13aa22498c Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Mon, 7 Nov 2016 20:50:20 -0800 Subject: Support #: reading for uninterned symbols. * parser.l (BTKEY, NTKEY): Renamed to BTKWUN and NTKWUN ("keyword and uninterned") respectively. Include an optional match for the # character. (BTOK, NTOK): Refer to BTKEY and NTKEY respectively * parser.y (sym_helper): Implement uninterned symbols by detecting when the package name string is "#" and handling specially. * txr.1: Documented package prefixes and uninterned symbols. --- parser.l | 8 +++---- parser.y | 16 ++++++++----- txr.1 | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 10 deletions(-) diff --git a/parser.l b/parser.l index 28e0d1d2..cff641ae 100644 --- a/parser.l +++ b/parser.l @@ -206,14 +206,14 @@ BT0 {BSCHR}({BSCHR}|{EXTRA})* BT1 @{BT0}+ BT2 ({BSCHR}|{EXTRA})+ BTREG ({BT0}|{BT1})?:{BT2}?|({BT0}|{BT1})(:{BT2})? -BTKEY @?:{BT2}? -BTOK {BTREG}|{BTKEY} +BTKWUN @?#?:{BT2}? +BTOK {BTREG}|{BTKWUN} NT0 {NSCHR}({NSCHR}|{EXTRA})* NT1 @{NT0}+ NT2 ({NSCHR}|{EXTRA})+ NTREG ({NT0}|{NT1})?:{NT2}?|({NT0}|{NT1})(:{NT2})? -NTKEY @?:{NT2}? -NTOK {NTREG}|{NTKEY} +NTKWUN @?#?:{NT2}? +NTOK {NTREG}|{NTKWUN} WS [\t ]* REQWS [\t ]+ NL (\n|\r|\r\n) diff --git a/parser.y b/parser.y index 48d36840..6a43f664 100644 --- a/parser.y +++ b/parser.y @@ -1249,7 +1249,7 @@ static val sym_helper(parser_t *parser, wchar_t *lexeme, val meta_allowed) int leading_at = *lexeme == L'@'; wchar_t *tokfree = lexeme; wchar_t *colon = wcschr(lexeme, L':'); - val sym_name = nil, pkg_name = nil, package = nil, sym; + val sym_name = nil, pkg_name = nil, package = user_package, sym; if (leading_at) { if (!meta_allowed) { @@ -1270,13 +1270,17 @@ static val sym_helper(parser_t *parser, wchar_t *lexeme, val meta_allowed) free(tokfree); } else if (colon != 0) { pkg_name = string(lexeme); - package = find_package(pkg_name); sym_name = string(colon + 1); scrub_scanner(parser->scanner, SYMTOK, tokfree); free(tokfree); - if (!package) { - yyerrorf(scnr, lit("~a:~a: package ~a not found"), pkg_name, sym_name, pkg_name, nao); - return nil; + if (equal(pkg_name, lit("#"))) { + package = nil; + } else { + package = find_package(pkg_name); + if (!package) { + yyerrorf(scnr, lit("~a:~a: package ~a not found"), pkg_name, sym_name, pkg_name, nao); + return nil; + } } } else { sym_name = string(lexeme); @@ -1284,7 +1288,7 @@ static val sym_helper(parser_t *parser, wchar_t *lexeme, val meta_allowed) free(tokfree); } - sym = intern(sym_name, package); + sym = package ? intern(sym_name, package) : make_sym(sym_name); return leading_at ? rl(list(var_s, sym, nao), num(parser->lineno)) : sym; } diff --git a/txr.1 b/txr.1 index 6dd6285e..91127f58 100644 --- a/txr.1 +++ b/txr.1 @@ -10056,6 +10056,84 @@ variable syntax. Within \*(TL, regular expressions are written with a leading .codn # . +.NP* Package Prefixes + +If a symbol name contains a colon, the +.I lident +characters, if any, before that colon constitute the package prefix. +It is erroneous to read a symbol whose package doesn't exist. +If the package exist, the symbol is interned in that package. + +If the package name is an empty identifier, the package is understood to be the +.code keyword +package and the symbol is a self-evaluating keyword symbol. + +For example +.code foo:bar +is the +.code bar +symbol in the +.code foo +package. + +The syntax +.code :test +denotes the symbol +.code test +in the +.code keyword +package, the same as +.codn keyword:test . + +The syntax +.code @foo:bar +denotes the meta prefix +.code @ +being applied to the +.code foo:bar +symbol, not to a symbol in the +.code @foo +package. + +The syntax +.code #:bar +denotes an uninterned symbol named +.codn bar , +described in the next section. + +.TP* "Dialect note:" +In ANSI Common Lisp, the +.code foo:bar +syntax does not create the symbol +.code bar +in the +.code foo +package; the symbol must exist or else the syntax is erroneous. +In \*(TL, only the package has to exist; the symbol will be interned +in that package. + +.NP* Uninterned Symbols + +Uninterned symbols are written with the +.code #: +prefix, followed by zero or more +.I lident +characters. +When an uninterned symbol is read, a new, unique symbol is constructed, +with the specified name. Even if two uninterned symbols have the same name, +they are different objects. The +.code make-sym +and +.code gensym +functions produce uninterned symbols. + +"Uninterned" means "not entered into a package". Interning refers to a +process which combines package lookup with symbol creation, which ensures +that multiple occurrences of a symbol name in written syntax are all converted +to the same object: the first occurrence creates the symbol and associates it +with its name in a package. Subsequent occurrences do not create a new symbol, +but retrieve the existing one. + .NP* Consing Dot Unlike other major Lisp dialects, \*(TL allows a consing dot with no forms -- cgit v1.2.3