Compare commits

..

No commits in common. "712936e4d6cd8712ca642c361ae4dd635598202f" and "b4e5caa0f00559891125b97fedb0379dd7c2c62c" have entirely different histories.

14 changed files with 150 additions and 192 deletions

View File

@ -2,28 +2,21 @@
## TODO ## TODO
- [ ] Implement functions as first class citizens - Implement functions as first class citizens
- [ ] Parse __more__ binary operators - Parse __more__ binary operators
- [ ] Parse more complex bindings - Parse more complex bindings
- [ ] Namespace identifiers in the symbol table - Namespace identifiers in the symbol table
- [ ] Stdlib - Stdlib
- [ ] Document code - Document code
- [ ] Watch mode - Watch mode
- [ ] Simple language server - Simple language server
- [ ] Decide how to handle comments in the syntax (?)(should comments mean something like in rust?) - Decide how to handle comments in the syntax (?)(should comments mean something like in rust?)
- [ ] Abstract the parsing of datatypes, such that in the future generics can be implemented in a single place - Abstract the parsing of datatypes, such that in the future generics can be implemented in a single place
- [ ] Begin work on the code formatter - Begin work on the code formatter
- [ ] Remove all panic! and todo! - Remove all panic! and todo!
- [ ] Change REPL to execute code only after `;;` is found - Change REPL to execute code only after `;;` is found
- [ ] Forward the code generated by the REPL to the PHP repl - Forward the code generated by the REPL to the PHP repl
- [ ] Test assignment parsing - Test assignment parsing
## v0.1.4
- [ ] Parse obj/map/dict syntax
- [ ] Parse tuple syntax
- [ ] Parse class instantiation syntax
## v0.1.3 ## v0.1.3
@ -32,9 +25,9 @@
- [ ] Generate php code from current AST - [ ] Generate php code from current AST
- [x] Test correct operator precedence - [x] Test correct operator precedence
- [x] Parse assignments - [x] Parse assignments
- [x] Parse dot `.` operator - [ ] Parse dot `.` operator
- [ ] Parse logic operators `&& ||` - [ ] Parse logic operators `&& ||`
- [x] Parse Array access `arr[pos]` - [ ] Parse Array access `arr[pos]`
- [ ] Parse namespace operator `::` - [ ] Parse namespace operator `::`
- [ ] Implement subtyping for numbers - [ ] Implement subtyping for numbers

View File

@ -24,7 +24,6 @@ pub const COMPILER_TODO: u32 = 20;
pub const SEMANTIC_MISMATCHED_TYPES: u32 = 21; pub const SEMANTIC_MISMATCHED_TYPES: u32 = 21;
pub const SEMANTIC_DUPLICATED_REFERENCE: u32 = 22; pub const SEMANTIC_DUPLICATED_REFERENCE: u32 = 22;
pub const SEMANTIC_MISMATCHED_ARGUMENT_COUNT: u32 = 23; pub const SEMANTIC_MISMATCHED_ARGUMENT_COUNT: u32 = 23;
pub const SYNTAX_INVALID_ARRAY_ACCESS: u32 = 24;
/// Reads the error codes from the error code list /// Reads the error codes from the error code list
pub fn error_code_to_string() -> String { pub fn error_code_to_string() -> String {

View File

@ -45,7 +45,6 @@ impl<'a> PHPTransformable<'a> for Expression<'_> {
PExpresssion::BinaryOp(Box::new(left_value), Box::new(right_value), &op.value) PExpresssion::BinaryOp(Box::new(left_value), Box::new(right_value), &op.value)
} }
Expression::Array(_) => unimplemented!("transform array into php"), Expression::Array(_) => unimplemented!("transform array into php"),
Expression::ArrayAcccess(_) => unimplemented!("transform array access into php"),
} }
} }
} }

View File

@ -262,7 +262,6 @@ impl SemanticCheck for Expression<'_> {
Ok(()) Ok(())
} }
Expression::ArrayAcccess(_array_access) => unimplemented!("typecheck array access"),
} }
} }
} }

