Skip to content

Commit

Permalink
implement string escaping
Browse files Browse the repository at this point in the history
  • Loading branch information
Gusarich committed Mar 27, 2024
1 parent ea32eed commit 3667ee6
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 7 deletions.
22 changes: 21 additions & 1 deletion src/generator/writers/writeExpression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,27 @@ export function writeExpression(f: ASTExpression, ctx: WriterContext): string {
//

if (f.kind === 'string') {
const id = writeString(f.value, ctx);
const s = f.value.replace(/\\\\|\\\"|\\n|\\r|\\t|\\b|\\f/g, (match) => {
switch (match) {
case '\\\\':
return '\\';
case '\\"':
return '"';
case '\\n':
return '\n';
case '\\r':
return '\r';
case '\\t':
return '\t';
case '\\b':
return '\b';
case '\\f':
return '\f';
default:
return match;
}
});
let id = writeString(s, ctx);
ctx.used(id);
return `${id}()`;
}
Expand Down
13 changes: 11 additions & 2 deletions src/grammar/grammar.ohm
Original file line number Diff line number Diff line change
Expand Up @@ -215,8 +215,17 @@ Tact {
boolLiteral = ("true" | "false") ~idPart

// String literal
stringLiteralCharacter = ~("\"" | "\\" | lineTerminator) any
stringLiteral = "\"" stringLiteralCharacter* "\""
// stringLiteralCharacter = ~("\"" | "\\" | lineTerminator) any
// stringLiteral = "\"" stringLiteralCharacter* "\""
stringLiteral = "\"" (nonQuoteOrBackslashChar | escapeSequence)* "\""
nonQuoteOrBackslashChar = ~("\"" | "\\") any
escapeSequence = "\\" "\\" -- backslash
| "\\" "\"" -- doubleQuote
| "\\" "n" -- newline
| "\\" "r" -- carriageReturn
| "\\" "t" -- tab
| "\\" "b" -- backspace
| "\\" "f" -- formFeed

// Keywords
// NOTE Order is important
Expand Down
10 changes: 9 additions & 1 deletion src/grammar/grammar.ohm-bundle.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,16 @@ export interface TactActionDict<T> extends ActionDict<T> {
funcLetter?: (this: NonterminalNode, arg0: NonterminalNode | TerminalNode) => T;
funcId?: (this: NonterminalNode, arg0: NonterminalNode, arg1: IterationNode) => T;
boolLiteral?: (this: NonterminalNode, arg0: TerminalNode) => T;
stringLiteralCharacter?: (this: NonterminalNode, arg0: NonterminalNode) => T;
stringLiteral?: (this: NonterminalNode, arg0: TerminalNode, arg1: IterationNode, arg2: TerminalNode) => T;
nonQuoteOrBackslashChar?: (this: NonterminalNode, arg0: NonterminalNode) => T;
escapeSequence_backslash?: (this: NonterminalNode, arg0: TerminalNode, arg1: TerminalNode) => T;
escapeSequence_doubleQuote?: (this: NonterminalNode, arg0: TerminalNode, arg1: TerminalNode) => T;
escapeSequence_newline?: (this: NonterminalNode, arg0: TerminalNode, arg1: TerminalNode) => T;
escapeSequence_carriageReturn?: (this: NonterminalNode, arg0: TerminalNode, arg1: TerminalNode) => T;
escapeSequence_tab?: (this: NonterminalNode, arg0: TerminalNode, arg1: TerminalNode) => T;
escapeSequence_backspace?: (this: NonterminalNode, arg0: TerminalNode, arg1: TerminalNode) => T;
escapeSequence_formFeed?: (this: NonterminalNode, arg0: TerminalNode, arg1: TerminalNode) => T;
escapeSequence?: (this: NonterminalNode, arg0: NonterminalNode) => T;
keyword?: (this: NonterminalNode, arg0: NonterminalNode) => T;
contract?: (this: NonterminalNode, arg0: TerminalNode) => T;
let?: (this: NonterminalNode, arg0: TerminalNode) => T;
Expand Down
2 changes: 1 addition & 1 deletion src/grammar/grammar.ohm-bundle.js

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions src/test/feature-strings.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,15 @@ describe('feature-strings', () => {
const d = r.beginParse().loadBuffer(r.bits.length / 8);
expect(d.toString('hex')).toEqual(s.toString('hex'));
}

expect(await contract.getStringWithEscapedChars1()).toBe(
'test \n \n \\ \\\n "string"'
);
expect(await contract.getStringWithEscapedChars2()).toEqual(
'test \n test \t test \r test \b test \f test " test \' test \\ \\\\ "_" "" test'
);
expect(await contract.getStringWithEscapedChars3()).toEqual(
'test \\n test \\t test \\r test \\b test \\f test \\" test \\\' test \\\\ \\\\\\\\ \\"_\\" \\"\\" test'
);
});
});
14 changes: 12 additions & 2 deletions src/test/features/strings.tact
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
contract StringsTester {

init() {

}
Expand Down Expand Up @@ -60,7 +59,6 @@ contract StringsTester {
return b.toString();
}


get fun stringWithLargeNumber(): String {
let b: StringBuilder = beginString();
b.append("Hello, your balance: ");
Expand All @@ -79,4 +77,16 @@ contract StringsTester {
get fun processBase64(src: String): Slice {
return src.fromBase64();
}

get fun stringWithEscapedChars1(): String {
return "test \n \n \\ \\\n \"string\"";
}

get fun stringWithEscapedChars2(): String {
return "test \n test \t test \r test \b test \f test \" test ' test \\ \\\\ \"_\" \"\" test";
}

get fun stringWithEscapedChars3(): String {
return "test \\n test \\t test \\r test \\b test \\f test \\\" test \\' test \\\\ \\\\\\\\ \\\"_\\\" \\\"\\\" test";
}
}

0 comments on commit 3667ee6

Please sign in to comment.