Compare commits

..

No commits in common. "83c0c59ae97ea9a4cf5d0ef88e867408c1074cdd" and "2184f7e654fab17f25569f323f14426a9d608a0b" have entirely different histories.

14 changed files with 29 additions and 182 deletions

View File

@ -4,13 +4,7 @@ use super::Transpilable;
impl Transpilable for FunctionCall { impl Transpilable for FunctionCall {
fn transpile(&self) -> String { fn transpile(&self) -> String {
let parameters = &self let parameters = &self.arguments.arguments.iter().map(|expr| expr.transpile()).collect::<Vec<_>>().join(", ");
.arguments
.arguments
.iter()
.map(|expr| expr.transpile())
.collect::<Vec<_>>()
.join(", ");
format!("{}({})", self.function.transpile(), parameters) format!("{}({})", self.function.transpile(), parameters)
} }

View File

@ -9,8 +9,6 @@ mod file;
mod syntax; mod syntax;
// Module to handle syntactic analysis // Module to handle syntactic analysis
mod lexic; mod lexic;
// Module to handle semantic analysis
mod semantic;
// Transforms an AST to JS // Transforms an AST to JS
mod codegen; mod codegen;
mod utils; mod utils;

View File

@ -1,55 +0,0 @@
mod symbol_table;
use symbol_table::{SymbolEntry, SymbolTable};
// What to do?
// 1. Create a mutable symbol table
// 2. Walk the AST
// 3. Add the symbols declared to the symbol table, annotating them with their type
// 4. Check if the symbols used are declared
#[cfg(test)]
mod tests {
use std::{borrow::BorrowMut, rc::Rc};
use super::*;
#[test]
fn test_1() {
let mut global_scope = SymbolTable::new();
let main_function = SymbolEntry::new_function(vec![], String::from("Unit"));
global_scope.insert("main".into(), main_function);
assert!(global_scope.test(&"main".into()));
}
#[test]
fn test_2() {
let global_scope = SymbolTable::new();
let main_function = SymbolEntry::new_function(vec![], String::from("Unit"));
global_scope.insert("main".into(), main_function);
global_scope.insert("db_url".into(), SymbolEntry::Variable("String".into()));
let add_function =
SymbolEntry::new_function(vec!["Int".into(), "Int".into()], "Int".into());
global_scope.insert("add".into(), add_function);
let main_function_scope = SymbolTable::new_from_parent(&global_scope);
main_function_scope.insert("message".into(), SymbolEntry::Variable("String".into()));
assert!(main_function_scope.test(&"message".into()));
assert!(main_function_scope.test(&"db_url".into()));
assert_eq!(main_function_scope.test(&"non_existant".into()), false);
let mut add_function_scope = SymbolTable::new_from_parent(&global_scope);
add_function_scope.insert("a".into(), SymbolEntry::Variable("Int".into()));
add_function_scope.insert("b".into(), SymbolEntry::Variable("Int".into()));
assert!(add_function_scope.test(&"a".into()));
global_scope.insert("test".into(), SymbolEntry::Variable("Int".into()));
}
}

View File

@ -1,96 +0,0 @@
use std::{cell::RefCell, collections::HashMap, rc::Rc};
/// Public interface for the symbol table
pub struct SymbolTable {
node: Rc<RefCell<SymbolTableNode>>,
}
// struct for a symbol table
struct SymbolTableNode {
// the parent scope
parent: Option<Rc<RefCell<SymbolTableNode>>>,
// the current scope
scope: HashMap<String, SymbolEntry>,
}
pub enum SymbolEntry {
// Just a Datatype
Variable(String),
// Contains: parameters, return type
Function(Vec<String>, String),
}
impl SymbolTable {
/// Creates a new, global symbol table
pub fn new() -> SymbolTable {
SymbolTable {
node: Rc::new(RefCell::new(SymbolTableNode::new())),
}
}
pub fn new_from_parent(parent: &SymbolTable) -> SymbolTable {
let new_table = SymbolTableNode::new_from_parent(&parent.node);
SymbolTable {
node: Rc::new(RefCell::new(new_table)),
}
}
/// Inserts a new symbol into the current table scope
pub fn insert(&self, key: String, value: SymbolEntry) {
self.node.borrow_mut().insert(key, value);
}
/// Tests if a symbol is declared in the current or parent scopes
pub fn test(&self, key: &String) -> bool {
self.node.borrow_mut().test(key)
}
}
impl SymbolTableNode {
/// Creates a new, global symbol table
pub fn new<'a>() -> SymbolTableNode {
SymbolTableNode {
parent: None,
scope: HashMap::new(),
}
}
/// Creates a new symbol table with a parent
pub fn new_from_parent<'a>(parent: &Rc<RefCell<SymbolTableNode>>) -> SymbolTableNode {
SymbolTableNode {
parent: Some(Rc::clone(&parent)),
scope: HashMap::new(),
}
}
/// Inserts a new symbol into the current scope
pub fn insert(&mut self, key: String, value: SymbolEntry) {
self.scope.insert(key, value);
}
/// Tests if a symbol is declared in the current or parent scopes
pub fn test(&mut self, key: &String) -> bool {
if self.scope.contains_key(key) {
return true;
}
match &self.parent {
Some(parent) => {
let mut parent = parent.as_ref().borrow_mut();
parent.test(key)
}
None => false,
}
}
}
impl SymbolEntry {
pub fn new_variable(datatype: String) -> SymbolEntry {
SymbolEntry::Variable(datatype)
}
pub fn new_function(parameters: Vec<String>, return_type: String) -> SymbolEntry {
SymbolEntry::Function(parameters, return_type)
}
}

