Compare commits
5 Commits
6c774f960a
...
2830a1befd
Author | SHA1 | Date | |
---|---|---|---|
2830a1befd | |||
3e592392a8 | |||
7379c469d3 | |||
498f8fb87f | |||
3d5c7769e6 |
@ -22,11 +22,11 @@
|
|||||||
|
|
||||||
## v0.0.9
|
## v0.0.9
|
||||||
|
|
||||||
- [ ] Hand made CLI, remove clap
|
- [x] Hand-make CLI, remove clap
|
||||||
- [ ] Compile a single file
|
- [x] Compile a single file
|
||||||
- [ ] Implement code generation for ast nodes implemented as of now
|
- [ ] Display error messages during compilation instead of panicking
|
||||||
- [ ] Display error messages during compilation
|
|
||||||
- [ ] Improve errror messages
|
- [ ] Improve errror messages
|
||||||
|
- [ ] Implement code generation for ast nodes implemented as of now
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
50
src/cli/compile.rs
Normal file
50
src/cli/compile.rs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
use colored::*;
|
||||||
|
|
||||||
|
pub fn compile_command(arguments: Vec<String>) {
|
||||||
|
if arguments.is_empty() {
|
||||||
|
println!("{}", compile_help());
|
||||||
|
println!("{}: {}", "error".on_red(), "No file specified");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if arguments.len() > 1 {
|
||||||
|
println!("{}", compile_help());
|
||||||
|
println!(
|
||||||
|
"{}: {}",
|
||||||
|
"error".on_red(),
|
||||||
|
"Only a single file can be compiled at a time"
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let argument = &arguments[0];
|
||||||
|
if argument.starts_with("-") {
|
||||||
|
let opt_str = argument.as_str();
|
||||||
|
|
||||||
|
println!("{}", compile_help());
|
||||||
|
|
||||||
|
if opt_str != "-h" && opt_str != "--help" {
|
||||||
|
println!(
|
||||||
|
"{}: {}",
|
||||||
|
"error".on_red(),
|
||||||
|
"Invalid option. The compile command only accepts the `-h` or `--help` option"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
crate::file::compile_file(argument);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compile_help() -> String {
|
||||||
|
format!(
|
||||||
|
r#"Compile a single file in place. If the file to compile
|
||||||
|
references other THP files, they will be (typechecked?) as well.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
`thp compile {0}` Compile {0} and output in the same directory
|
||||||
|
`thp compile -h` Print this message & exit
|
||||||
|
"#,
|
||||||
|
"_file_".green()
|
||||||
|
)
|
||||||
|
}
|
@ -7,11 +7,11 @@ enum EmptyOptions {
|
|||||||
Version,
|
Version,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn empty_command(options: &Vec<String>) {
|
pub fn empty_command(arguments: Vec<String>) {
|
||||||
// Add all options to a set
|
// Add all options to a set
|
||||||
let mut options_set = std::collections::HashSet::new();
|
let mut options_set = std::collections::HashSet::new();
|
||||||
for option in options {
|
for option in arguments {
|
||||||
match expand_option(option) {
|
match expand_option(&option) {
|
||||||
Ok(o) => {
|
Ok(o) => {
|
||||||
options_set.insert(o);
|
options_set.insert(o);
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
use crate::cli::get_help_text;
|
use crate::cli::get_help_text;
|
||||||
use colored::*;
|
use colored::*;
|
||||||
|
|
||||||
pub fn help_command(options: &Vec<String>) {
|
pub fn help_command(arguments: Vec<String>) {
|
||||||
println!("{}", get_help_text());
|
println!("{}", get_help_text());
|
||||||
|
|
||||||
if options.len() > 0 {
|
if arguments.len() > 0 {
|
||||||
println!(
|
println!(
|
||||||
"{}: {}",
|
"{}: {}",
|
||||||
"warning".yellow(),
|
"warning".yellow(),
|
||||||
"The help command doesn't take any options."
|
"The help command doesn't take any argument."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
|
mod compile;
|
||||||
mod empty;
|
mod empty;
|
||||||
mod help;
|
mod help;
|
||||||
mod types;
|
mod types;
|
||||||
|
|
||||||
use types::{Command, CommandType};
|
use types::CommandType;
|
||||||
|
|
||||||
use colored::*;
|
use colored::*;
|
||||||
|
|
||||||
@ -39,7 +40,7 @@ fn get_version() -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_cli() {
|
pub fn run_cli() {
|
||||||
let command = match parse_args() {
|
let (command, args) = match parse_args() {
|
||||||
Ok(c) => c,
|
Ok(c) => c,
|
||||||
Err(reason) => {
|
Err(reason) => {
|
||||||
println!("{}", get_help_text());
|
println!("{}", get_help_text());
|
||||||
@ -48,38 +49,17 @@ pub fn run_cli() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
command.run();
|
command.run(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_args() -> Result<Command, String> {
|
fn parse_args() -> Result<(CommandType, Vec<String>), String> {
|
||||||
let mut args = std::env::args().collect::<Vec<String>>();
|
let mut args = std::env::args().collect::<Vec<String>>();
|
||||||
|
|
||||||
|
// Remove the first argument, which is the path to the executable
|
||||||
args.remove(0);
|
args.remove(0);
|
||||||
|
|
||||||
let mut args = args.into_iter();
|
let command = match args.get(0) {
|
||||||
let mut options = Vec::new();
|
Some(command) if !command.starts_with('-') => match command.as_str() {
|
||||||
|
|
||||||
let command = match args.next() {
|
|
||||||
Some(command) if !command.starts_with('-') => Some(command),
|
|
||||||
Some(option) => {
|
|
||||||
options.push(option);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
for arg in args {
|
|
||||||
if arg.starts_with('-') {
|
|
||||||
options.push(arg);
|
|
||||||
} else {
|
|
||||||
return Err(format!(
|
|
||||||
"Unexpected command `{}`. There can only be one command",
|
|
||||||
arg
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let command = match command {
|
|
||||||
Some(command) => match command.as_str() {
|
|
||||||
"c" | "compile" => CommandType::Compile,
|
"c" | "compile" => CommandType::Compile,
|
||||||
"f" | "format" => CommandType::Format,
|
"f" | "format" => CommandType::Format,
|
||||||
"r" | "repl" => CommandType::Repl,
|
"r" | "repl" => CommandType::Repl,
|
||||||
@ -90,8 +70,12 @@ fn parse_args() -> Result<Command, String> {
|
|||||||
"help" | "h" => CommandType::Help,
|
"help" | "h" => CommandType::Help,
|
||||||
_ => return Err(format!("Unknown command `{}`", command)),
|
_ => return Err(format!("Unknown command `{}`", command)),
|
||||||
},
|
},
|
||||||
None => CommandType::None,
|
_ => CommandType::None,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Command { command, options })
|
if command != CommandType::None {
|
||||||
|
args.remove(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok((command, args))
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,4 @@
|
|||||||
#[derive(Debug)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct Command {
|
|
||||||
pub command: CommandType,
|
|
||||||
pub options: Vec<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum CommandType {
|
pub enum CommandType {
|
||||||
Compile,
|
Compile,
|
||||||
Format,
|
Format,
|
||||||
@ -17,16 +11,11 @@ pub enum CommandType {
|
|||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Command {
|
|
||||||
pub fn run(&self) {
|
|
||||||
self.command.run(&self.options);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandType {
|
impl CommandType {
|
||||||
pub fn run(&self, options: &Vec<String>) {
|
pub fn run(&self, options: Vec<String>) {
|
||||||
match self {
|
match self {
|
||||||
CommandType::Help => super::help::help_command(options),
|
CommandType::Help => super::help::help_command(options),
|
||||||
|
CommandType::Compile => super::compile::compile_command(options),
|
||||||
CommandType::None => super::empty::empty_command(options),
|
CommandType::None => super::empty::empty_command(options),
|
||||||
_ => {
|
_ => {
|
||||||
println!("Not implemented yet! {:?} {:?}", self, options);
|
println!("Not implemented yet! {:?} {:?}", self, options);
|
||||||
|
@ -4,38 +4,27 @@ use crate::syntax::ast::var_binding::Binding;
|
|||||||
impl Transpilable for Binding {
|
impl Transpilable for Binding {
|
||||||
/// Transpiles val and var bindings into PHP.
|
/// Transpiles val and var bindings into PHP.
|
||||||
fn transpile(&self) -> String {
|
fn transpile(&self) -> String {
|
||||||
match self {
|
let expression_str = self.expression.transpile();
|
||||||
Binding::Val(val_binding) => {
|
|
||||||
let expression_str = val_binding.expression.transpile();
|
|
||||||
|
|
||||||
format!("${} = {};", val_binding.identifier, expression_str)
|
format!("${} = {};", self.identifier, expression_str)
|
||||||
}
|
|
||||||
Binding::Var(var_binding) => {
|
|
||||||
let expression_str = var_binding.expression.transpile();
|
|
||||||
|
|
||||||
format!("${} = {};", var_binding.identifier, expression_str)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::syntax::ast::{
|
use crate::syntax::ast::{var_binding::Binding, Expression};
|
||||||
var_binding::{Binding, ValBinding},
|
|
||||||
Expression,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn binding_should_transpile() {
|
fn binding_should_transpile() {
|
||||||
let id = String::from("identifier");
|
let id = String::from("identifier");
|
||||||
let value = String::from("322");
|
let value = String::from("322");
|
||||||
let binding = Binding::Val(ValBinding {
|
let binding = Binding {
|
||||||
datatype: None,
|
datatype: None,
|
||||||
identifier: Box::new(id),
|
identifier: Box::new(id),
|
||||||
expression: Expression::Number(Box::new(value)),
|
expression: Expression::Number(Box::new(value)),
|
||||||
});
|
is_mutable: false,
|
||||||
|
};
|
||||||
|
|
||||||
let result = binding.transpile();
|
let result = binding.transpile();
|
||||||
|
|
||||||
|
@ -18,20 +18,18 @@ impl Transpilable for ModuleAST {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::syntax::ast::{
|
use crate::syntax::ast::{var_binding::Binding, Expression, TopLevelDeclaration};
|
||||||
var_binding::{Binding, ValBinding},
|
|
||||||
Expression, TopLevelDeclaration,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn module_ast_should_transpile() {
|
fn module_ast_should_transpile() {
|
||||||
let id = String::from("identifier");
|
let id = String::from("identifier");
|
||||||
let value = String::from("322");
|
let value = String::from("322");
|
||||||
let binding = Binding::Val(ValBinding {
|
let binding = Binding {
|
||||||
datatype: None,
|
datatype: None,
|
||||||
identifier: Box::new(id),
|
identifier: Box::new(id),
|
||||||
expression: Expression::Number(Box::new(value)),
|
expression: Expression::Number(Box::new(value)),
|
||||||
});
|
is_mutable: false,
|
||||||
|
};
|
||||||
|
|
||||||
let module = ModuleAST {
|
let module = ModuleAST {
|
||||||
declarations: vec![TopLevelDeclaration::Binding(binding)],
|
declarations: vec![TopLevelDeclaration::Binding(binding)],
|
||||||
|
@ -4,8 +4,8 @@ use crate::lexic::{token::Token, utils, LexResult};
|
|||||||
/// Checks if a String is a keyword, and returns its TokenType
|
/// Checks if a String is a keyword, and returns its TokenType
|
||||||
fn str_is_keyword(s: &String) -> Option<TokenType> {
|
fn str_is_keyword(s: &String) -> Option<TokenType> {
|
||||||
match s.as_str() {
|
match s.as_str() {
|
||||||
"var" => Some(TokenType::VAR),
|
"let" => Some(TokenType::LET),
|
||||||
"val" => Some(TokenType::VAL),
|
"mut" => Some(TokenType::MUT),
|
||||||
"fun" => Some(TokenType::FUN),
|
"fun" => Some(TokenType::FUN),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
@ -141,23 +141,23 @@ mod tests {
|
|||||||
// Should scan keywords
|
// Should scan keywords
|
||||||
#[test]
|
#[test]
|
||||||
fn test_4() {
|
fn test_4() {
|
||||||
let input = str_to_vec("var");
|
let input = str_to_vec("mut");
|
||||||
let start_pos = 0;
|
let start_pos = 0;
|
||||||
if let LexResult::Some(token, next) = scan(*input.get(0).unwrap(), &input, start_pos) {
|
if let LexResult::Some(token, next) = scan(*input.get(0).unwrap(), &input, start_pos) {
|
||||||
assert_eq!(3, next);
|
assert_eq!(3, next);
|
||||||
assert_eq!(TokenType::VAR, token.token_type);
|
assert_eq!(TokenType::MUT, token.token_type);
|
||||||
assert_eq!("var", token.value);
|
assert_eq!("mut", token.value);
|
||||||
assert_eq!(0, token.position);
|
assert_eq!(0, token.position);
|
||||||
} else {
|
} else {
|
||||||
panic!()
|
panic!()
|
||||||
}
|
}
|
||||||
|
|
||||||
let input = str_to_vec("val");
|
let input = str_to_vec("let");
|
||||||
let start_pos = 0;
|
let start_pos = 0;
|
||||||
if let LexResult::Some(token, next) = scan(*input.get(0).unwrap(), &input, start_pos) {
|
if let LexResult::Some(token, next) = scan(*input.get(0).unwrap(), &input, start_pos) {
|
||||||
assert_eq!(3, next);
|
assert_eq!(3, next);
|
||||||
assert_eq!(TokenType::VAL, token.token_type);
|
assert_eq!(TokenType::LET, token.token_type);
|
||||||
assert_eq!("val", token.value);
|
assert_eq!("let", token.value);
|
||||||
assert_eq!(0, token.position);
|
assert_eq!(0, token.position);
|
||||||
} else {
|
} else {
|
||||||
panic!()
|
panic!()
|
||||||
|
@ -15,8 +15,8 @@ pub enum TokenType {
|
|||||||
Comment,
|
Comment,
|
||||||
INDENT,
|
INDENT,
|
||||||
DEDENT,
|
DEDENT,
|
||||||
VAR,
|
LET,
|
||||||
VAL,
|
MUT,
|
||||||
EOF,
|
EOF,
|
||||||
FUN,
|
FUN,
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,9 @@
|
|||||||
use super::Expression;
|
use super::Expression;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Binding {
|
pub struct Binding {
|
||||||
Val(ValBinding),
|
|
||||||
Var(VarBinding),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct ValBinding {
|
|
||||||
pub datatype: Option<String>,
|
|
||||||
pub identifier: Box<String>,
|
|
||||||
pub expression: Expression,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct VarBinding {
|
|
||||||
pub datatype: Option<String>,
|
pub datatype: Option<String>,
|
||||||
pub identifier: Box<String>,
|
pub identifier: Box<String>,
|
||||||
pub expression: Expression,
|
pub expression: Expression,
|
||||||
|
pub is_mutable: bool,
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use super::ast::var_binding::{Binding, ValBinding, VarBinding};
|
use super::ast::var_binding::Binding;
|
||||||
use super::utils::{parse_token_type, try_operator};
|
use super::utils::{parse_token_type, try_operator};
|
||||||
use super::{expression, ParseResult};
|
use super::{expression, ParseResult};
|
||||||
use crate::error_handling::SyntaxError;
|
use crate::error_handling::SyntaxError;
|
||||||
@ -8,22 +8,22 @@ use crate::utils::Result3;
|
|||||||
pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<Binding, ()> {
|
pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<Binding, ()> {
|
||||||
let mut current_pos = pos;
|
let mut current_pos = pos;
|
||||||
|
|
||||||
|
// TODO: Detect if the binding starts with a datatype
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* val/var keyword
|
* let keyword
|
||||||
*/
|
*/
|
||||||
let (is_val, binding_token, next_pos) = {
|
let (is_mutable, binding_token, next_pos) = {
|
||||||
let res1 = parse_token_type(tokens, current_pos, TokenType::VAL);
|
let let_token = parse_token_type(tokens, current_pos, TokenType::LET);
|
||||||
match res1 {
|
match let_token {
|
||||||
ParseResult::Ok(val_token, next) => (true, val_token, next),
|
ParseResult::Ok(let_token, next_let) => {
|
||||||
_ => {
|
let mut_token = parse_token_type(tokens, next_let, TokenType::MUT);
|
||||||
let res2 = parse_token_type(tokens, current_pos, TokenType::VAR);
|
match mut_token {
|
||||||
match res2 {
|
ParseResult::Ok(_mut_token, next_mut) => (true, let_token, next_mut),
|
||||||
ParseResult::Ok(var_token, next) => (false, var_token, next),
|
_ => (false, let_token, next_let),
|
||||||
// Neither VAL nor VAR were matched, the caller should try
|
|
||||||
// other constructs
|
|
||||||
_ => return ParseResult::Unmatched,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_ => return ParseResult::Unmatched,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
current_pos = next_pos;
|
current_pos = next_pos;
|
||||||
@ -50,7 +50,7 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<Binding,
|
|||||||
return ParseResult::Err(SyntaxError {
|
return ParseResult::Err(SyntaxError {
|
||||||
reason: format!(
|
reason: format!(
|
||||||
"There should be an identifier after a `{}` token",
|
"There should be an identifier after a `{}` token",
|
||||||
if is_val { "val" } else { "var" }
|
if is_mutable { "val" } else { "var" }
|
||||||
),
|
),
|
||||||
error_start: binding_token.position,
|
error_start: binding_token.position,
|
||||||
error_end: binding_token.get_end_position(),
|
error_end: binding_token.get_end_position(),
|
||||||
@ -95,18 +95,11 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<Binding,
|
|||||||
};
|
};
|
||||||
current_pos = next_pos;
|
current_pos = next_pos;
|
||||||
|
|
||||||
let binding = if is_val {
|
let binding = Binding {
|
||||||
Binding::Val(ValBinding {
|
datatype: None,
|
||||||
datatype: None,
|
identifier: Box::new(identifier.value.clone()),
|
||||||
identifier: Box::new(identifier.value.clone()),
|
expression,
|
||||||
expression,
|
is_mutable,
|
||||||
})
|
|
||||||
} else {
|
|
||||||
Binding::Var(VarBinding {
|
|
||||||
datatype: None,
|
|
||||||
identifier: Box::new(identifier.value.clone()),
|
|
||||||
expression,
|
|
||||||
})
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ParseResult::Ok(binding, current_pos)
|
ParseResult::Ok(binding, current_pos)
|
||||||
@ -119,8 +112,8 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_parse_val_binding() {
|
fn should_parse_val_binding() {
|
||||||
let tokens = get_tokens(&String::from("val identifier = 20")).unwrap();
|
let tokens = get_tokens(&String::from("let identifier = 20")).unwrap();
|
||||||
let ParseResult::Ok(Binding::Val(binding), _) = try_parse(&tokens, 0) else {
|
let ParseResult::Ok(binding, _) = try_parse(&tokens, 0) else {
|
||||||
panic!()
|
panic!()
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -129,11 +122,11 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_parse_val() {
|
fn should_parse_val() {
|
||||||
let tokens = get_tokens(&String::from("val")).unwrap();
|
let tokens = get_tokens(&String::from("let")).unwrap();
|
||||||
let token = *try_token_type(&tokens, 0, TokenType::VAL).unwrap();
|
let token = *try_token_type(&tokens, 0, TokenType::LET).unwrap();
|
||||||
|
|
||||||
assert_eq!(TokenType::VAL, token.token_type);
|
assert_eq!(TokenType::LET, token.token_type);
|
||||||
assert_eq!("val", token.value);
|
assert_eq!("let", token.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -175,8 +168,8 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_return_correct_error() {
|
fn should_return_correct_error() {
|
||||||
let tokens = get_tokens(&String::from("val")).unwrap();
|
let tokens = get_tokens(&String::from("let")).unwrap();
|
||||||
assert_eq!(TokenType::VAL, tokens[0].token_type);
|
assert_eq!(TokenType::LET, tokens[0].token_type);
|
||||||
assert_eq!(0, tokens[0].position);
|
assert_eq!(0, tokens[0].position);
|
||||||
let binding = try_parse(&tokens, 0);
|
let binding = try_parse(&tokens, 0);
|
||||||
|
|
||||||
@ -191,8 +184,8 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_return_error_when_identifier_is_wrong() {
|
fn should_return_error_when_identifier_is_wrong() {
|
||||||
let tokens = get_tokens(&String::from("val 322")).unwrap();
|
let tokens = get_tokens(&String::from("let 322")).unwrap();
|
||||||
assert_eq!(TokenType::VAL, tokens[0].token_type);
|
assert_eq!(TokenType::LET, tokens[0].token_type);
|
||||||
assert_eq!(0, tokens[0].position);
|
assert_eq!(0, tokens[0].position);
|
||||||
let binding = try_parse(&tokens, 0);
|
let binding = try_parse(&tokens, 0);
|
||||||
|
|
||||||
@ -204,7 +197,7 @@ mod tests {
|
|||||||
_ => panic!("Error expected"),
|
_ => panic!("Error expected"),
|
||||||
}
|
}
|
||||||
|
|
||||||
let tokens = get_tokens(&String::from("val \"hello\"")).unwrap();
|
let tokens = get_tokens(&String::from("let \"hello\"")).unwrap();
|
||||||
let binding = try_parse(&tokens, 0);
|
let binding = try_parse(&tokens, 0);
|
||||||
|
|
||||||
match binding {
|
match binding {
|
||||||
@ -218,7 +211,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_return_error_when_equal_op_is_wrong() {
|
fn should_return_error_when_equal_op_is_wrong() {
|
||||||
let tokens = get_tokens(&String::from("val id \"error\"")).unwrap();
|
let tokens = get_tokens(&String::from("let id \"error\"")).unwrap();
|
||||||
let binding = try_parse(&tokens, 0);
|
let binding = try_parse(&tokens, 0);
|
||||||
|
|
||||||
match binding {
|
match binding {
|
||||||
|
@ -39,7 +39,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_parse_binding() {
|
fn should_parse_binding() {
|
||||||
let input = String::from("val identifier = 20");
|
let input = String::from("let identifier = 20");
|
||||||
let tokens = crate::lexic::get_tokens(&input).unwrap();
|
let tokens = crate::lexic::get_tokens(&input).unwrap();
|
||||||
let statement = try_parse(&tokens, 0);
|
let statement = try_parse(&tokens, 0);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user