Skip to content

Commit 3021500

Browse files
committed
Add: quasiquote
1 parent 02be20b commit 3021500

File tree

10 files changed

+120
-8
lines changed

10 files changed

+120
-8
lines changed

src/ambeval.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ static void init(obj execution_environment)
6767
" (cond ((self-evaluating? exp) "
6868
" (analyze-self-evaluating exp))"
6969
" ((quoted? exp) (analyze-quoted exp))"
70+
" ((quasiquote? exp) (analyze (quasi->combination exp)))"
7071
" ((variable? exp) (analyze-variable exp))"
7172
" ((assignment? exp) (analyze-assignment exp))"
7273
" ((definition? exp) (analyze-definition exp))"

src/aneval.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,16 @@ static obj is_quoted_p(obj args)
263263
return is_quoted(car(args)) ? true_o : false_o;
264264
}
265265

266+
static obj is_quasiquote_p(obj args)
267+
{
268+
return is_quasiquote(car(args)) ? true_o : false_o;
269+
}
270+
271+
static obj quasi_to_combination_p(obj args)
272+
{
273+
return quasi_to_combination(car(args));
274+
}
275+
266276
static obj rest_exps_p(obj args)
267277
{
268278
return rest_exps(car(args));
@@ -403,6 +413,10 @@ void add_primprocs(obj env)
403413
of_function(procedure_parameters_p), env);
404414
define_variable(of_identifier("quoted?"), of_function(is_quoted_p),
405415
env);
416+
define_variable(of_identifier("quasiquote?"),
417+
of_function(is_quasiquote_p), env);
418+
define_variable(of_identifier("quasi->combination"),
419+
of_function(quasi_to_combination_p), env);
406420
define_variable(of_identifier("rest-exps"), of_function(rest_exps_p),
407421
env);
408422
define_variable(of_identifier("reverse"), of_function(reverse_p), env);
@@ -454,6 +468,7 @@ static void init(obj execution_environment)
454468
" (cond ((self-evaluating? exp) "
455469
" (analyze-self-evaluating exp))"
456470
" ((quoted? exp) (analyze-quoted exp))"
471+
" ((quasiquote? exp) (analyze (quasi->combination exp)))"
457472
" ((variable? exp) (analyze-variable exp))"
458473
" ((assignment? exp) (analyze-assignment exp))"
459474
" ((definition? exp) (analyze-definition exp))"

src/eceval.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,8 @@ obj eceval(obj expression, obj _environment)
268268
goto ev_variable;
269269
if (is_quoted(expr))
270270
goto ev_quoted;
271+
if (is_quasiquote(expr))
272+
goto ev_quasiquoted;
271273
if (is_assignment(expr))
272274
goto ev_assignment;
273275
if (is_definition(expr))
@@ -316,6 +318,9 @@ obj eceval(obj expression, obj _environment)
316318
ev_quoted:
317319
val = text_of_quotation(expr);
318320
goto go_cont;
321+
ev_quasiquoted:
322+
expr = quasi_to_combination(expr);
323+
goto eval_dispatch;
319324
ev_lambda:
320325
unev = lambda_parameters(expr);
321326
expr = lambda_body(expr);

src/lexer.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,14 @@ static enum token_type scan(struct inport *in)
8686
sb_addc(sb, '\'');
8787
return TKN_QUOTE;
8888
}
89+
if (c == '`') {
90+
sb_addc(sb, '`');
91+
return TKN_QUASIQUOTE;
92+
}
93+
if (c == ',') {
94+
sb_addc(sb, ',');
95+
return TKN_UNQUOTE;
96+
}
8997
if (is_peculiar_identifier(c)) {
9098
return peculiar(c, in);
9199
}

src/lexer.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ enum token_type {
1414
TKN_NUMBER, // 5
1515
TKN_STRING, // 6
1616
TKN_DOT, // 7
17-
TKN_QUOTE // 8
17+
TKN_QUOTE, // 8
18+
TKN_QUASIQUOTE, // 9
19+
TKN_UNQUOTE // 10
1820
};
1921

2022
struct location {

src/mceval.c

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,7 +560,57 @@ obj cons_stream_to_cons(obj exp)
560560
delay_to_lambda(list2(delay, caddr(exp)))));
561561
}
562562