View File

@ -219,7 +219,6 @@ impl Typed for Expression<'_> {
let first_type = arr.exps[0].get_type(scope)?; let first_type = arr.exps[0].get_type(scope)?;
Ok(Type::Generic("Array".into(), vec![first_type])) Ok(Type::Generic("Array".into(), vec![first_type]))
} }
Expression::ArrayAcccess(_array_access) => unimplemented!("typecheck array access"),
} }
} }
} }

View File

@ -121,7 +121,6 @@ pub enum Expression<'a> {
/// left expression, right expression, operator /// left expression, right expression, operator
BinaryOperator(Box<Expression<'a>>, Box<Expression<'a>>, &'a Token), BinaryOperator(Box<Expression<'a>>, Box<Expression<'a>>, &'a Token),
Array(Array<'a>), Array(Array<'a>),
ArrayAcccess(ArrayAccess<'a>),
} }
#[derive(Debug)] #[derive(Debug)]
@ -133,13 +132,6 @@ pub struct Array<'a> {
pub end: usize, pub end: usize,
} }
#[derive(Debug)]
pub struct ArrayAccess<'a> {
pub left_expr: Box<Expression<'a>>,
pub idx_expr: Box<Expression<'a>>,
pub end_pos: usize,
}
impl Positionable for Expression<'_> { impl Positionable for Expression<'_> {
/// Returns the absolute start and end position /// Returns the absolute start and end position
/// of this expression /// of this expression
@ -166,10 +158,6 @@ impl Positionable for Expression<'_> {
end, end,
exps: _, exps: _,
}) => (*start, *end), }) => (*start, *end),
Expression::ArrayAcccess(a) => {
let (start, _) = a.left_expr.get_position();
(start, a.end_pos)
}
} }
} }
} }

View File

@ -3,7 +3,7 @@ use crate::{
syntax::{ast::Expression, ParsingError, ParsingResult}, syntax::{ast::Expression, ParsingError, ParsingResult},
}; };
use super::utils::parse_many; use super::utils::try_binary_op;
/// Parses a factor expression. /// Parses a factor expression.
/// ///
@ -16,7 +16,33 @@ pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParsingResult<Expression> {
_ => return Err(ParsingError::Unmatched), _ => return Err(ParsingError::Unmatched),
}; };
parse_many(tokens, next_pos, term, 0, &vec![">", ">=", "<", "<="]) parse_many(tokens, next_pos, term, 0)
}
fn parse_many<'a>(
tokens: &'a Vec<Token>,
pos: usize,
prev_expr: Expression<'a>,
indentation_level: u32,
) -> ParsingResult<'a, Expression<'a>> {
// comparison = term, ((">" | ">=" | "<" | "<="), term)*;
try_binary_op(
tokens,
pos,
prev_expr,
vec![">", ">=", "<", "<="],
indentation_level,
|tokens, next_pos, prev_expr, token, indent_count: u32| match super::term::try_parse(
tokens, next_pos,
) {
Ok((expr, next_pos)) => {
let expr = Expression::BinaryOperator(Box::new(prev_expr), Box::new(expr), &token);
parse_many(tokens, next_pos, expr, indentation_level + indent_count)
}
_ => return Err(ParsingError::Unmatched),
},
)
} }
#[cfg(test)] #[cfg(test)]

View File

@ -1,20 +0,0 @@
use crate::{
lexic::token::Token,
syntax::{ast::Expression, ParsingError, ParsingResult},
};
use super::utils::parse_many;
/// Parses a dot access
///
/// ```ebnf
/// dot_access = unary, (("."), unary)*;
/// ```
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParsingResult<Expression> {
let (unary, next_pos) = match super::unary::try_parse(tokens, pos) {
Ok((expr, next_pos)) => (expr, next_pos),
_ => return Err(ParsingError::Unmatched),
};
parse_many(tokens, next_pos, unary, 0, &vec![".", "?.", "!."])
}

