use lexer to detect remaining layout in parse_number_from_string (#1773)
This commit is contained in:
@@ -886,75 +886,92 @@ impl MachineState {
|
|||||||
indices: &IndexStore,
|
indices: &IndexStore,
|
||||||
stub_gen: impl Fn() -> FunctorStub,
|
stub_gen: impl Fn() -> FunctorStub,
|
||||||
) -> CallResult {
|
) -> CallResult {
|
||||||
|
use crate::parser::lexer::*;
|
||||||
|
|
||||||
let nx = self.store(self.deref(self.registers[2]));
|
let nx = self.store(self.deref(self.registers[2]));
|
||||||
|
let add_dot = !string.ends_with(".");
|
||||||
|
let cursor = std::io::Cursor::new(string);
|
||||||
|
|
||||||
let mut charcode_space = false;
|
let iter = std::io::Read::chain(
|
||||||
let mut cs = string.chars();
|
cursor,
|
||||||
|
{
|
||||||
|
let mut dot_buf: [u8; '.'.len_utf8()] = [0u8];
|
||||||
|
|
||||||
loop {
|
if add_dot {
|
||||||
let c = cs.next();
|
'.'.encode_utf8(&mut dot_buf);
|
||||||
|
}
|
||||||
|
|
||||||
if c == None {
|
std::io::Cursor::new(dot_buf)
|
||||||
break;
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut lexer = Lexer::new(CharReader::new(iter), self);
|
||||||
|
let mut tokens = vec![];
|
||||||
|
|
||||||
|
match lexer.next_token() {
|
||||||
|
Ok(token @ Token::Literal(Literal::Atom(atom!("-")) | Literal::Char('-'))) => {
|
||||||
|
tokens.push(token);
|
||||||
|
|
||||||
|
if let Ok(token) = lexer.next_token() {
|
||||||
|
tokens.push(token);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Ok(token) => {
|
||||||
if c == Some('0')
|
tokens.push(token);
|
||||||
&& cs.next() == Some('\'')
|
}
|
||||||
&& cs.next() == Some(' ')
|
Err(err) => {
|
||||||
&& cs.next() == None {
|
let err = self.syntax_error(err);
|
||||||
charcode_space = true;
|
return Err(self.error_form(err, stub_gen()));
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !charcode_space {
|
loop {
|
||||||
if let Some(c) = string.chars().last() {
|
match lexer.lookahead_char() {
|
||||||
if layout_char!(c) {
|
Err(ParserError::UnexpectedEOF) => {
|
||||||
let (line_num, col_num) = string.chars().fold((0, 0), |(line_num, col_num), c| {
|
let mut parser = Parser::from_lexer(lexer);
|
||||||
if new_line_char!(c) {
|
let op_dir = CompositeOpDir::new(&indices.op_dir, None);
|
||||||
(1 + line_num, 0)
|
|
||||||
} else {
|
tokens.reverse();
|
||||||
(line_num, col_num + 1)
|
|
||||||
|
match parser.read_term(&op_dir, Tokens::Provided(tokens)) {
|
||||||
|
Err(err) => {
|
||||||
|
let err = self.syntax_error(err);
|
||||||
|
return Err(self.error_form(err, stub_gen()));
|
||||||
}
|
}
|
||||||
});
|
Ok(Term::Literal(_, Literal::Rational(n))) => {
|
||||||
|
self.unify_rational(n, nx);
|
||||||
|
}
|
||||||
|
Ok(Term::Literal(_, Literal::Float(n))) => {
|
||||||
|
self.unify_f64(n.as_ptr(), nx);
|
||||||
|
}
|
||||||
|
Ok(Term::Literal(_, Literal::Integer(n))) => {
|
||||||
|
self.unify_big_int(n, nx);
|
||||||
|
}
|
||||||
|
Ok(Term::Literal(_, Literal::Fixnum(n))) => {
|
||||||
|
self.unify_fixnum(n, nx);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let err = ParserError::ParseBigInt(0, 0);
|
||||||
|
let err = self.syntax_error(err);
|
||||||
|
|
||||||
|
return Err(self.error_form(err, stub_gen()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Ok('.') => {
|
||||||
|
lexer.skip_char('.');
|
||||||
|
}
|
||||||
|
Ok(c) => {
|
||||||
|
let (line_num, col_num) = (lexer.line_num, lexer.col_num);
|
||||||
|
|
||||||
let err = ParserError::UnexpectedChar(c, line_num, col_num);
|
let err = ParserError::UnexpectedChar(c, line_num, col_num);
|
||||||
let err = self.syntax_error(err);
|
let err = self.syntax_error(err);
|
||||||
|
|
||||||
return Err(self.error_form(err, stub_gen()));
|
return Err(self.error_form(err, stub_gen()));
|
||||||
}
|
}
|
||||||
}
|
Err(_) => unreachable!(),
|
||||||
}
|
|
||||||
|
|
||||||
let mut dot_buf: [u8; '.'.len_utf8()] = [0u8];
|
|
||||||
'.'.encode_utf8(&mut dot_buf);
|
|
||||||
|
|
||||||
let cursor = std::io::Cursor::new(string);
|
|
||||||
let iter = std::io::Read::chain(cursor, std::io::Cursor::new(dot_buf));
|
|
||||||
|
|
||||||
let mut parser = Parser::new(CharReader::new(iter), self);
|
|
||||||
|
|
||||||
match parser.read_term(&CompositeOpDir::new(&indices.op_dir, None)) {
|
|
||||||
Err(err) => {
|
|
||||||
let err = self.syntax_error(err);
|
|
||||||
return Err(self.error_form(err, stub_gen()));
|
|
||||||
}
|
|
||||||
Ok(Term::Literal(_, Literal::Rational(n))) => {
|
|
||||||
self.unify_rational(n, nx);
|
|
||||||
}
|
|
||||||
Ok(Term::Literal(_, Literal::Float(n))) => {
|
|
||||||
self.unify_f64(n.as_ptr(), nx);
|
|
||||||
}
|
|
||||||
Ok(Term::Literal(_, Literal::Integer(n))) => {
|
|
||||||
self.unify_big_int(n, nx);
|
|
||||||
}
|
|
||||||
Ok(Term::Literal(_, Literal::Fixnum(n))) => {
|
|
||||||
self.unify_fixnum(n, nx);
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
let err = ParserError::ParseBigInt(0, 0);
|
|
||||||
let err = self.syntax_error(err);
|
|
||||||
|
|
||||||
return Err(self.error_form(err, stub_gen()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5730,8 +5747,9 @@ impl Machine {
|
|||||||
if let Some(atom_or_string) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
|
if let Some(atom_or_string) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
|
||||||
let chars = CharReader::new(ByteStream::from_string(atom_or_string.to_string()));
|
let chars = CharReader::new(ByteStream::from_string(atom_or_string.to_string()));
|
||||||
let mut parser = Parser::new(chars, &mut self.machine_st);
|
let mut parser = Parser::new(chars, &mut self.machine_st);
|
||||||
|
let op_dir = CompositeOpDir::new(&self.indices.op_dir, None);
|
||||||
|
|
||||||
let term_write_result = parser.read_term(&CompositeOpDir::new(&self.indices.op_dir, None))
|
let term_write_result = parser.read_term(&op_dir, Tokens::Default)
|
||||||
.map_err(CompilationError::from)
|
.map_err(CompilationError::from)
|
||||||
.and_then(|term| {
|
.and_then(|term| {
|
||||||
write_term_to_heap(
|
write_term_to_heap(
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ impl<'a> TermStream for BootstrappingTermStream<'a> {
|
|||||||
fn next(&mut self, op_dir: &CompositeOpDir) -> Result<Term, CompilationError> {
|
fn next(&mut self, op_dir: &CompositeOpDir) -> Result<Term, CompilationError> {
|
||||||
self.parser.reset();
|
self.parser.reset();
|
||||||
self.parser
|
self.parser
|
||||||
.read_term(op_dir)
|
.read_term(op_dir, Tokens::Default)
|
||||||
.map_err(CompilationError::from)
|
.map_err(CompilationError::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
|||||||
self.reader.put_back_char(c);
|
self.reader.put_back_char(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn skip_char(&mut self, c: char) {
|
pub fn skip_char(&mut self, c: char) {
|
||||||
self.reader.consume(c.len_utf8());
|
self.reader.consume(c.len_utf8());
|
||||||
|
|
||||||
if new_line_char!(c) {
|
if new_line_char!(c) {
|
||||||
|
|||||||
@@ -24,6 +24,16 @@ enum TokenType {
|
|||||||
End,
|
End,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Specifies whether the token sequence should be read from the lexer or
|
||||||
|
provided via the Provided variant.
|
||||||
|
*/
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Tokens {
|
||||||
|
Default,
|
||||||
|
Provided(Vec<Token>),
|
||||||
|
}
|
||||||
|
|
||||||
impl TokenType {
|
impl TokenType {
|
||||||
fn is_sep(self) -> bool {
|
fn is_sep(self) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
@@ -302,8 +312,17 @@ impl<'a, R: CharRead> Parser<'a, R> {
|
|||||||
Parser {
|
Parser {
|
||||||
lexer: Lexer::new(stream, machine_st),
|
lexer: Lexer::new(stream, machine_st),
|
||||||
tokens: vec![],
|
tokens: vec![],
|
||||||
stack: Vec::new(),
|
stack: vec![],
|
||||||
terms: Vec::new(),
|
terms: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_lexer(lexer: Lexer<'a, R>) -> Self {
|
||||||
|
Parser {
|
||||||
|
lexer,
|
||||||
|
tokens: vec![],
|
||||||
|
stack: vec![],
|
||||||
|
terms: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1048,8 +1067,11 @@ impl<'a, R: CharRead> Parser<'a, R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// on success, returns the parsed term and the number of lines read.
|
// on success, returns the parsed term and the number of lines read.
|
||||||
pub fn read_term(&mut self, op_dir: &CompositeOpDir) -> Result<Term, ParserError> {
|
pub fn read_term(&mut self, op_dir: &CompositeOpDir, tokens: Tokens) -> Result<Term, ParserError> {
|
||||||
self.tokens = read_tokens(&mut self.lexer)?;
|
self.tokens = match tokens {
|
||||||
|
Tokens::Default => read_tokens(&mut self.lexer)?,
|
||||||
|
Tokens::Provided(tokens) => tokens,
|
||||||
|
};
|
||||||
|
|
||||||
while let Some(token) = self.tokens.pop() {
|
while let Some(token) = self.tokens.pop() {
|
||||||
self.shift_token(token, op_dir)?;
|
self.shift_token(token, op_dir)?;
|
||||||
|
|||||||
@@ -45,10 +45,11 @@ impl MachineState {
|
|||||||
let (term, num_lines_read) = {
|
let (term, num_lines_read) = {
|
||||||
let prior_num_lines_read = inner.lines_read();
|
let prior_num_lines_read = inner.lines_read();
|
||||||
let mut parser = Parser::new(inner, self);
|
let mut parser = Parser::new(inner, self);
|
||||||
|
let op_dir = CompositeOpDir::new(op_dir, None);
|
||||||
|
|
||||||
parser.add_lines_read(prior_num_lines_read);
|
parser.add_lines_read(prior_num_lines_read);
|
||||||
|
|
||||||
let term = parser.read_term(&CompositeOpDir::new(op_dir, None))
|
let term = parser.read_term(&op_dir, Tokens::Default)
|
||||||
.map_err(CompilationError::from)?;
|
.map_err(CompilationError::from)?;
|
||||||
|
|
||||||
(term, parser.lines_read() - prior_num_lines_read)
|
(term, parser.lines_read() - prior_num_lines_read)
|
||||||
|
|||||||
Reference in New Issue
Block a user