563+
// new - amb
564+
563565
bool is_amb(obj exp)
564566
{
565567
return is_tagged_list(exp, amb);
566568
}
569+
570+
// new - quasiquoted
571+
572+
static bool is_unquote(obj exp)
573+
{
574+
return is_tagged_list(exp, unquote);
575+
}
576+
577+
static obj quasi_list(obj lst)
578+
{
579+
obj qlst = emptylst;
580+
581+
if (is_quasiquote(lst)) {
582+
return error_syntax(AREA,
583+
"Nested '`' (quasiquote) is not supported");
584+
}
585+
586+
for (lst = reverse(lst); is_pair(lst); lst = cdr(lst)) {
587+
obj item = car(lst);
588+
if (is_unquote(item)) {
589+
item = cadr(item);
590+
} else if (is_pair(item)) {
591+
item = quasi_list(item);
592+
} else {
593+
item = list2(quote, item);
594+
}
595+
qlst = cons(item, qlst);
596+
}
597+
return cons(of_identifier("list"), qlst);
598+
}
599+
600+
static obj quasi_dat(obj dat)
601+
{
602+
if (is_pair(dat)) {
603+
return quasi_list(dat);
604+
}
605+
return list2(quote, dat);
606+
}
607+
608+
bool is_quasiquote(obj exp)
609+
{
610+
return is_tagged_list(exp, quasiquote);
611+
}
612+
613+
obj quasi_to_combination(obj exp)
614+
{
615+
return quasi_dat(cadr(exp));
616+
}

src/mceval.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,7 @@ obj cons_stream_to_cons(obj exp);
6767

6868
bool is_amb(obj exp);
6969

70+
bool is_quasiquote(obj exp);
71+
obj quasi_to_combination(obj exp);
72+
7073
#endif

src/obj.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,9 +257,11 @@ const obj letstar = SYMBOL("let*");
257257
const obj memo_proc = SYMBOL("memo-proc");
258258
SYMBOL_VAR(lambda)
259259
const obj or_s = SYMBOL("or");
260+
SYMBOL_VAR(quasiquote)
260261
SYMBOL_VAR(quote)
261262
const obj set = SYMBOL("set!");
262263
const obj time_s = SYMBOL("time");
264+
SYMBOL_VAR(unquote)
263265

264266
// TAGS
265267
SYMBOL_VAR(procedure)

src/obj.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,9 +139,11 @@ extern const obj letstar;
139139
extern const obj lambda;
140140
extern const obj memo_proc;
141141
extern const obj or_s;
142+
extern const obj quasiquote;
142143
extern const obj quote;
143144
extern const obj set;
144145
extern const obj time_s;
146+
extern const obj unquote;
145147

146148
// EVAL TAGS
147149
extern const obj procedure;

src/parser.c

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@ obj read(void)
2121
return readp(dfltin());
2222
}
2323

24-
obj read_p(obj args){
25-
if(is_err(args = chkarity("read", 0, args)))
24+
obj read_p(obj args)
25+
{
26+
if (is_err(args = chkarity("read", 0, args)))
2627
return args;
2728
return read();
2829
}
@@ -74,7 +75,7 @@ static obj string(struct token *tkn)
7475
return of_string(str);
7576
}
7677

77-
static obj quote_(struct inport *port)
78+
static obj mark_to_list(struct inport *port, obj keyword, char *msg)
7879
{
7980
obj dat = readp(port);
8081
if (is_err(dat))
@@ -86,14 +87,33 @@ static obj quote_(struct inport *port)
8687
case TYPE_PAIRPTR:
8788
case TYPE_STRING:
8889
case TYPE_SYMBOL:
89-
return list2(quote, dat);
90+
return list2(keyword, dat);
9091
default:
91-
return error_parser(
92-
AREA, "Expected a datum after quote ', but got \"%s\"",
93-
errstr(dat));
92+
return error_parser(AREA, msg, errstr(dat));
9493
}
9594
}
9695

96+
static obj quote_(struct inport *port)
97+
{
98+
return mark_to_list(
99+
port, quote,
100+
"Expected a datum after \"'\" (quote), but got \"%s\"");
101+
}
102+
103+
static obj quasiquote_(struct inport *port)
104+
{
105+
return mark_to_list(
106+
port, quasiquote,
107+
"Expected a datum after '`' (quasiquote), but got \"%s\"");
108+
}
109+
110+
static obj unquote_(struct inport *port)
111+
{
112+
return mark_to_list(
113+
port, unquote,
114+
"Expected a datum after ',' (unquote), but got \"%s\"");
115+
}
116+
97117
static obj parse_list(obj, struct inport *);
98118
static obj parse(struct token *tkn, struct inport *port)
99119
{
@@ -110,6 +130,10 @@ static obj parse(struct token *tkn, struct inport *port)
110130
return string(tkn);
111131
case TKN_QUOTE:
112132
return quote_(port);
133+
case TKN_QUASIQUOTE:
134+
return quasiquote_(port);
135+
case TKN_UNQUOTE:
136+
return unquote_(port);
113137
case TKN_EOF:
114138
return check_eof();
115139
default:

0 commit comments

Comments
 (0)