Refactor last change
This commit is contained in:
parent
8b80dad589
commit
19474eb85e
@ -8,12 +8,13 @@ impl Transpilable for FunctionDeclaration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{lexic::get_tokens, syntax::{construct_ast, ast::TopLevelConstruct}};
|
use crate::{
|
||||||
|
lexic::get_tokens,
|
||||||
|
syntax::{ast::TopLevelConstruct, construct_ast},
|
||||||
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_transpile() {
|
fn should_transpile() {
|
||||||
@ -28,8 +29,7 @@ mod tests {
|
|||||||
let transpiled = fun_decl.transpile();
|
let transpiled = fun_decl.transpile();
|
||||||
|
|
||||||
assert_eq!("function id() {}", transpiled);
|
assert_eq!("function id() {}", transpiled);
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,9 +2,9 @@ use crate::syntax::ast::ModuleAST;
|
|||||||
|
|
||||||
mod binding;
|
mod binding;
|
||||||
mod expression;
|
mod expression;
|
||||||
|
mod function_declaration;
|
||||||
mod module_ast;
|
mod module_ast;
|
||||||
mod top_level_construct;
|
mod top_level_construct;
|
||||||
mod function_declaration;
|
|
||||||
|
|
||||||
/// Trait that the AST and its nodes implement to support transformation to PHP
|
/// Trait that the AST and its nodes implement to support transformation to PHP
|
||||||
trait Transpilable {
|
trait Transpilable {
|
||||||
|
@ -41,16 +41,14 @@ pub fn get_tokens(input: &String) -> Result<Vec<Token>, MistiError> {
|
|||||||
let chars: Vec<char> = input.chars().into_iter().collect();
|
let chars: Vec<char> = input.chars().into_iter().collect();
|
||||||
let mut results = Vec::new();
|
let mut results = Vec::new();
|
||||||
let mut current_pos: usize = 0;
|
let mut current_pos: usize = 0;
|
||||||
let mut indentation_stack = Vec::<usize>::new();
|
let mut indentation_stack = vec![0];
|
||||||
// Used to emit INDENT & DEDENT tokens
|
// Used to emit INDENT & DEDENT tokens
|
||||||
let mut at_new_line = false;
|
let mut at_new_line = false;
|
||||||
|
|
||||||
while has_input(&chars, current_pos) {
|
while has_input(&chars, current_pos) {
|
||||||
match next_token(&chars, current_pos, &mut indentation_stack, at_new_line) {
|
match next_token(&chars, current_pos, &mut indentation_stack, at_new_line) {
|
||||||
LexResult::Some(token, next_pos) => {
|
LexResult::Some(token, next_pos) => {
|
||||||
if token.token_type == TokenType::NewLine {
|
at_new_line = token.token_type == TokenType::NewLine;
|
||||||
at_new_line = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
results.push(token);
|
results.push(token);
|
||||||
current_pos = next_pos;
|
current_pos = next_pos;
|
||||||
@ -73,43 +71,33 @@ pub fn get_tokens(input: &String) -> Result<Vec<Token>, MistiError> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Scans a single token from `chars`, starting from `current_pos`
|
/// Scans a single token from `chars`, starting from `current_pos`
|
||||||
fn next_token(chars: &Chars, current_pos: usize, indentation_stack: &mut Vec<usize>, at_new_line: bool) -> LexResult {
|
fn next_token(
|
||||||
let next_char = peek(chars, current_pos);
|
chars: &Chars,
|
||||||
|
current_pos: usize,
|
||||||
|
indentation_stack: &mut Vec<usize>,
|
||||||
|
at_new_line: bool,
|
||||||
|
) -> LexResult {
|
||||||
|
let mut current_pos = current_pos;
|
||||||
|
|
||||||
// If EOF is reached return nothing but the current position
|
// Handle whitespace
|
||||||
if next_char == '\0' {
|
if peek(chars, current_pos) == ' ' {
|
||||||
|
if at_new_line {
|
||||||
|
return handle_indentation(chars, current_pos, indentation_stack);
|
||||||
|
} else {
|
||||||
|
// Consume whitespace
|
||||||
|
current_pos += 1;
|
||||||
|
while peek(chars, current_pos) == ' ' {
|
||||||
|
current_pos += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If EOF is reached return only the current position
|
||||||
|
if peek(chars, current_pos) == '\0' {
|
||||||
return LexResult::None(current_pos);
|
return LexResult::None(current_pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle whitespace recursively.
|
let next_char = peek(chars, current_pos);
|
||||||
if next_char == ' ' && !at_new_line {
|
|
||||||
return next_token(chars, current_pos + 1, indentation_stack, false);
|
|
||||||
}
|
|
||||||
// When whitespace is found at the start of the line, emit INDENT/DEDENT
|
|
||||||
else if next_char == ' ' && at_new_line {
|
|
||||||
// Count the number of spaces
|
|
||||||
let mut spaces = 0;
|
|
||||||
let mut sub_pos = current_pos;
|
|
||||||
while peek(chars, sub_pos) == ' ' {
|
|
||||||
spaces += 1;
|
|
||||||
sub_pos += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compare the number of spaces with the top of the stack
|
|
||||||
let top = indentation_stack.last().unwrap_or(&0);
|
|
||||||
if spaces > *top {
|
|
||||||
// Push the new indentation level
|
|
||||||
indentation_stack.push(spaces);
|
|
||||||
return LexResult::Some(Token::new_indent(current_pos), current_pos + spaces);
|
|
||||||
} else if spaces < *top {
|
|
||||||
// Pop the indentation level
|
|
||||||
indentation_stack.pop();
|
|
||||||
return LexResult::Some(Token::new_dedent(current_pos), current_pos + spaces);
|
|
||||||
} else {
|
|
||||||
// Same indentation level
|
|
||||||
return next_token(chars, current_pos + spaces, indentation_stack, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scanners
|
// Scanners
|
||||||
None.or_else(|| scanner::number(next_char, chars, current_pos))
|
None.or_else(|| scanner::number(next_char, chars, current_pos))
|
||||||
@ -133,6 +121,35 @@ fn next_token(chars: &Chars, current_pos: usize, indentation_stack: &mut Vec<usi
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_indentation(
|
||||||
|
chars: &Chars,
|
||||||
|
current_pos: usize,
|
||||||
|
indentation_stack: &mut Vec<usize>,
|
||||||
|
) -> LexResult {
|
||||||
|
// Count the number of spaces
|
||||||
|
let mut spaces = 0;
|
||||||
|
let mut sub_pos = current_pos;
|
||||||
|
while peek(chars, sub_pos) == ' ' {
|
||||||
|
spaces += 1;
|
||||||
|
sub_pos += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare the number of spaces with the top of the stack
|
||||||
|
let top = indentation_stack.last().unwrap_or(&0);
|
||||||
|
if spaces > *top {
|
||||||
|
// Push the new indentation level
|
||||||
|
indentation_stack.push(spaces);
|
||||||
|
return LexResult::Some(Token::new_indent(current_pos), current_pos + spaces);
|
||||||
|
} else if spaces < *top {
|
||||||
|
// Pop the indentation level
|
||||||
|
indentation_stack.pop();
|
||||||
|
return LexResult::Some(Token::new_dedent(current_pos), current_pos + spaces);
|
||||||
|
} else {
|
||||||
|
// Same indentation level
|
||||||
|
return next_token(chars, current_pos + spaces, indentation_stack, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the char at `pos`
|
/// Returns the char at `pos`
|
||||||
fn peek(input: &Chars, pos: usize) -> char {
|
fn peek(input: &Chars, pos: usize) -> char {
|
||||||
let result = input.get(pos).unwrap_or(&'\0');
|
let result = input.get(pos).unwrap_or(&'\0');
|
||||||
@ -151,7 +168,7 @@ mod tests {
|
|||||||
|
|
||||||
/// Should return an EOF token if the input has no tokens
|
/// Should return an EOF token if the input has no tokens
|
||||||
#[test]
|
#[test]
|
||||||
fn test1() {
|
fn should_emit_eof() {
|
||||||
let input = String::from("");
|
let input = String::from("");
|
||||||
let tokens = get_tokens(&input).unwrap();
|
let tokens = get_tokens(&input).unwrap();
|
||||||
// 1 semicolon and 1 EOF token
|
// 1 semicolon and 1 EOF token
|
||||||
|
@ -120,9 +120,9 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> Option<SyntaxResult>
|
|||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
Some(SyntaxResult::Ok(
|
Some(SyntaxResult::Ok(super::ast::TopLevelConstruct::Binding(
|
||||||
super::ast::TopLevelConstruct::Binding(binding)
|
binding,
|
||||||
))
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Expects the token at `pos` to be of type `token_type`
|
/// Expects the token at `pos` to be of type `token_type`
|
||||||
|
Loading…
Reference in New Issue
Block a user