add support for escaped strings + (multi-)char literatls

This commit is contained in:
2022-05-06 01:23:31 +02:00
parent aac7bbd878
commit 4cfc7ae8a8
2 changed files with 84 additions and 4 deletions

View File

@@ -0,0 +1,15 @@
import "env.memory" memory(4);
import "env.printString" fn printString(i32);
import "env.printChar" fn printChar(i32);
export fn upd() {
printChar(12);
printChar('Test');
printChar('\x1f\x10\x10');
printChar('abc\n');
printString(0);
}
data 0 {
"\x0e\x64\"Colors!!!\"\x0e\1\0"
}

View File

@@ -288,11 +288,32 @@ fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = LexerError> {
.map_err(|err| LexerError::custom(span, err.to_string()))
});
let str_ = just('"')
.ignore_then(filter(|c| *c != '"').repeated())
.then_ignore(just('"'))
let str_ = just('\\')
.then(any())
.map(|t| vec![t.0, t.1])
.or(none_of("\"").map(|c| vec![c]))
.repeated()
.flatten()
.delimited_by(just('"'), just('"'))
.collect::<String>()
.map(Token::Str);
.map(|s| Token::Str(parse_string_escapes(s)));
let char_ = just('\\')
.then(any())
.map(|t| vec![t.0, t.1])
.or(none_of("\'").map(|c| vec![c]))
.repeated()
.flatten()
.delimited_by(just('\''), just('\''))
.collect::<String>()
.map(|s| {
let s = parse_string_escapes(s);
let mut value = 0;
for (i, c) in s.chars().enumerate() {
value |= (c as u32) << (i * 8);
}
Token::Int(value as i32)
});
let op = one_of("+-*/%&^|<=>#")
.repeated()
@@ -344,6 +365,7 @@ fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = LexerError> {
.or(int_float)
.or(int)
.or(str_)
.or(char_)
.or(op)
.or(ctrl)
.or(ident)
@@ -354,6 +376,7 @@ fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = LexerError> {
.padded()
.padded_by(comment.padded().repeated())
.repeated()
.boxed()
}
fn map_token<O>(
@@ -372,6 +395,48 @@ fn map_token<O>(
})
}
fn parse_string_escapes(s: String) -> String {
let mut result = String::new();
let mut chars = s.chars();
while let Some(c) = chars.next() {
if c != '\\' {
result.push(c);
} else if let Some(c) = chars.next() {
match c {
'0' => result.push('\0'),
'n' => result.push('\n'),
'r' => result.push('\r'),
't' => result.push('\t'),
'x' => {
if let Some(high) = chars.next() {
if let Some(low) = chars.next() {
if let Ok(c) = u8::from_str_radix(&format!("{}{}", high, low), 16) {
result.push(c as char);
} else {
result.push('\\');
result.push('x');
result.push(high);
result.push(low);
}
} else {
result.push('\\');
result.push('x');
result.push(high);
}
} else {
result.push('\\');
result.push('x');
}
}
other => result.push(other),
}
} else {
result.push('\\');
}
}
result
}
type ScriptError = Simple<Token, Span>;
fn script_parser() -> impl Parser<Token, ast::Script, Error = ScriptError> + Clone {
let identifier = filter_map(|span, tok| match tok {