parent
9d9aaa91b1
commit
10c377b88c
2
justfile
2
justfile
@ -92,7 +92,7 @@ quine: create
|
|||||||
diff tmp/gen1.c tmp/gen2.c
|
diff tmp/gen1.c tmp/gen2.c
|
||||||
@echo 'It was a quine!'
|
@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 our quine
|
||||||
create:
|
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 NAME: Regex = token(r"([a-zA-Z_-][a-zA-Z0-9_-]*)");
|
||||||
static ref PLUS: Regex = token(r"[+]" );
|
static ref PLUS: Regex = token(r"[+]" );
|
||||||
static ref STRING: Regex = token("\"" );
|
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 INDENT: Regex = re(r"^([ \t]*)[^ \t\n\r]" );
|
||||||
static ref INTERPOLATION_START: Regex = re(r"^[{][{]" );
|
static ref INTERPOLATION_START: Regex = re(r"^[{][{]" );
|
||||||
static ref LEADING_TEXT: Regex = re(r"^(?m)(.+?)[{][{]" );
|
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)
|
(captures.at(1).unwrap(), captures.at(2).unwrap(), Comment)
|
||||||
} else if let Some(captures) = RAW_STRING.captures(rest) {
|
} else if let Some(captures) = RAW_STRING.captures(rest) {
|
||||||
(captures.at(1).unwrap(), captures.at(2).unwrap(), RawString)
|
(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) {
|
} else if let Some(captures) = STRING.captures(rest) {
|
||||||
let prefix = captures.at(1).unwrap();
|
let prefix = captures.at(1).unwrap();
|
||||||
let contents = &rest[prefix.len()+1..];
|
let contents = &rest[prefix.len()+1..];
|
||||||
@ -1661,8 +1664,6 @@ fn tokenize(text: &str) -> Result<Vec<Token>, CompileError> {
|
|||||||
return error!(ErrorKind::UnknownStartOfToken)
|
return error!(ErrorKind::UnknownStartOfToken)
|
||||||
};
|
};
|
||||||
|
|
||||||
let len = prefix.len() + lexeme.len();
|
|
||||||
|
|
||||||
tokens.push(Token {
|
tokens.push(Token {
|
||||||
index: index,
|
index: index,
|
||||||
line: line,
|
line: line,
|
||||||
@ -1673,6 +1674,8 @@ fn tokenize(text: &str) -> Result<Vec<Token>, CompileError> {
|
|||||||
kind: kind,
|
kind: kind,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let len = prefix.len() + lexeme.len();
|
||||||
|
|
||||||
if len == 0 {
|
if len == 0 {
|
||||||
let last = tokens.last().unwrap();
|
let last = tokens.last().unwrap();
|
||||||
match last.kind {
|
match last.kind {
|
||||||
@ -1687,10 +1690,19 @@ fn tokenize(text: &str) -> Result<Vec<Token>, CompileError> {
|
|||||||
Eol => {
|
Eol => {
|
||||||
line += 1;
|
line += 1;
|
||||||
column = 0;
|
column = 0;
|
||||||
},
|
}
|
||||||
Eof => {
|
Eof => {
|
||||||
break;
|
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;
|
column += len;
|
||||||
}
|
}
|
||||||
@ -1963,24 +1975,7 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn file(mut self) -> Result<Justfile<'a>, CompileError<'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;
|
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 {
|
loop {
|
||||||
match self.tokens.next() {
|
match self.tokens.next() {
|
||||||
Some(token) => match token.kind {
|
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]
|
#[test]
|
||||||
fn string_quote_escape() {
|
fn string_quote_escape() {
|
||||||
parse_summary(
|
parse_summary(
|
||||||
|
Loading…
Reference in New Issue
Block a user