Compare commits
2 Commits
6e2b7da22f
...
61de3b100f
Author | SHA1 | Date | |
---|---|---|---|
61de3b100f | |||
ef70bc1cc0 |
@ -15,6 +15,7 @@
|
|||||||
- Watch mode
|
- Watch mode
|
||||||
- Formatter
|
- Formatter
|
||||||
- Simple language server
|
- Simple language server
|
||||||
|
- Decide how to handle comments in the syntax (?)
|
||||||
|
|
||||||
## v0.0.10
|
## v0.0.10
|
||||||
|
|
||||||
@ -24,8 +25,8 @@
|
|||||||
|
|
||||||
- [x] Hand-make CLI, remove clap
|
- [x] Hand-make CLI, remove clap
|
||||||
- [x] Compile a single file
|
- [x] Compile a single file
|
||||||
- [ ] Display error messages during compilation instead of panicking
|
- [x] Display error messages during compilation instead of panicking
|
||||||
- [ ] Improve errror messages
|
- [x] Improve error messages
|
||||||
- [ ] Implement code generation for ast nodes implemented as of now
|
- [ ] Implement code generation for ast nodes implemented as of now
|
||||||
|
|
||||||
|
|
||||||
|
14
src/codegen/block.rs
Normal file
14
src/codegen/block.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
use crate::syntax::ast::Block;
|
||||||
|
|
||||||
|
use super::Transpilable;
|
||||||
|
|
||||||
|
impl Transpilable for Block {
|
||||||
|
fn transpile(&self) -> String {
|
||||||
|
// TODO: Handle indentation
|
||||||
|
self.statements
|
||||||
|
.iter()
|
||||||
|
.map(|x| x.transpile())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("\n")
|
||||||
|
}
|
||||||
|
}
|
@ -4,7 +4,11 @@ use super::Transpilable;
|
|||||||
|
|
||||||
impl Transpilable for FunctionDeclaration {
|
impl Transpilable for FunctionDeclaration {
|
||||||
fn transpile(&self) -> String {
|
fn transpile(&self) -> String {
|
||||||
format!("function {}() {{}}", self.identifier)
|
format!(
|
||||||
|
"function {}() {{\n{}\n}}",
|
||||||
|
self.identifier,
|
||||||
|
self.block.transpile()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
use crate::syntax::ast::ModuleAST;
|
use crate::syntax::ast::ModuleAST;
|
||||||
|
|
||||||
mod binding;
|
mod binding;
|
||||||
|
mod block;
|
||||||
mod expression;
|
mod expression;
|
||||||
mod function_declaration;
|
mod function_declaration;
|
||||||
mod module_ast;
|
mod module_ast;
|
||||||
|
mod statement;
|
||||||
mod top_level_construct;
|
mod top_level_construct;
|
||||||
|
|
||||||
/// 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
|
||||||
|
@ -11,7 +11,7 @@ impl Transpilable for ModuleAST {
|
|||||||
.map(|binding| binding.transpile())
|
.map(|binding| binding.transpile())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
bindings_str.join("\n")
|
format!("<?php\n\n{}\n", bindings_str.join("\n"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
9
src/codegen/statement.rs
Normal file
9
src/codegen/statement.rs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
use crate::syntax::ast::statement::Statement;
|
||||||
|
|
||||||
|
use super::Transpilable;
|
||||||
|
|
||||||
|
impl Transpilable for Statement {
|
||||||
|
fn transpile(&self) -> String {
|
||||||
|
String::from("// TODO (statement)")
|
||||||
|
}
|
||||||
|
}
|
@ -1,22 +1,29 @@
|
|||||||
use std::collections::VecDeque;
|
|
||||||
|
|
||||||
use super::{PrintableError, SyntaxError};
|
use super::{PrintableError, SyntaxError};
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
impl PrintableError for SyntaxError {
|
impl PrintableError for SyntaxError {
|
||||||
fn get_error_str(&self, chars: &Vec<char>) -> String {
|
fn get_error_str(&self, chars: &Vec<char>) -> String {
|
||||||
let (line, before, length) = get_line(chars, self.error_start, self.error_end);
|
let (line, before, length) = get_line(chars, self.error_start, self.error_end);
|
||||||
|
|
||||||
|
let line_number = get_line_number(chars, self.error_start);
|
||||||
|
let line_number_whitespace = " ".repeat(line_number.to_string().len());
|
||||||
|
|
||||||
let whitespace = vec![' '; before].iter().collect::<String>();
|
let whitespace = vec![' '; before].iter().collect::<String>();
|
||||||
let indicator = vec!['^'; length].iter().collect::<String>();
|
let indicator = vec!['^'; length].iter().collect::<String>();
|
||||||
|
let reason = &self.reason;
|
||||||
|
|
||||||
format!(
|
format!(
|
||||||
"\n{}\n{}{}\n\n{}{}{}\n{}",
|
r#"
|
||||||
line, whitespace, indicator, "Syntax error at pos ", self.error_start, ":", self.reason
|
{line_number_whitespace} |
|
||||||
|
{line_number } | {line}
|
||||||
|
{line_number_whitespace} | {whitespace}{indicator}
|
||||||
|
|
||||||
|
{reason} at line {line_number}:{before}"#,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extracts a lin e of code
|
/// Extracts a line of code
|
||||||
///
|
///
|
||||||
/// - `chars`: Input where to extract the line from
|
/// - `chars`: Input where to extract the line from
|
||||||
/// - `start_position`: Position where the erroneous code starts
|
/// - `start_position`: Position where the erroneous code starts
|
||||||
@ -90,6 +97,22 @@ fn get_line(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_line_number(chars: &Vec<char>, target_pos: usize) -> usize {
|
||||||
|
let mut count = 1;
|
||||||
|
|
||||||
|
for (pos, char) in chars.iter().enumerate() {
|
||||||
|
if pos >= target_pos {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if *char == '\n' {
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
count
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -449,4 +449,12 @@ mod indentation_tests {
|
|||||||
assert_eq!(TokenType::DEDENT, tokens[8].token_type);
|
assert_eq!(TokenType::DEDENT, tokens[8].token_type);
|
||||||
assert_eq!(TokenType::EOF, tokens[9].token_type);
|
assert_eq!(TokenType::EOF, tokens[9].token_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_lex_comments() {
|
||||||
|
let input = String::from("// ??");
|
||||||
|
let tokens = get_tokens(&input).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(TokenType::Comment, tokens[0].token_type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ pub enum TopLevelDeclaration {
|
|||||||
pub struct FunctionDeclaration {
|
pub struct FunctionDeclaration {
|
||||||
pub identifier: Box<String>,
|
pub identifier: Box<String>,
|
||||||
pub params_list: Box<ParamsList>,
|
pub params_list: Box<ParamsList>,
|
||||||
|
pub block: Box<Block>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -64,7 +64,7 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<Function
|
|||||||
};
|
};
|
||||||
current_pos = next_pos;
|
current_pos = next_pos;
|
||||||
|
|
||||||
let (_block, next_pos) = match parse_block(tokens, current_pos) {
|
let (block, next_pos) = match parse_block(tokens, current_pos) {
|
||||||
ParseResult::Ok(block, next_pos) => (block, next_pos),
|
ParseResult::Ok(block, next_pos) => (block, next_pos),
|
||||||
ParseResult::Err(error) => {
|
ParseResult::Err(error) => {
|
||||||
return ParseResult::Err(error);
|
return ParseResult::Err(error);
|
||||||
@ -91,6 +91,7 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<Function
|
|||||||
FunctionDeclaration {
|
FunctionDeclaration {
|
||||||
identifier: Box::new(identifier.value.clone()),
|
identifier: Box::new(identifier.value.clone()),
|
||||||
params_list: Box::new(params_list),
|
params_list: Box::new(params_list),
|
||||||
|
block: Box::new(block),
|
||||||
},
|
},
|
||||||
current_pos,
|
current_pos,
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user