parent
9d9aaa91b1
commit
10c377b88c
2
justfile
2
justfile
@ -92,7 +92,7 @@ quine: create
|
||||
diff tmp/gen1.c tmp/gen2.c
|
||||
@echo 'It was a quine!'
|
||||
|
||||
quine-text = "int printf(const char*, ...); int main() { char *s = \"int printf(const char*, ...); int main() { char *s = %c%s%c; printf(s, 34, s, 34); return 0; }\"; printf(s, 34, s, 34); return 0; }"
|
||||
quine-text = 'int printf(const char*, ...); int main() { char *s = "int printf(const char*, ...); int main() { char *s = %c%s%c; printf(s, 34, s, 34); return 0; }"; printf(s, 34, s, 34); return 0; }'
|
||||
|
||||
# create our quine
|
||||
create:
|
||||
|
@ -1272,3 +1272,142 @@ fn long_circular_recipe_dependency() {
|
||||
",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiline_raw_string() {
|
||||
integration_test(
|
||||
&["a"],
|
||||
"
|
||||
string = 'hello
|
||||
whatever'
|
||||
|
||||
a:
|
||||
echo '{{string}}'
|
||||
",
|
||||
0,
|
||||
"hello
|
||||
whatever
|
||||
",
|
||||
"echo 'hello
|
||||
whatever'
|
||||
",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_line_after_multiline_raw_string() {
|
||||
integration_test(
|
||||
&["a"],
|
||||
"
|
||||
string = 'hello
|
||||
|
||||
whatever' + 'yo'
|
||||
|
||||
a:
|
||||
echo '{{foo}}'
|
||||
",
|
||||
255,
|
||||
"",
|
||||
"error: variable `foo` not defined
|
||||
|
|
||||
7 | echo '{{foo}}'
|
||||
| ^^^
|
||||
",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_column_after_multiline_raw_string() {
|
||||
integration_test(
|
||||
&["a"],
|
||||
"
|
||||
string = 'hello
|
||||
|
||||
whatever' + bar
|
||||
|
||||
a:
|
||||
echo '{{string}}'
|
||||
",
|
||||
255,
|
||||
"",
|
||||
"error: variable `bar` not defined
|
||||
|
|
||||
4 | whatever' + bar
|
||||
| ^^^
|
||||
",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiline_raw_string_in_interpolation() {
|
||||
integration_test(
|
||||
&["a"],
|
||||
r#"
|
||||
a:
|
||||
echo '{{"a" + '
|
||||
' + "b"}}'
|
||||
"#,
|
||||
0,
|
||||
"a
|
||||
b
|
||||
",
|
||||
"echo 'a
|
||||
b'
|
||||
",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_line_after_multiline_raw_string_in_interpolation() {
|
||||
integration_test(
|
||||
&["a"],
|
||||
r#"
|
||||
a:
|
||||
echo '{{"a" + '
|
||||
' + "b"}}'
|
||||
|
||||
echo {{b}}
|
||||
"#,
|
||||
255,
|
||||
"",
|
||||
"error: variable `b` not defined
|
||||
|
|
||||
6 | echo {{b}}
|
||||
| ^
|
||||
",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unterminated_raw_string() {
|
||||
integration_test(
|
||||
&["a"],
|
||||
"
|
||||
a b=':
|
||||
",
|
||||
255,
|
||||
"",
|
||||
"error: unterminated string
|
||||
|
|
||||
2 | a b=':
|
||||
| ^
|
||||
",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unterminated_string() {
|
||||
integration_test(
|
||||
&["a"],
|
||||
r#"
|
||||
a b=":
|
||||
"#,
|
||||
255,
|
||||
"",
|
||||
r#"error: unterminated string
|
||||
|
|
||||
2 | a b=":
|
||||
| ^
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
39
src/lib.rs
39
src/lib.rs
@ -1467,7 +1467,8 @@ fn tokenize(text: &str) -> Result<Vec<Token>, CompileError> {
|
||||
static ref NAME: Regex = token(r"([a-zA-Z_-][a-zA-Z0-9_-]*)");
|
||||
static ref PLUS: Regex = token(r"[+]" );
|
||||
static ref STRING: Regex = token("\"" );
|
||||
static ref RAW_STRING: Regex = token(r#"'[^'\r\n]*'"# );
|
||||
static ref RAW_STRING: Regex = token(r#"'[^']*'"# );
|
||||
static ref UNTERMINATED_RAW_STRING: Regex = token(r#"'[^']*"# );
|
||||
static ref INDENT: Regex = re(r"^([ \t]*)[^ \t\n\r]" );
|
||||
static ref INTERPOLATION_START: Regex = re(r"^[{][{]" );
|
||||
static ref LEADING_TEXT: Regex = re(r"^(?m)(.+?)[{][{]" );
|
||||
@ -1629,6 +1630,8 @@ fn tokenize(text: &str) -> Result<Vec<Token>, CompileError> {
|
||||
(captures.at(1).unwrap(), captures.at(2).unwrap(), Comment)
|
||||
} else if let Some(captures) = RAW_STRING.captures(rest) {
|
||||
(captures.at(1).unwrap(), captures.at(2).unwrap(), RawString)
|
||||
} else if UNTERMINATED_RAW_STRING.is_match(rest) {
|
||||
return error!(ErrorKind::UnterminatedString);
|
||||
} else if let Some(captures) = STRING.captures(rest) {
|
||||
let prefix = captures.at(1).unwrap();
|
||||
let contents = &rest[prefix.len()+1..];
|
||||
@ -1661,8 +1664,6 @@ fn tokenize(text: &str) -> Result<Vec<Token>, CompileError> {
|
||||
return error!(ErrorKind::UnknownStartOfToken)
|
||||
};
|
||||
|
||||
let len = prefix.len() + lexeme.len();
|
||||
|
||||
tokens.push(Token {
|
||||
index: index,
|
||||
line: line,
|
||||
@ -1673,6 +1674,8 @@ fn tokenize(text: &str) -> Result<Vec<Token>, CompileError> {
|
||||
kind: kind,
|
||||
});
|
||||
|
||||
let len = prefix.len() + lexeme.len();
|
||||
|
||||
if len == 0 {
|
||||
let last = tokens.last().unwrap();
|
||||
match last.kind {
|
||||
@ -1687,10 +1690,19 @@ fn tokenize(text: &str) -> Result<Vec<Token>, CompileError> {
|
||||
Eol => {
|
||||
line += 1;
|
||||
column = 0;
|
||||
},
|
||||
}
|
||||
Eof => {
|
||||
break;
|
||||
},
|
||||
}
|
||||
RawString => {
|
||||
let lexeme_lines = lexeme.lines().count();
|
||||
line += lexeme_lines - 1;
|
||||
if lexeme_lines == 1 {
|
||||
column += len;
|
||||
} else {
|
||||
column = lexeme.lines().last().unwrap().len();
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
column += len;
|
||||
}
|
||||
@ -1963,24 +1975,7 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
|
||||
fn file(mut self) -> Result<Justfile<'a>, CompileError<'a>> {
|
||||
// how do i associate comments with recipes?
|
||||
// save the last doc
|
||||
// clear it after every item
|
||||
|
||||
let mut doc = None;
|
||||
|
||||
/*
|
||||
trait Swap<T> {
|
||||
fn swap(&mut self, T) -> T
|
||||
}
|
||||
|
||||
impl<I> Swap<Option<I>> for Option<I> {
|
||||
fn swap(&mut self, replacement: Option<I>) -> Option<I> {
|
||||
std::mem::replace(self, replacement)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
loop {
|
||||
match self.tokens.next() {
|
||||
Some(token) => match token.kind {
|
||||
|
13
src/unit.rs
13
src/unit.rs
@ -612,6 +612,19 @@ fn unterminated_string_with_escapes() {
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unterminated_raw_string() {
|
||||
let text = "r a='asdf";
|
||||
parse_error(text, CompileError {
|
||||
text: text,
|
||||
index: 4,
|
||||
line: 0,
|
||||
column: 4,
|
||||
width: None,
|
||||
kind: ErrorKind::UnterminatedString,
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn string_quote_escape() {
|
||||
parse_summary(
|
||||
|
Loading…
Reference in New Issue
Block a user