Better stringing.
This commit is contained in:
parent
d825ca3fe2
commit
9d2effe206
|
@ -10,7 +10,7 @@
|
||||||
)))
|
)))
|
||||||
|
|
||||||
(def pop (fn ()
|
(def pop (fn ()
|
||||||
"Remove the top of the stack"
|
"Remove and print the top of the stack"
|
||||||
(if (> (len stack) 0) (
|
(if (> (len stack) 0) (
|
||||||
(def top (at 0 stack))
|
(def top (at 0 stack))
|
||||||
(set stack (rest stack))
|
(set stack (rest stack))
|
||||||
|
@ -18,6 +18,13 @@
|
||||||
) (prnl "pop: STACK EMPTY"))
|
) (prnl "pop: STACK EMPTY"))
|
||||||
))
|
))
|
||||||
|
|
||||||
|
(def drop (fn ()
|
||||||
|
"Remove the top of the stack"
|
||||||
|
(if (> (len stack) 0) (
|
||||||
|
(set stack (rest stack))
|
||||||
|
) (prnl "pop: STACK EMPTY"))
|
||||||
|
))
|
||||||
|
|
||||||
(def twop (fn (op)
|
(def twop (fn (op)
|
||||||
"Apply the given operation to the top two stack elements" (
|
"Apply the given operation to the top two stack elements" (
|
||||||
(if (< (len stack) 2) (prnl "stack too small!") (
|
(if (< (len stack) 2) (prnl "stack too small!") (
|
||||||
|
@ -92,6 +99,7 @@
|
||||||
(h-insert operations name op)
|
(h-insert operations name op)
|
||||||
)))
|
)))
|
||||||
(add-op "cls" '(sys "clear"))
|
(add-op "cls" '(sys "clear"))
|
||||||
|
(add-op "drop" '(drop))
|
||||||
(add-op "over" '(over))
|
(add-op "over" '(over))
|
||||||
(add-op "rot" '(rot))
|
(add-op "rot" '(rot))
|
||||||
(add-op "dup" '(dup))
|
(add-op "dup" '(dup))
|
||||||
|
|
14
src/object.c
14
src/object.c
|
@ -739,22 +739,20 @@ inline Object nullTerminated(const char* string)
|
||||||
inline Object stringFromSlice(const char* string, int len)
|
inline Object stringFromSlice(const char* string, int len)
|
||||||
{
|
{
|
||||||
#ifdef STANDALONE
|
#ifdef STANDALONE
|
||||||
|
//eprintf("ay: %s\n", string);
|
||||||
Object o = withLen(len, TYPE_STRING);
|
Object o = withLen(len, TYPE_STRING);
|
||||||
int c = 0;
|
int c = 0;
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
if (string[i] == '\\') {
|
if (string[i] == '\\') {
|
||||||
switch (string[i + 1]) {
|
i++;
|
||||||
case '"':
|
switch (string[i]) {
|
||||||
o.string[c] = '"';
|
case 'n':
|
||||||
break;
|
o.string[c] = '\n';
|
||||||
case '\\':
|
|
||||||
o.string[c] = '\\';
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
o.string[c] = string[i + 1];
|
o.string[c] = string[i];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
i++;
|
|
||||||
} else {
|
} else {
|
||||||
o.string[c] = string[i];
|
o.string[c] = string[i];
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ pass() {
|
||||||
|
|
||||||
fail() {
|
fail() {
|
||||||
echo -n "[1;31mX"
|
echo -n "[1;31mX"
|
||||||
FAIL_OUTPUT="$FAIL_OUTPUT [1;31m$1 FAILED\n When running [0;34m\"$2\"[0m"
|
FAIL_OUTPUT="$FAIL_OUTPUT [1;31m$1 FAILED\n When running [0;34m$2[0m"
|
||||||
((FAILS++))
|
((FAILS++))
|
||||||
((TOTAL_FAILS++))
|
((TOTAL_FAILS++))
|
||||||
}
|
}
|
||||||
|
@ -115,6 +115,9 @@ check "String Inequality" '(= "Beans" "Bean" )' "F"
|
||||||
check "Null Inequality" '(= "Beans" "" )' "F"
|
check "Null Inequality" '(= "Beans" "" )' "F"
|
||||||
|
|
||||||
title "Complex Strings"
|
title "Complex Strings"
|
||||||
|
check "Escaping Quotes" '"\"Hello\""' '"Hello"'
|
||||||
|
check "Escaping Backslash" '"\\Hello\\"' '\Hello\'
|
||||||
|
check "Escaping Many" '"\\\"\\\\\\Hello\\\"\\\\\\"' '\"\\\Hello\"\\\'
|
||||||
check "Triple Quoting" '"""Hello"""' 'Hello'
|
check "Triple Quoting" '"""Hello"""' 'Hello'
|
||||||
check "Triple Quoting With Quotes" '"""My name is "yoink"."""' 'My name is "yoink".'
|
check "Triple Quoting With Quotes" '"""My name is "yoink"."""' 'My name is "yoink".'
|
||||||
|
|
||||||
|
|
107
src/tokens.c
107
src/tokens.c
|
@ -43,6 +43,11 @@ void buildErrFromInput(struct Error* err, enum errorCode code, int i, const char
|
||||||
strncpy(err->context, &input[start], ERR_LEN);
|
strncpy(err->context, &input[start], ERR_LEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void collectSymbol(const char* input, int* i, int* length);
|
||||||
|
|
||||||
|
void processString(const char* input, struct Error* err, struct Slice* slices, int slice, int* i, int* lineNumber,
|
||||||
|
int* length);
|
||||||
|
|
||||||
struct Slice* nf_tokenize(const char* input, struct Error* err)
|
struct Slice* nf_tokenize(const char* input, struct Error* err)
|
||||||
{
|
{
|
||||||
if (!input) {
|
if (!input) {
|
||||||
|
@ -94,40 +99,14 @@ struct Slice* nf_tokenize(const char* input, struct Error* err)
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
} else if (input[i] == '"') {
|
} else if (input[i] == '"') {
|
||||||
if (input[i + 1] == '"' && input[i + 2] == '"') {
|
processString(input, err, slices, slice, &i, &lineNumber, &length);
|
||||||
// Triple-quoted block
|
} else {
|
||||||
i += 2;
|
collectSymbol(input, &i, &length);
|
||||||
slices[slice].text += 2;
|
|
||||||
for (;;) {
|
|
||||||
i++;
|
|
||||||
if (input[i] == '"' && input[i + 1] == '"' && input[i + 2] == '"') {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
if (input[i] == '\n') {
|
|
||||||
lineNumber++;
|
if (err->context != NULL) {
|
||||||
}
|
|
||||||
length++;
|
|
||||||
if (input[i] == '\0' || input[i + 1] == '\0' || input[i + 2] == '\0') {
|
|
||||||
buildErrFromInput(err, UNEXPECTED_EOF, i, input);
|
|
||||||
//free(slices);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Simple string
|
|
||||||
while ((input[++i] != '"' || input[i - 1] == '\\') && input[i] != '\0') {
|
|
||||||
if (input[i] == '\n') {
|
|
||||||
lineNumber++;
|
|
||||||
}
|
|
||||||
length++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
} else {
|
|
||||||
while (!isWhitespace(input[++i]) && !isSingle(input[i]) && input[i] != '"' && input[i] != '\0') {
|
|
||||||
length++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
slices[slice].length = length;
|
slices[slice].length = length;
|
||||||
slice++;
|
slice++;
|
||||||
|
@ -147,3 +126,69 @@ struct Slice* nf_tokenize(const char* input, struct Error* err)
|
||||||
|
|
||||||
return allocated;
|
return allocated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void singleQuotedString(const char* input, int* i, int* lineNumber, int* length);
|
||||||
|
|
||||||
|
void tripleQuotedString(const char* input, struct Error* err, struct Slice* slice, int* i, int* lineNumber,
|
||||||
|
int* length);
|
||||||
|
|
||||||
|
void processString(const char* input, struct Error* err, struct Slice* slices, int slice, int* i, int* lineNumber,
|
||||||
|
int* length)
|
||||||
|
{
|
||||||
|
if (input[(*i) + 1] == '"' && input[(*i) + 2] == '"') {
|
||||||
|
tripleQuotedString(input, err, &slices[slice], i, lineNumber, length);
|
||||||
|
} else {
|
||||||
|
singleQuotedString(input, i, lineNumber, length);
|
||||||
|
}
|
||||||
|
(*i)++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void collectSymbol(const char* input, int* i, int* length)
|
||||||
|
{
|
||||||
|
while (!isWhitespace(input[++(*i)]) && !isSingle(input[(*i)]) && input[(*i)] != '"' && input[(*i)] != '\0') {
|
||||||
|
(*length)++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tripleQuotedString(const char* input, struct Error* err, struct Slice* slice, int* i, int* lineNumber, int* length)
|
||||||
|
{
|
||||||
|
// Skip past the extra opening quotes
|
||||||
|
(*i) += 2;
|
||||||
|
slice->text += 2;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
(*i)++;
|
||||||
|
const int c = *i;
|
||||||
|
if (input[c] == '"' && input[c + 1] == '"' && input[c + 2] == '"') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (input[c] == '\n') {
|
||||||
|
(*lineNumber)++;
|
||||||
|
}
|
||||||
|
(*length)++;
|
||||||
|
if (input[c] == '\0' || input[c + 1] == '\0' || input[c + 2] == '\0') {
|
||||||
|
buildErrFromInput(err, UNEXPECTED_EOF, c, input);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void singleQuotedString(const char* input, int* i, int* lineNumber, int* length)
|
||||||
|
{
|
||||||
|
while (input[++(*i)] != '\0') {
|
||||||
|
if (input[(*i)] == '"') {
|
||||||
|
int backslashes = 0;
|
||||||
|
while (input[((*i) - 1) - backslashes] == '\\') {
|
||||||
|
backslashes++;
|
||||||
|
}
|
||||||
|
// \\\" => Odd number of backslashes, quote IS escaped
|
||||||
|
// \\" => Even number of backslashes, quote is NOT escaped
|
||||||
|
if (backslashes % 2 == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (input[(*i)] == '\n') {
|
||||||
|
(*lineNumber)++;
|
||||||
|
}
|
||||||
|
(*length)++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue