|
|
@ -1,16 +1,14 @@
|
|
|
|
use std::str::Chars;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mod cursor;
|
|
|
|
mod cursor;
|
|
|
|
use cursor::Cursor;
|
|
|
|
use cursor::Cursor;
|
|
|
|
|
|
|
|
|
|
|
|
pub(crate) mod token;
|
|
|
|
pub(crate) mod token;
|
|
|
|
use token::Token;
|
|
|
|
use token::{Position, Token};
|
|
|
|
|
|
|
|
|
|
|
|
use crate::error::Error;
|
|
|
|
use crate::error::Error;
|
|
|
|
|
|
|
|
|
|
|
|
pub struct Lexer<'a> {
|
|
|
|
pub struct Lexer {
|
|
|
|
file: String,
|
|
|
|
file: String,
|
|
|
|
cursor: Cursor<'a>,
|
|
|
|
cursor: Cursor,
|
|
|
|
history: Vec<Token>,
|
|
|
|
history: Vec<Token>,
|
|
|
|
offset: usize,
|
|
|
|
offset: usize,
|
|
|
|
token_line: usize,
|
|
|
|
token_line: usize,
|
|
|
@ -27,6 +25,7 @@ struct KeywordMap {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const fn kw(raw: &'static str, kind: token::Kind) -> KeywordMap {
|
|
|
|
const fn kw(raw: &'static str, kind: token::Kind) -> KeywordMap {
|
|
|
|
|
|
|
|
assert!(raw.len() >= 2);
|
|
|
|
KeywordMap { raw, kind }
|
|
|
|
KeywordMap { raw, kind }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -39,7 +38,7 @@ static KEYWORDS: [KeywordMap; 6] = [
|
|
|
|
kw("type", token::Kind::TypeKeyword),
|
|
|
|
kw("type", token::Kind::TypeKeyword),
|
|
|
|
];
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
impl Iterator for Lexer<'_> {
|
|
|
|
impl Iterator for Lexer {
|
|
|
|
type Item = Result<Token, Error>;
|
|
|
|
type Item = Result<Token, Error>;
|
|
|
|
|
|
|
|
|
|
|
|
fn next(&mut self) -> Option<Result<Token, Error>> {
|
|
|
|
fn next(&mut self) -> Option<Result<Token, Error>> {
|
|
|
@ -70,7 +69,8 @@ impl Iterator for Lexer<'_> {
|
|
|
|
'%' => self.token_ok(token::Kind::Percent),
|
|
|
|
'%' => self.token_ok(token::Kind::Percent),
|
|
|
|
|
|
|
|
|
|
|
|
'#' => {
|
|
|
|
'#' => {
|
|
|
|
self.read_comment().unwrap(); // this can't fail
|
|
|
|
// this can't fail
|
|
|
|
|
|
|
|
self.read_comment().unwrap();
|
|
|
|
// we don't need comments for now and they would
|
|
|
|
// we don't need comments for now and they would
|
|
|
|
// only confuse the parser so let's just Not
|
|
|
|
// only confuse the parser so let's just Not
|
|
|
|
self.next()?
|
|
|
|
self.next()?
|
|
|
@ -90,11 +90,11 @@ impl Iterator for Lexer<'_> {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl<'a> Lexer<'a> {
|
|
|
|
impl Lexer {
|
|
|
|
pub fn new(file: String, stream: Chars<'a>) -> Lexer<'a> {
|
|
|
|
pub fn new(filename: String, raw: String) -> Lexer {
|
|
|
|
Lexer {
|
|
|
|
Lexer {
|
|
|
|
file,
|
|
|
|
file: filename,
|
|
|
|
cursor: Cursor::new(stream),
|
|
|
|
cursor: Cursor::new(raw),
|
|
|
|
history: Vec::new(),
|
|
|
|
history: Vec::new(),
|
|
|
|
offset: 0,
|
|
|
|
offset: 0,
|
|
|
|
token_line: 1,
|
|
|
|
token_line: 1,
|
|
|
@ -123,12 +123,18 @@ impl<'a> Lexer<'a> {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub fn expect_kind(&mut self, kind: token::Kind) -> Result<Token, Error> {
|
|
|
|
pub fn expect_kind(&mut self, kind: token::Kind) -> Result<Token, Error> {
|
|
|
|
|
|
|
|
self.expect_kinds(&[kind])
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn expect_kinds(&mut self, kinds: &[token::Kind]) -> Result<Token, Error> {
|
|
|
|
match self.next() {
|
|
|
|
match self.next() {
|
|
|
|
Some(Ok(t)) => if t.kind == kind {
|
|
|
|
Some(Ok(t)) => {
|
|
|
|
Ok(t)
|
|
|
|
if kinds.contains(&t.kind) {
|
|
|
|
} else {
|
|
|
|
Ok(t)
|
|
|
|
self.syntax_error(format!("Expected {}, got {}", kind, t.kind))
|
|
|
|
} else {
|
|
|
|
},
|
|
|
|
self.syntax_error(format!("Expected one of {:?}, got {}", kinds, t.kind))
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
Some(Err(e)) => Err(e),
|
|
|
|
Some(Err(e)) => Err(e),
|
|
|
|
None => self.syntax_error(String::from("Unexpected EOF")),
|
|
|
|
None => self.syntax_error(String::from("Unexpected EOF")),
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -189,7 +195,7 @@ impl<'a> Lexer<'a> {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn read_prefix_int_literal(&mut self) -> Result<Token, Error> {
|
|
|
|
fn read_prefix_int_literal(&mut self) -> Result<Token, Error> {
|
|
|
|
assert_eq!(self.cursor.next(), Some('0'));
|
|
|
|
assert_eq!(self.cursor.current(), Some('0'));
|
|
|
|
match self.cursor.next() {
|
|
|
|
match self.cursor.next() {
|
|
|
|
Some('x') => self.read_int_literal(16),
|
|
|
|
Some('x') => self.read_int_literal(16),
|
|
|
|
Some('o') => self.read_int_literal(8),
|
|
|
|
Some('o') => self.read_int_literal(8),
|
|
|
@ -215,8 +221,11 @@ impl<'a> Lexer<'a> {
|
|
|
|
fn token(&mut self, kind: token::Kind, raw: String) -> Token {
|
|
|
|
fn token(&mut self, kind: token::Kind, raw: String) -> Token {
|
|
|
|
let t = Token {
|
|
|
|
let t = Token {
|
|
|
|
kind,
|
|
|
|
kind,
|
|
|
|
line: self.token_line,
|
|
|
|
pos: Position {
|
|
|
|
col: self.token_col,
|
|
|
|
file: self.file.clone(),
|
|
|
|
|
|
|
|
line: self.token_line,
|
|
|
|
|
|
|
|
col: self.token_col,
|
|
|
|
|
|
|
|
},
|
|
|
|
raw,
|
|
|
|
raw,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
self.token_line = self.cursor.line();
|
|
|
|
self.token_line = self.cursor.line();
|
|
|
@ -248,10 +257,12 @@ impl<'a> Lexer<'a> {
|
|
|
|
|
|
|
|
|
|
|
|
fn syntax_error<T>(&mut self, msg: String) -> Result<T, Error> {
|
|
|
|
fn syntax_error<T>(&mut self, msg: String) -> Result<T, Error> {
|
|
|
|
Err(Error::syntax_error(
|
|
|
|
Err(Error::syntax_error(
|
|
|
|
self.file.clone(),
|
|
|
|
Position {
|
|
|
|
self.cursor.line(),
|
|
|
|
file: self.file.clone(),
|
|
|
|
self.cursor.col(),
|
|
|
|
line: self.cursor.line(),
|
|
|
|
msg
|
|
|
|
col: self.cursor.col(),
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
msg,
|
|
|
|
))
|
|
|
|
))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|