feat: parse loops
This commit is contained in:
parent
fa4d79dbe4
commit
86166c2105
@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
- [x] Parse conditionals
|
- [x] Parse conditionals
|
||||||
- [x] Parse arrays
|
- [x] Parse arrays
|
||||||
|
- [x] Parse for loops
|
||||||
|
|
||||||
|
|
||||||
## v0.1.1
|
## v0.1.1
|
||||||
|
17
src/semantic/checks/block.rs
Normal file
17
src/semantic/checks/block.rs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
use crate::{
|
||||||
|
error_handling::MistiError,
|
||||||
|
semantic::{impls::SemanticCheck, symbol_table::SymbolTable},
|
||||||
|
syntax::ast::BlockMember,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl<'a> SemanticCheck for BlockMember<'a> {
|
||||||
|
// TODO: A block may contain a function declaration statement,
|
||||||
|
// but (afaik) those are not allowed inside conditionals/loops
|
||||||
|
// somehow detect those?
|
||||||
|
fn check_semantics(&self, scope: &SymbolTable) -> Result<(), MistiError> {
|
||||||
|
match self {
|
||||||
|
BlockMember::Stmt(s) => s.check_semantics(scope),
|
||||||
|
BlockMember::Expr(e) => e.check_semantics(scope),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
error_handling::{semantic_error::SemanticError, MistiError},
|
error_handling::{semantic_error::SemanticError, MistiError},
|
||||||
semantic::{impls::SemanticCheck, symbol_table::SymbolTable, types::Type},
|
semantic::{impls::SemanticCheck, symbol_table::SymbolTable, types::Type},
|
||||||
syntax::ast::{BlockMember, FunctionDeclaration, Statement},
|
syntax::ast::FunctionDeclaration,
|
||||||
};
|
};
|
||||||
|
|
||||||
impl SemanticCheck for FunctionDeclaration<'_> {
|
impl SemanticCheck for FunctionDeclaration<'_> {
|
||||||
@ -31,27 +31,7 @@ impl SemanticCheck for FunctionDeclaration<'_> {
|
|||||||
// TODO: Check the return type of the function body
|
// TODO: Check the return type of the function body
|
||||||
// This should be the last expression in the block
|
// This should be the last expression in the block
|
||||||
for stmt in self.block.members.iter() {
|
for stmt in self.block.members.iter() {
|
||||||
match stmt {
|
stmt.check_semantics(&function_scope)?;
|
||||||
BlockMember::Stmt(Statement::Binding(b)) => {
|
|
||||||
if let Err(err) = b.check_semantics(&function_scope) {
|
|
||||||
return Err(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BlockMember::Stmt(Statement::FnDecl(f)) => {
|
|
||||||
// TODO: (for now) a function cannot be declared inside another function.
|
|
||||||
let error = SemanticError {
|
|
||||||
error_start: f.identifier.position,
|
|
||||||
error_end: f.identifier.get_end_position(),
|
|
||||||
reason: format!(
|
|
||||||
"A function cannot be defined inside another function."
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
return Err(MistiError::Semantic(error));
|
|
||||||
}
|
|
||||||
BlockMember::Stmt(Statement::Conditional(_)) => unimplemented!("check conditional"),
|
|
||||||
BlockMember::Expr(e) => e.check_semantics(scope)?,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Check that the return type of the function
|
// TODO: Check that the return type of the function
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
pub mod binding;
|
pub mod binding;
|
||||||
|
pub mod block;
|
||||||
pub mod expression;
|
pub mod expression;
|
||||||
pub mod function_declaration;
|
pub mod function_declaration;
|
||||||
pub mod top_level_declaration;
|
pub mod top_level_declaration;
|
||||||
|
@ -23,6 +23,7 @@ impl SemanticCheck for Statement<'_> {
|
|||||||
Statement::Binding(b) => b.check_semantics(scope),
|
Statement::Binding(b) => b.check_semantics(scope),
|
||||||
Statement::FnDecl(f) => f.check_semantics(scope),
|
Statement::FnDecl(f) => f.check_semantics(scope),
|
||||||
Statement::Conditional(_) => unimplemented!("check conditional"),
|
Statement::Conditional(_) => unimplemented!("check conditional"),
|
||||||
|
Statement::ForLoop(_) => unimplemented!("check for loop"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
15
src/syntax/ast/loops.rs
Normal file
15
src/syntax/ast/loops.rs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
use crate::lexic::token::Token;
|
||||||
|
|
||||||
|
use super::Block;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ForLoop<'a> {
|
||||||
|
/// the start position of the
|
||||||
|
/// `for` keyword
|
||||||
|
pub loop_start: usize,
|
||||||
|
/// the position of the closing bracket
|
||||||
|
pub loop_end: usize,
|
||||||
|
pub key: Option<&'a Token>,
|
||||||
|
pub value: &'a Token,
|
||||||
|
pub body: Block<'a>,
|
||||||
|
}
|
@ -1,9 +1,11 @@
|
|||||||
use crate::lexic::token::Token;
|
use crate::lexic::token::Token;
|
||||||
|
|
||||||
use self::functions::FunctionCall;
|
use self::functions::FunctionCall;
|
||||||
|
use loops::ForLoop;
|
||||||
use var_binding::VariableBinding;
|
use var_binding::VariableBinding;
|
||||||
|
|
||||||
pub mod functions;
|
pub mod functions;
|
||||||
|
pub mod loops;
|
||||||
pub mod var_binding;
|
pub mod var_binding;
|
||||||
|
|
||||||
/// Trait that allows nodes to inform
|
/// Trait that allows nodes to inform
|
||||||
@ -33,13 +35,14 @@ pub enum Statement<'a> {
|
|||||||
FnDecl(FunctionDeclaration<'a>),
|
FnDecl(FunctionDeclaration<'a>),
|
||||||
// TODO: Implement conditionals as expressions
|
// TODO: Implement conditionals as expressions
|
||||||
Conditional(Conditional<'a>),
|
Conditional(Conditional<'a>),
|
||||||
|
ForLoop(ForLoop<'a>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Conditional<'a> {
|
pub struct Conditional<'a> {
|
||||||
pub if_member: Condition<'a>,
|
pub if_member: Condition<'a>,
|
||||||
pub else_if_members: Vec<Condition<'a>>,
|
pub else_if_members: Vec<Condition<'a>>,
|
||||||
pub else_block: Option<Block<'a>>
|
pub else_block: Option<Block<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -48,7 +51,6 @@ pub struct Condition<'a> {
|
|||||||
pub body: Block<'a>,
|
pub body: Block<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FunctionDeclaration<'a> {
|
pub struct FunctionDeclaration<'a> {
|
||||||
pub identifier: &'a Token,
|
pub identifier: &'a Token,
|
||||||
@ -59,9 +61,17 @@ pub struct FunctionDeclaration<'a> {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Block<'a> {
|
pub struct Block<'a> {
|
||||||
|
pub start: usize,
|
||||||
|
pub end: usize,
|
||||||
pub members: Vec<BlockMember<'a>>,
|
pub members: Vec<BlockMember<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Positionable for Block<'_> {
|
||||||
|
fn get_position(&self) -> (usize, usize) {
|
||||||
|
(self.start, self.end)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Enum for productions available at the block level
|
/// Enum for productions available at the block level
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum BlockMember<'a> {
|
pub enum BlockMember<'a> {
|
||||||
@ -125,9 +135,11 @@ impl Positionable for Expression<'_> {
|
|||||||
let (_, end) = right_expr.get_position();
|
let (_, end) = right_expr.get_position();
|
||||||
(start, end)
|
(start, end)
|
||||||
}
|
}
|
||||||
Expression::Array(Array {start, end, exps: _}) => {
|
Expression::Array(Array {
|
||||||
(*start, *end)
|
start,
|
||||||
}
|
end,
|
||||||
|
exps: _,
|
||||||
|
}) => (*start, *end),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,7 @@ impl<'a> Parseable<'a> for Block<'a> {
|
|||||||
Ok((prod, next_pos)) => {
|
Ok((prod, next_pos)) => {
|
||||||
members.push(BlockMember::Expr(prod));
|
members.push(BlockMember::Expr(prod));
|
||||||
current_pos = next_pos;
|
current_pos = next_pos;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
Err(ParsingError::Err(error)) => {
|
Err(ParsingError::Err(error)) => {
|
||||||
// TODO: Better error handling, write a better error message
|
// TODO: Better error handling, write a better error message
|
||||||
@ -59,7 +60,7 @@ impl<'a> Parseable<'a> for Block<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Parse closing brace
|
// Parse closing brace
|
||||||
let (_closing_brace, next_pos) =
|
let (closing_brace, next_pos) =
|
||||||
match parse_token_type(tokens, current_pos, TokenType::RightBrace) {
|
match parse_token_type(tokens, current_pos, TokenType::RightBrace) {
|
||||||
Ok((t, next)) => (t, next),
|
Ok((t, next)) => (t, next),
|
||||||
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
||||||
@ -82,7 +83,11 @@ impl<'a> Parseable<'a> for Block<'a> {
|
|||||||
};
|
};
|
||||||
current_pos = next_pos;
|
current_pos = next_pos;
|
||||||
|
|
||||||
let block = Block { members };
|
let block = Block {
|
||||||
|
members,
|
||||||
|
start: opening_brace.position,
|
||||||
|
end: closing_brace.position,
|
||||||
|
};
|
||||||
Ok((block, current_pos))
|
Ok((block, current_pos))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -152,24 +157,23 @@ mod tests {
|
|||||||
assert_eq!(block.members.len(), 1);
|
assert_eq!(block.members.len(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_block_2() {
|
fn test_parse_block_2() {
|
||||||
let tokens = get_tokens(&String::from("{f()\ng()}")).unwrap();
|
let tokens = get_tokens(&String::from("{f()\ng()}")).unwrap();
|
||||||
let block = parse_block(&tokens, 0);
|
let block = Block::try_parse(&tokens, 0);
|
||||||
|
|
||||||
let block = match block {
|
let block = match block {
|
||||||
ParsingResult::Ok((p, _)) => p,
|
ParsingResult::Ok((p, _)) => p,
|
||||||
_ => panic!("Expected a block, got: {:?}", block),
|
_ => panic!("Expected a block, got: {:?}", block),
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(block.statements.len(), 2);
|
assert_eq!(block.members.len(), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_block_3() {
|
fn test_parse_block_3() {
|
||||||
let tokens = get_tokens(&String::from("{\n f()\n}")).unwrap();
|
let tokens = get_tokens(&String::from("{\n f()\n}")).unwrap();
|
||||||
let block = parse_block(&tokens, 0);
|
let block = Block::try_parse(&tokens, 0);
|
||||||
|
|
||||||
let block = match block {
|
let block = match block {
|
||||||
ParsingResult::Ok((p, _)) => p,
|
ParsingResult::Ok((p, _)) => p,
|
||||||
@ -178,7 +182,6 @@ mod tests {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(block.statements.len(), 1);
|
assert_eq!(block.members.len(), 1);
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
@ -141,18 +141,14 @@ impl<'a> Parseable<'a> for Conditional<'a> {
|
|||||||
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
||||||
Err(ParsingError::Mismatch(wrong_token)) => {
|
Err(ParsingError::Mismatch(wrong_token)) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
reason: String::from(
|
reason: String::from("Expected a block after the else keyword"),
|
||||||
"Expected a block after the else keyword",
|
|
||||||
),
|
|
||||||
error_start: wrong_token.position,
|
error_start: wrong_token.position,
|
||||||
error_end: wrong_token.get_end_position(),
|
error_end: wrong_token.get_end_position(),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
Err(ParsingError::Unmatched) => {
|
Err(ParsingError::Unmatched) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
reason: String::from(
|
reason: String::from("Expected a block after the else keyword"),
|
||||||
"Expected a block after the else keyword",
|
|
||||||
),
|
|
||||||
error_start: else_token.position,
|
error_start: else_token.position,
|
||||||
error_end: else_token.get_end_position(),
|
error_end: else_token.get_end_position(),
|
||||||
}));
|
}));
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use super::super::{ast::Expression, ParsingResult};
|
use super::super::{ast::Expression, ParsingResult};
|
||||||
use crate::{lexic::token::Token, syntax::parseable::Parseable};
|
use crate::{lexic::token::Token, syntax::parseable::Parseable};
|
||||||
|
|
||||||
|
mod array;
|
||||||
mod comparison;
|
mod comparison;
|
||||||
mod equality;
|
mod equality;
|
||||||
mod factor;
|
mod factor;
|
||||||
@ -9,7 +10,6 @@ mod primary;
|
|||||||
mod term;
|
mod term;
|
||||||
mod unary;
|
mod unary;
|
||||||
mod utils;
|
mod utils;
|
||||||
mod array;
|
|
||||||
|
|
||||||
impl<'a> Parseable<'a> for Expression<'a> {
|
impl<'a> Parseable<'a> for Expression<'a> {
|
||||||
type Item = Expression<'a>;
|
type Item = Expression<'a>;
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
lexic::token::{Token, TokenType},
|
lexic::token::{Token, TokenType},
|
||||||
syntax::{
|
syntax::{
|
||||||
ast::{Array, Expression}, parseable::Parseable, utils::Tokenizer, ParsingError, ParsingResult,
|
ast::{Array, Expression},
|
||||||
|
parseable::Parseable,
|
||||||
|
utils::Tokenizer,
|
||||||
|
ParsingError, ParsingResult,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -9,20 +12,18 @@ use crate::{
|
|||||||
///
|
///
|
||||||
/// ```ebnf
|
/// ```ebnf
|
||||||
/// primary = array
|
/// primary = array
|
||||||
/// | number
|
/// | number
|
||||||
/// | string
|
/// | string
|
||||||
/// | boolean
|
/// | boolean
|
||||||
/// | identifier
|
/// | identifier
|
||||||
/// | ("(", expression, ")");
|
/// | ("(", expression, ")");
|
||||||
/// ```
|
/// ```
|
||||||
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParsingResult<Expression> {
|
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParsingResult<Expression> {
|
||||||
// array
|
// array
|
||||||
match Array::try_parse(tokens, pos) {
|
match Array::try_parse(tokens, pos) {
|
||||||
Ok((exp, next)) => {
|
Ok((exp, next)) => return Ok((Expression::Array(exp), next)),
|
||||||
return Ok((Expression::Array(exp), next))
|
|
||||||
},
|
|
||||||
Err(ParsingError::Err(e)) => return Err(ParsingError::Err(e)),
|
Err(ParsingError::Err(e)) => return Err(ParsingError::Err(e)),
|
||||||
Err(_) => {},
|
Err(_) => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
match tokens.get_significant(pos) {
|
match tokens.get_significant(pos) {
|
||||||
|
152
src/syntax/parsers/for_loop.rs
Normal file
152
src/syntax/parsers/for_loop.rs
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
use crate::{
|
||||||
|
error_handling::SyntaxError,
|
||||||
|
lexic::token::{Token, TokenType},
|
||||||
|
syntax::{
|
||||||
|
ast::{loops::ForLoop, Block, Expression, Positionable},
|
||||||
|
parseable::{Parseable, ParsingError, ParsingResult},
|
||||||
|
utils::parse_token_type,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
impl<'a> Parseable<'a> for ForLoop<'a> {
|
||||||
|
type Item = ForLoop<'a>;
|
||||||
|
|
||||||
|
fn try_parse(tokens: &'a Vec<Token>, current_pos: usize) -> ParsingResult<'a, Self::Item> {
|
||||||
|
// for keyword
|
||||||
|
let (for_keyword, next) = match parse_token_type(tokens, current_pos, TokenType::FOR) {
|
||||||
|
Ok(tuple) => tuple,
|
||||||
|
_ => return Err(ParsingError::Unmatched),
|
||||||
|
};
|
||||||
|
|
||||||
|
// first identifier
|
||||||
|
let (first_id, next) = match parse_token_type(tokens, next, TokenType::Identifier) {
|
||||||
|
Ok(t) => t,
|
||||||
|
Err(ParsingError::Err(e)) => return Err(ParsingError::Err(e)),
|
||||||
|
Err(ParsingError::Mismatch(e)) => {
|
||||||
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
|
error_start: e.position,
|
||||||
|
error_end: e.get_end_position(),
|
||||||
|
reason: format!(
|
||||||
|
"Expected an identifier after the `for` keyword, found {}",
|
||||||
|
e.value
|
||||||
|
),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
Err(ParsingError::Unmatched) => {
|
||||||
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
|
error_start: for_keyword.position,
|
||||||
|
error_end: for_keyword.get_end_position(),
|
||||||
|
reason: format!("Expected an identifier after the `for` keyword"),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// comma and possible second identifier
|
||||||
|
let (second_id, next) = 'block: {
|
||||||
|
// attempt to parse comma
|
||||||
|
let (comma, next) = match parse_token_type(tokens, next, TokenType::Comma) {
|
||||||
|
Ok(t) => t,
|
||||||
|
_ => break 'block (None, next),
|
||||||
|
};
|
||||||
|
|
||||||
|
// parse second id
|
||||||
|
// if this fails then its a syntax error, because a comma was already commited
|
||||||
|
match parse_token_type(&tokens, next, TokenType::Identifier) {
|
||||||
|
Ok((second_id, next)) => (Some(second_id), next),
|
||||||
|
Err(ParsingError::Err(e)) => return Err(ParsingError::Err(e)),
|
||||||
|
Err(ParsingError::Mismatch(t)) => {
|
||||||
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
|
error_start: t.position,
|
||||||
|
error_end: t.get_end_position(),
|
||||||
|
reason: format!(
|
||||||
|
"Expected an identifier after the comma, found `{}`",
|
||||||
|
t.value
|
||||||
|
),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
Err(ParsingError::Unmatched) => {
|
||||||
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
|
error_start: comma.position,
|
||||||
|
error_end: comma.get_end_position(),
|
||||||
|
reason: format!("Expected an identifier after the comma"),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// in keyword
|
||||||
|
let (in_keyword, next) = match parse_token_type(tokens, next, TokenType::IN) {
|
||||||
|
Ok(tuple) => tuple,
|
||||||
|
Err(ParsingError::Err(e)) => return Err(ParsingError::Err(e)),
|
||||||
|
Err(ParsingError::Mismatch(t)) => {
|
||||||
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
|
error_start: t.position,
|
||||||
|
error_end: t.get_end_position(),
|
||||||
|
reason: format!("Expected the `in` keyword, found `{}`", t.value),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
Err(ParsingError::Unmatched) => {
|
||||||
|
let previous_token = if second_id.is_none() {
|
||||||
|
first_id
|
||||||
|
} else {
|
||||||
|
second_id.unwrap()
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
|
error_start: previous_token.position,
|
||||||
|
error_end: previous_token.get_end_position(),
|
||||||
|
reason: format!("Expected the `in` keyword"),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// expression
|
||||||
|
let (expr, next) = match Expression::try_parse(tokens, next) {
|
||||||
|
Ok(t) => t,
|
||||||
|
Err(ParsingError::Err(e)) => return Err(ParsingError::Err(e)),
|
||||||
|
Err(_) => {
|
||||||
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
|
error_start: in_keyword.position,
|
||||||
|
error_end: in_keyword.get_end_position(),
|
||||||
|
reason: format!("Expected an expression after the `in` keyword"),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// block
|
||||||
|
let (block, next) = match Block::try_parse(tokens, next) {
|
||||||
|
Ok(t) => t,
|
||||||
|
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
||||||
|
Err(ParsingError::Mismatch(wrong_token)) => {
|
||||||
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
|
reason: String::from("Expected a block after the collection"),
|
||||||
|
error_start: wrong_token.position,
|
||||||
|
error_end: wrong_token.get_end_position(),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
Err(ParsingError::Unmatched) => {
|
||||||
|
let (error_start, error_end) = expr.get_position();
|
||||||
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
|
reason: String::from("Expected a block after the collection"),
|
||||||
|
error_start,
|
||||||
|
error_end,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// return
|
||||||
|
let (key, value) = match second_id {
|
||||||
|
Some(id) => (Some(first_id), id),
|
||||||
|
None => (None, first_id),
|
||||||
|
};
|
||||||
|
|
||||||
|
let (_, loop_end) = block.get_position();
|
||||||
|
let for_loop = ForLoop {
|
||||||
|
loop_start: for_keyword.position,
|
||||||
|
loop_end,
|
||||||
|
key,
|
||||||
|
value,
|
||||||
|
body: block,
|
||||||
|
};
|
||||||
|
Ok((for_loop, next))
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,8 @@
|
|||||||
pub mod binding;
|
pub mod binding;
|
||||||
pub mod block;
|
pub mod block;
|
||||||
|
pub mod conditional;
|
||||||
pub mod expression;
|
pub mod expression;
|
||||||
|
pub mod for_loop;
|
||||||
pub mod function_declaration;
|
pub mod function_declaration;
|
||||||
pub mod module;
|
pub mod module;
|
||||||
pub mod statement;
|
pub mod statement;
|
||||||
pub mod conditional;
|
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
lexic::token::Token,
|
lexic::token::Token,
|
||||||
syntax::{
|
syntax::{
|
||||||
ast::{var_binding::VariableBinding, Conditional, FunctionDeclaration, Statement},
|
ast::{
|
||||||
|
loops::ForLoop, var_binding::VariableBinding, Conditional, FunctionDeclaration,
|
||||||
|
Statement,
|
||||||
|
},
|
||||||
parseable::{Parseable, ParsingError, ParsingResult},
|
parseable::{Parseable, ParsingError, ParsingResult},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -41,6 +44,13 @@ impl<'a> Parseable<'a> for Statement<'a> {
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Try to parse a for loop
|
||||||
|
match ForLoop::try_parse(tokens, current_pos) {
|
||||||
|
Ok((prod, next)) => return Ok((Statement::ForLoop(prod), next)),
|
||||||
|
Err(ParsingError::Err(e)) => return Err(ParsingError::Err(e)),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
// Here nothing was parsed.
|
// Here nothing was parsed.
|
||||||
Err(ParsingError::Unmatched)
|
Err(ParsingError::Unmatched)
|
||||||
}
|
}
|
||||||
|
@ -85,10 +85,7 @@ pub fn parse_token_type(
|
|||||||
/// Ignores indentation, newlines and comments.
|
/// Ignores indentation, newlines and comments.
|
||||||
///
|
///
|
||||||
/// Only returns: Ok or Unmatched.
|
/// Only returns: Ok or Unmatched.
|
||||||
pub fn parse_terminator(
|
pub fn parse_terminator(tokens: &Vec<Token>, pos: usize) -> ParsingResult<()> {
|
||||||
tokens: &Vec<Token>,
|
|
||||||
pos: usize,
|
|
||||||
) -> ParsingResult<()> {
|
|
||||||
let mut current_pos = pos;
|
let mut current_pos = pos;
|
||||||
|
|
||||||
// Ignore all whitespace, newlines and semicolons
|
// Ignore all whitespace, newlines and semicolons
|
||||||
|
Loading…
Reference in New Issue
Block a user