View File

@ -3,7 +3,7 @@ use crate::{
syntax::{ast::Expression, ParsingError, ParsingResult}, syntax::{ast::Expression, ParsingError, ParsingResult},
}; };
use super::utils::parse_many; use super::utils::try_binary_op;
/// Parses a factor expression. /// Parses a factor expression.
/// ///
@ -16,7 +16,33 @@ pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParsingResult<Expression> {
_ => return Err(ParsingError::Unmatched), _ => return Err(ParsingError::Unmatched),
}; };
parse_many(tokens, next_pos, comparison, 0, &vec!["==", "!="]) parse_many(tokens, next_pos, comparison, 0)
}
fn parse_many<'a>(
tokens: &'a Vec<Token>,
pos: usize,
prev_expr: Expression<'a>,
indentation_level: u32,
) -> ParsingResult<'a, Expression<'a>> {
// equality = comparison, (("==" | "!="), comparison )*;
try_binary_op(
tokens,
pos,
prev_expr,
vec!["==", "!="],
indentation_level,
|tokens, next_pos, prev_expr, token, indent_count: u32| match super::comparison::try_parse(
tokens, next_pos,
) {
Ok((expr, next_pos)) => {
let expr = Expression::BinaryOperator(Box::new(prev_expr), Box::new(expr), &token);
parse_many(tokens, next_pos, expr, indentation_level + indent_count)
}
_ => return Err(ParsingError::Unmatched),
},
)
} }
#[cfg(test)] #[cfg(test)]

View File

@ -1,22 +1,50 @@
use crate::{ use crate::{
lexic::token::Token, lexic::token::Token,
syntax::{ast::Expression, ParsingError, ParsingResult}, syntax::{
ast::Expression, parsers::expression::utils::try_binary_op, ParsingError, ParsingResult,
},
}; };
use super::utils::parse_many;
/// Parses a factor expression. /// Parses a factor expression.
/// ///
/// ```ebnf /// ```ebnf
/// factor = dot_access, (("/" | "*" | "%"), dot_access)*; /// factor = unary, (("/" | "*" | "%"), unary)*;
/// ``` /// ```
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParsingResult<Expression> { pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParsingResult<Expression> {
let (unary, next_pos) = match super::dot_access::try_parse(tokens, pos) { let (unary, next_pos) = match super::unary::try_parse(tokens, pos) {
Ok((expr, next_pos)) => (expr, next_pos), Ok((expr, next_pos)) => (expr, next_pos),
_ => return Err(ParsingError::Unmatched), _ => return Err(ParsingError::Unmatched),
}; };
parse_many(tokens, next_pos, unary, 0, &vec!["/", "*", "%"]) parse_many(tokens, next_pos, unary, 0)
}
fn parse_many<'a>(
tokens: &'a Vec<Token>,
pos: usize,
prev_expr: Expression<'a>,
indentation_level: u32,
) -> ParsingResult<'a, Expression<'a>> {
// (("/" | "*" | "%"), unary)*
try_binary_op(
tokens,
pos,
prev_expr,
vec!["/", "*", "%"],
indentation_level,
|tokens, next_pos, prev_expr, token, indent_count: u32| {
// match next
match super::unary::try_parse(tokens, next_pos) {
Ok((expr, next_pos)) => {
let expr =
Expression::BinaryOperator(Box::new(prev_expr), Box::new(expr), &token);
parse_many(tokens, next_pos, expr, indentation_level + indent_count)
}
_ => return Err(ParsingError::Unmatched),
}
},
)
} }
#[cfg(test)] #[cfg(test)]

View File

