Escape in strings
This commit is contained in:
parent
55dd616416
commit
4c7acd92f0
4 changed files with 45 additions and 15 deletions
|
@ -655,7 +655,18 @@ struct Object *func_display(
|
||||||
printf("%li", object->number.i64);
|
printf("%li", object->number.i64);
|
||||||
break;
|
break;
|
||||||
case TYPE_STRING:
|
case TYPE_STRING:
|
||||||
printf("\"%s\"", object->s);
|
putchar('"');
|
||||||
|
for (char *str = object->s; *str; ++str) {
|
||||||
|
const char chr = *str;
|
||||||
|
if (chr == '\\') {
|
||||||
|
printf("\\\\");
|
||||||
|
} else if (chr == '\"') {
|
||||||
|
printf("\\\"");
|
||||||
|
} else {
|
||||||
|
putchar(chr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
putchar('"');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
10
src/lexer.c
10
src/lexer.c
|
@ -354,6 +354,8 @@ void Lexer_lex(const Lexer self, const char chr)
|
||||||
if (chr == '"') {
|
if (chr == '"') {
|
||||||
token_finish(self);
|
token_finish(self);
|
||||||
token_start(self, STATE_STRING_END);
|
token_start(self, STATE_STRING_END);
|
||||||
|
} else if (chr == '\\') {
|
||||||
|
self->state = STATE_STRING_ESCAPE;
|
||||||
} else {
|
} else {
|
||||||
token_putc(self, chr);
|
token_putc(self, chr);
|
||||||
}
|
}
|
||||||
|
@ -389,5 +391,13 @@ void Lexer_lex(const Lexer self, const char chr)
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case STATE_STRING_ESCAPE:
|
||||||
|
if (chr == '\\' || chr == '"') {
|
||||||
|
token_putc(self, chr);
|
||||||
|
self->state = STATE_STRING_INSIDE;
|
||||||
|
} else {
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ enum Lexer_State {
|
||||||
STATE_STRING_START,
|
STATE_STRING_START,
|
||||||
STATE_STRING_INSIDE,
|
STATE_STRING_INSIDE,
|
||||||
STATE_STRING_END,
|
STATE_STRING_END,
|
||||||
|
STATE_STRING_ESCAPE,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct Lexer {
|
typedef struct Lexer {
|
||||||
|
|
|
@ -20,22 +20,30 @@
|
||||||
(assert-equal
|
(assert-equal
|
||||||
(arcana/tokenize "#false")
|
(arcana/tokenize "#false")
|
||||||
(list (cons 'TOKEN_TAG "false")))
|
(list (cons 'TOKEN_TAG "false")))
|
||||||
;(assert-equal
|
(assert-equal
|
||||||
; (arcana/tokenize "\"\"")
|
(arcana/tokenize "\"\"")
|
||||||
; (list (cons 'TOKEN_STRING "\"\"")))
|
(list (cons 'TOKEN_STRING "")))
|
||||||
;(assert-equal
|
(assert-equal
|
||||||
; (arcana/tokenize "\"qwe\"")
|
(arcana/tokenize "\"qwe\"")
|
||||||
; (list (cons 'TOKEN_STRING "\"qwe\"")))
|
(list (cons 'TOKEN_STRING "qwe")))
|
||||||
|
(assert-equal
|
||||||
|
(arcana/tokenize "(displayln \"qwe\")")
|
||||||
|
(list
|
||||||
|
(cons 'TOKEN_ROUND_OPEN "(")
|
||||||
|
(cons 'TOKEN_IDENT "displayln")
|
||||||
|
(cons 'TOKEN_STRING "qwe")
|
||||||
|
(cons 'TOKEN_ROUND_CLOSE ")")))
|
||||||
|
|
||||||
(assert-equal
|
(assert-equal
|
||||||
(arcana/tokenize "(displayln (list 1))")
|
(arcana/tokenize "(displayln (list 1))")
|
||||||
(list
|
(list
|
||||||
(cons 'TOKEN_ROUND_OPEN "(")
|
(cons 'TOKEN_ROUND_OPEN "(")
|
||||||
(cons 'TOKEN_IDENT "displayln")
|
(cons 'TOKEN_IDENT "displayln")
|
||||||
(cons 'TOKEN_ROUND_OPEN "(")
|
(cons 'TOKEN_ROUND_OPEN "(")
|
||||||
(cons 'TOKEN_IDENT "list")
|
(cons 'TOKEN_IDENT "list")
|
||||||
(cons 'TOKEN_NUM "1")
|
(cons 'TOKEN_NUM "1")
|
||||||
(cons 'TOKEN_ROUND_CLOSE ")")
|
(cons 'TOKEN_ROUND_CLOSE ")")
|
||||||
(cons 'TOKEN_ROUND_CLOSE ")")))
|
(cons 'TOKEN_ROUND_CLOSE ")")))
|
||||||
|
|
||||||
;;; arcana/typeof ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;; arcana/typeof ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
(assert-equal 'null (arcana/typeof '()))
|
(assert-equal 'null (arcana/typeof '()))
|
||||||
|
|
Loading…
Reference in a new issue