summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2016-11-07 20:50:20 -0800
committerKaz Kylheku <kaz@kylheku.com>2016-11-07 20:50:20 -0800
commita2ea64e158ad9be884482747b45a90e27579f9f1 (patch)
treeaa4640188bcd4e4d9320f1eb9302452c3892599d
parent4af3611c835e9b6acb979987568f46ba86ef52e7 (diff)
downloadtxr-a2ea64e158ad9be884482747b45a90e27579f9f1.tar.gz
txr-a2ea64e158ad9be884482747b45a90e27579f9f1.tar.bz2
txr-a2ea64e158ad9be884482747b45a90e27579f9f1.zip
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.
-rw-r--r--parser.l8
-rw-r--r--parser.y16
-rw-r--r--txr.178
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