@ -1,11 +1,8 @@
use crate::{ use crate::{
error_handling::{error_messages::SYNTAX_INVALID_ARRAY_ACCESS, ErrorContainer, ErrorLabel}, lexic::token::Token,
lexic::token::{Token, TokenType},
syntax::{ syntax::{
ast::{functions::FunctionCall, ArrayAccess, Expression}, ast::{functions::FunctionCall, Expression},
functions::arguments_list, functions::arguments_list,
parseable::Parseable,
utils::parse_token_type,
ParsingError, ParsingResult, ParsingError, ParsingResult,
}, },
}; };
@ -14,7 +11,6 @@ use crate::{
/// ///
/// ```ebnf /// ```ebnf
/// function call expr = primary, "(", (arguments list)?, ")" /// function call expr = primary, "(", (arguments list)?, ")"
/// | primary, "[", expressions, "]"
/// | primary; /// | primary;
/// ``` /// ```
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParsingResult<Expression> { pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParsingResult<Expression> {
@ -23,90 +19,21 @@ pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParsingResult<Expression> {
_ => return Err(ParsingError::Unmatched), _ => return Err(ParsingError::Unmatched),
}; };
// Attempt to parse a function call
// Parse arguments list // Parse arguments list
match arguments_list::try_parse(tokens, next_pos) { let (arguments, next_pos) = match arguments_list::try_parse(tokens, next_pos) {
Ok((arguments, next_pos)) => { Ok((args, next)) => (args, next),
let fun_call = FunctionCall {
function: Box::new(primary_expr),
arguments: Box::new(arguments),
};
return Ok((Expression::FunctionCall(fun_call), next_pos));
}
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)), Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
_ => {} _ => {
}; return Ok((primary_expr, next_pos));
// Attempt to parse an array access
match try_parse_array_access(tokens, next_pos) {
Ok(((array_idx, end_pos), next_pos)) => {
let fun_call = ArrayAccess {
left_expr: Box::new(primary_expr),
idx_expr: Box::new(array_idx),
end_pos,
};
return Ok((Expression::ArrayAcccess(fun_call), next_pos));
} }
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
_ => {}
}; };
// Return the parsed primary let fun_call = FunctionCall {
return Ok((primary_expr, next_pos)); function: Box::new(primary_expr),
} arguments: Box::new(arguments),
pub fn try_parse_array_access(
tokens: &Vec<Token>,
pos: usize,
) -> ParsingResult<(Expression, usize)> {
let (_token, next_pos) = parse_token_type(&tokens, pos, TokenType::LeftBracket)?;
// parse an expression
let (exp, next_pos) = match Expression::try_parse(tokens, next_pos) {
Ok(t) => t,
Err(ParsingError::Mismatch(e)) => {
let label = ErrorLabel {
message: String::from("Expected an expression for this array access"),
start: e.position,
end: e.get_end_position(),
};
let econtainer = ErrorContainer {
error_code: SYNTAX_INVALID_ARRAY_ACCESS,
error_offset: e.position,
labels: vec![label],
note: None,
help: None,
};
return Err(ParsingError::Err(econtainer));
}
Err(ParsingError::Unmatched) => {
//
let label = ErrorLabel {
message: String::from("Expected an expression for this array access"),
start: pos,
end: pos + 1,
};
let econtainer = ErrorContainer {
error_code: SYNTAX_INVALID_ARRAY_ACCESS,
error_offset: pos,
labels: vec![label],
note: None,
help: None,
};
return Err(ParsingError::Err(econtainer));
}
Err(ParsingError::Err(e)) => return Err(ParsingError::Err(e)),
}; };
// parse the closing bracket Ok((Expression::FunctionCall(fun_call), next_pos))
let (closed_bracket, next) = match parse_token_type(tokens, next_pos, TokenType::RightBracket) {
Ok(t) => t,
Err(e) => return Err(e),
};
return Ok(((exp, closed_bracket.get_end_position()), next));
} }
#[cfg(test)] #[cfg(test)]

View File