View File

@ -10,3 +10,4 @@ pub struct FunctionCall {
pub struct ArgumentsList { pub struct ArgumentsList {
pub arguments: Vec<Expression>, pub arguments: Vec<Expression>,
} }

View File

@ -114,7 +114,7 @@ mod tests {
ParseResult::Ok(p, _) => p, ParseResult::Ok(p, _) => p,
_ => { _ => {
panic!("Expected a block, got: {:?}\n\n{:?}", block, tokens) panic!("Expected a block, got: {:?}\n\n{:?}", block, tokens)
} },
}; };
assert_eq!(block.statements.len(), 1); assert_eq!(block.statements.len(), 1);

View File

@ -1,7 +1,10 @@
use crate::{ use crate::{
lexic::token::Token, lexic::token::Token,
syntax::{ syntax::{
ast::{functions::FunctionCall, Expression}, ast::{
functions::{ArgumentsList, FunctionCall},
Expression,
},
functions::arguments_list, functions::arguments_list,
ParseResult, ParseResult,
}, },

View File

@ -14,5 +14,8 @@ pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression, ()>
return equality::try_parse(tokens, pos); return equality::try_parse(tokens, pos);
} }
#[cfg(test)] #[cfg(test)]
mod tests {} mod tests {
}

View File

@ -1,8 +1,8 @@
use super::super::utils::Tokenizer;
use crate::{ use crate::{
lexic::token::{Token, TokenType}, lexic::token::{Token, TokenType},
syntax::{ast::Expression, ParseResult}, syntax::{ast::Expression, ParseResult},
}; };
use super::super::utils::Tokenizer;
/// This grammar may not be up to date. Refer to the spec for the latest grammar. /// This grammar may not be up to date. Refer to the spec for the latest grammar.
/// ///
@ -12,14 +12,12 @@ use crate::{
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression, ()> { pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression, ()> {
match tokens.get_significant(pos) { match tokens.get_significant(pos) {
Some((token, token_pos)) => match token.token_type { Some((token, token_pos)) => match token.token_type {
TokenType::Number => ParseResult::Ok( TokenType::Number => {
Expression::Number(Box::new(token.value.clone())), ParseResult::Ok(Expression::Number(Box::new(token.value.clone())), token_pos + 1)
token_pos + 1, }
), TokenType::String => {
TokenType::String => ParseResult::Ok( ParseResult::Ok(Expression::String(Box::new(token.value.clone())), token_pos + 1)
Expression::String(Box::new(token.value.clone())), }
token_pos + 1,
),
TokenType::Identifier if token.value == "true" || token.value == "false" => { TokenType::Identifier if token.value == "true" || token.value == "false" => {
ParseResult::Ok(Expression::Boolean(token.value == "true"), token_pos + 1) ParseResult::Ok(Expression::Boolean(token.value == "true"), token_pos + 1)
} }

View File

@ -79,6 +79,8 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<Argument
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::net;
use super::*; use super::*;
use crate::lexic::get_tokens; use crate::lexic::get_tokens;
@ -121,6 +123,7 @@ mod tests {
assert_eq!(list.arguments.len(), 0); assert_eq!(list.arguments.len(), 0);
} }
#[test] #[test]
fn should_parse_one_argument() { fn should_parse_one_argument() {
let tokens = get_tokens(&String::from("(0)")).unwrap(); let tokens = get_tokens(&String::from("(0)")).unwrap();
@ -139,7 +142,7 @@ mod tests {
panic!("Expected a number") panic!("Expected a number")
}; };
} }
#[test] #[test]
fn should_parse_one_argument_with_trailing_comma() { fn should_parse_one_argument_with_trailing_comma() {
let tokens = get_tokens(&String::from("(0, )")).unwrap(); let tokens = get_tokens(&String::from("(0, )")).unwrap();

View File

@ -4,14 +4,12 @@ use crate::{
utils::Result3, utils::Result3,
}; };
use super::{ use super::super::{
super::{ ast::FunctionDeclaration,
ast::FunctionDeclaration, block::parse_block,
block::parse_block,
utils::{parse_token_type, try_token_type},
ParseResult,
},
params_list::parse_params_list, params_list::parse_params_list,
utils::{parse_token_type, try_token_type},
ParseResult,
}; };
pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<FunctionDeclaration, ()> { pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<FunctionDeclaration, ()> {

View File

@ -1,4 +1,3 @@
pub mod arguments_list; pub mod arguments_list;
pub mod function_declaration; pub mod function_declaration;
pub mod params_list;

View File

@ -4,6 +4,7 @@ mod binding;
mod block; mod block;
mod expression; mod expression;
mod functions; mod functions;
mod params_list;
mod statement; mod statement;
mod utils; mod utils;

View File

@ -4,7 +4,7 @@ use crate::{
syntax::utils::parse_token_type, syntax::utils::parse_token_type,
}; };
use super::super::{ use super::{
ast::{Parameter, ParamsList}, ast::{Parameter, ParamsList},
utils, ParseResult, utils, ParseResult,
}; };