@ -3,7 +3,6 @@ use crate::{lexic::token::Token, syntax::parseable::Parseable};
mod array; mod array;
mod comparison; mod comparison;
mod dot_access;
mod equality; mod equality;
mod factor; mod factor;
pub mod function_call_expr; pub mod function_call_expr;

View File

@ -1,10 +1,9 @@
use crate::syntax::parsers::expression::utils::try_binary_op;
use crate::{ use crate::{
lexic::token::Token, lexic::token::Token,
syntax::{ast::Expression, ParsingError, ParsingResult}, syntax::{ast::Expression, ParsingError, ParsingResult},
}; };
use super::utils::parse_many;
/// Parses a factor expression. /// Parses a factor expression.
/// ///
/// ```ebnf /// ```ebnf
@ -16,7 +15,36 @@ pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParsingResult<Expression> {
_ => return Err(ParsingError::Unmatched), _ => return Err(ParsingError::Unmatched),
}; };
parse_many(tokens, next_pos, factor, 0, &vec!["-", "+", "++"]) parse_many(tokens, next_pos, factor, 0)
}
fn parse_many<'a>(
tokens: &'a Vec<Token>,
pos: usize,
prev_expr: Expression<'a>,
indentation_level: u32,
) -> ParsingResult<'a, Expression<'a>> {
// term = factor, (("-" | "+" | "++"), factor)*;
try_binary_op(
tokens,
pos,
prev_expr,
vec!["+", "-", "++"],
indentation_level,
|tokens, pos, prev_expr, token, indent_count: u32| {
// Parse the next factor
match super::factor::try_parse(tokens, pos) {
Ok((expr, next_pos)) => {
let expr =
Expression::BinaryOperator(Box::new(prev_expr), Box::new(expr), &token);
parse_many(tokens, next_pos, expr, indentation_level + indent_count)
}
_ => return Err(ParsingError::Unmatched),
}
},
)
} }
#[cfg(test)] #[cfg(test)]

View File

@ -1,7 +1,7 @@
use crate::lexic::token::Token; use crate::lexic::token::Token;
use crate::lexic::token::TokenType::{NewLine, DEDENT, INDENT}; use crate::lexic::token::TokenType::{NewLine, DEDENT, INDENT};
use crate::syntax::ast::Expression; use crate::syntax::ast::Expression;
use crate::syntax::parseable::{ParsingError, ParsingResult}; use crate::syntax::parseable::ParsingResult;
/// Parses a binary operator, handles indentation and runs a function on it. /// Parses a binary operator, handles indentation and runs a function on it.
/// ///
@ -15,7 +15,7 @@ pub fn try_binary_op<'a, F>(
tokens: &'a Vec<Token>, tokens: &'a Vec<Token>,
original_pos: usize, original_pos: usize,
prev_expr: Expression<'a>, prev_expr: Expression<'a>,
operators: &Vec<&str>, operators: Vec<&str>,
indentation_level: u32, indentation_level: u32,
fun: F, fun: F,
) -> ParsingResult<'a, Expression<'a>> ) -> ParsingResult<'a, Expression<'a>>
@ -87,36 +87,3 @@ where
Ok((new_expr, next_pos)) Ok((new_expr, next_pos))
} }
pub fn parse_many<'a>(
tokens: &'a Vec<Token>,
pos: usize,
prev_expr: Expression<'a>,
indentation_level: u32,
operators: &Vec<&str>,
) -> ParsingResult<'a, Expression<'a>> {
// comparison = term, ((">" | ">=" | "<" | "<="), term)*;
try_binary_op(
tokens,
pos,
prev_expr,
operators,
indentation_level,
|tokens, next_pos, prev_expr, token, indent_count: u32| match super::term::try_parse(
tokens, next_pos,
) {
Ok((expr, next_pos)) => {
let expr = Expression::BinaryOperator(Box::new(prev_expr), Box::new(expr), &token);
parse_many(
tokens,
next_pos,
expr,
indentation_level + indent_count,
operators,
)
}
_ => return Err(ParsingError::Unmatched),
},
)
}