Refactor AST location

master
Araozu 2023-09-07 20:50:51 -05:00
parent c0b5dde9cf
commit 94f0b0c92d
17 changed files with 125 additions and 256 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
target

View File

@ -1,5 +1,5 @@
use super::Transpilable;
use crate::ast_types::Binding;
use crate::syntax::ast::Binding;
impl Transpilable for Binding {
/// Transpiles val and var bindings into JS.
@ -22,7 +22,7 @@ impl Transpilable for Binding {
#[cfg(test)]
mod tests {
use super::*;
use crate::ast_types::{Binding, Expression, ValBinding};
use crate::syntax::ast::{Binding, Expression, ValBinding};
#[test]
fn binding_should_transpile() {

View File

@ -1,5 +1,5 @@
use super::Transpilable;
use crate::ast_types::Expression;
use crate::syntax::ast::Expression;
impl Transpilable for Expression {
/// Transpiles an Expression to JS
@ -24,7 +24,7 @@ impl Transpilable for Expression {
#[cfg(test)]
mod tests {
use super::*;
use crate::ast_types::Expression;
use crate::syntax::ast::Expression;
#[test]
fn should_transpile_number() {

View File

@ -1,4 +1,4 @@
use super::ast_types::ModuleAST;
use crate::syntax::ast::ModuleAST;
mod binding;
mod expression;
@ -25,7 +25,7 @@ mod tests {
fn should_codegen_1() {
let input = String::from("val id = 322");
let tokens = lexic::get_tokens(&input).unwrap();
let mut ast = syntax::construct_ast(&tokens).unwrap();
let ast = syntax::construct_ast(&tokens).unwrap();
let out_str = codegen(&ast);

View File

@ -1,5 +1,5 @@
use super::Transpilable;
use crate::ast_types::ModuleAST;
use crate::syntax::ast::ModuleAST;
impl Transpilable for ModuleAST {
/// Transpiles the whole AST into JS, using this same trait on the
@ -18,7 +18,7 @@ impl Transpilable for ModuleAST {
#[cfg(test)]
mod tests {
use super::*;
use crate::ast_types::{Binding, Expression, ValBinding};
use crate::syntax::ast::{Binding, Expression, ValBinding};
#[test]
fn module_ast_should_transpile() {

View File

@ -94,7 +94,7 @@ fn get_line(
mod tests {
use super::*;
use crate::{
error_handling::{MistiError, PrintableError, SyntaxError},
error_handling::{MistiError, PrintableError},
lexic::get_tokens,
syntax::construct_ast,
};

109
src/lexic/token.rs Executable file
View File

@ -0,0 +1,109 @@
#[derive(PartialEq, Debug, Clone)]
pub enum TokenType {
Identifier,
Datatype,
Number,
String,
Operator,
LeftParen,
RightParen,
LeftBracket,
RightBracket,
LeftBrace,
RightBrace,
Semicolon,
Comment,
VAR,
VAL,
EOF,
}
#[derive(Debug)]
pub struct Token {
pub token_type: TokenType,
// The token as a raw string
pub value: String,
/// The absolute position of this token, from the
/// start of the file
pub position: usize,
}
impl Token {
pub fn get_end_position(&self) -> usize {
self.position + self.value.len()
}
}
impl Token {
pub fn new_eof(position: usize) -> Token {
Token {
token_type: TokenType::EOF,
value: String::from(""),
position,
}
}
pub fn new_number(value: String, position: usize) -> Token {
Token {
token_type: TokenType::Number,
value,
position,
}
}
pub fn new_operator(value: String, position: usize) -> Token {
Token {
token_type: TokenType::Operator,
value,
position,
}
}
pub fn new(value: String, position: usize, token_type: TokenType) -> Token {
Token {
token_type,
value,
position,
}
}
pub fn new_identifier(value: String, position: usize) -> Token {
Token {
token_type: TokenType::Identifier,
value,
position,
}
}
pub fn new_string(value: String, position: usize) -> Token {
Token {
token_type: TokenType::String,
value,
position,
}
}
pub fn new_semicolon(position: usize) -> Token {
Token {
token_type: TokenType::Semicolon,
value: String::from(";"),
position,
}
}
pub fn new_datatype(value: String, position: usize) -> Token {
Token {
token_type: TokenType::Datatype,
value,
position,
}
}
pub fn new_comment(value: String, position: usize) -> Token {
Token {
token_type: TokenType::Comment,
value,
position,
}
}
}

View File

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

View File

@ -1,61 +0,0 @@
/// Represents a qualified datatype of the compiler.
///
/// A datatype is composed of a path, e.g. `base.Str`, `base.Num`
#[derive(PartialEq)]
pub struct Datatype {
t: String,
}
impl Datatype {
pub fn new(t: String) -> Datatype {
Datatype { t }
}
pub fn str() -> Datatype {
Datatype {
t: String::from("base.Str"),
}
}
pub fn num() -> Datatype {
Datatype {
t: String::from("base.Num"),
}
}
pub fn bool() -> Datatype {
Datatype {
t: String::from("base.Bool"),
}
}
pub fn clone(&self) -> Datatype {
Datatype { t: self.t.clone() }
}
}
#[cfg(test)]
mod tests {
use super::Datatype;
#[test]
fn should_create_datatype() {
let str = Datatype::new(String::from("base.Str"));
assert_eq!("base.Str", str.t);
}
#[test]
fn should_create_primitive_datatypes() {
assert_eq!("base.Str", Datatype::str().t);
assert_eq!("base.Num", Datatype::num().t);
assert_eq!("base.Bool", Datatype::bool().t);
}
#[test]
fn should_compare() {
let s1 = Datatype::str();
let s2 = Datatype::str();
assert_eq!(true, (s1 == s2));
}
}

View File

@ -1,15 +0,0 @@
# Semantic analysis
## Label checking
- Over all the bindings:
- Resolve references with the Symbol table
- If valid, insert reference into Symbol table
## Type checking
TODO
## Flow control check
TODO

View File

@ -1,101 +0,0 @@
use super::ast_types::{Binding, ModuleAST};
use super::symbol_table::SymbolTable;
mod datatype;
mod type_check;
use type_check::Typed;
pub use datatype::Datatype;
/// Checks the AST. In the future should return a list of errors.
pub fn check_ast<'a>(ast: &'a ModuleAST, symbol_table: &'a mut SymbolTable) {
for binding in ast.bindings.iter() {
match binding {
Binding::Val(b) => {
let datatype = b.expression.t(symbol_table);
let identifier = b.identifier;
// TODO: check datatype of a explicit datatype, e.g. `Str val x = 322`
symbol_table.insert(identifier.as_str(), datatype);
}
Binding::Var(b) => {
let datatype = b.expression.t(symbol_table);
let identifier = b.identifier;
// TODO: check datatype of a explicit datatype, e.g. `Str val x = 322`
symbol_table.insert(identifier.as_str(), datatype);
}
}
}
}
#[cfg(test)]
mod t {
use crate::ast_types::Expression;
use super::*;
#[test]
fn should_insert_into_symbol_table() {
let s1 = String::from("id");
let s2 = String::from("322");
let binding = Binding::Val(crate::ast_types::ValBinding {
datatype: None,
identifier: &s1,
expression: Expression::Number(&s2),
});
let mut table = SymbolTable::new();
check_ast(
&ModuleAST {
bindings: vec![binding],
},
&mut table,
);
assert!(table.has_id(&String::from("id")));
assert!(table.check_type(&String::from("id"), Datatype::num()));
}
#[test]
fn should_insert_id_reference() {
let s1 = String::from("id");
let s2 = String::from("322");
let binding = Binding::Val(crate::ast_types::ValBinding {
datatype: None,
identifier: &s1,
expression: Expression::Number(&s2),
});
let mut table = SymbolTable::new();
check_ast(
&ModuleAST {
bindings: vec![binding],
},
&mut table,
);
let s1 = String::from("id2");
let s2 = String::from("id");
let binding = Binding::Val(crate::ast_types::ValBinding {
datatype: None,
identifier: &s1,
expression: Expression::Identifier(&s2),
});
check_ast(
&ModuleAST {
bindings: vec![binding],
},
&mut table,
);
assert!(table.has_id(&String::from("id2")));
assert!(table.check_type(&String::from("id2"), Datatype::num()));
}
}

View File

@ -1,62 +0,0 @@
use crate::{ast_types::Expression, symbol_table::SymbolTable};
use super::datatype::Datatype;
pub trait Typed<'a> {
fn t(&self, symbol_table: &'a mut SymbolTable) -> Datatype;
}
impl<'a> Typed<'a> for Expression<'a> {
/// Returns the Datatype of this Expression
fn t(&self, symbol_table: &'a mut SymbolTable) -> Datatype {
match self {
Expression::Number(_) => Datatype::num(),
Expression::String(_) => Datatype::str(),
Expression::Boolean(_) => Datatype::bool(),
Expression::Identifier(id) => {
let res = symbol_table
.get_type(id)
.expect("SEMANTIC: identifier doesn't exist in Symbol table");
res.clone()
}
}
}
}
#[cfg(test)]
mod t {
use super::*;
#[test]
fn should_get_type_of_primitives() {
let mut t = SymbolTable::new();
let s = String::from("322");
let exp = Expression::Number(&s);
let datatype = exp.t(&mut t);
assert!(datatype == Datatype::num());
let s = String::from("hello");
let exp = Expression::String(&s);
let datatype = exp.t(&mut t);
assert!(datatype == Datatype::str());
let exp = Expression::Boolean(true);
let datatype = exp.t(&mut t);
assert!(datatype == Datatype::bool());
}
#[test]
fn shold_get_type_of_existing_id() {
let mut table = SymbolTable::new();
table.insert("my_number", Datatype::num());
let id = String::from("my_number");
let exp = Expression::Identifier(&id);
assert!(exp.t(&mut table) == Datatype::num());
}
}

View File

@ -1,4 +1,4 @@
use super::ast_types::{Binding, ValBinding, VarBinding};
use super::ast::{Binding, ValBinding, VarBinding};
use super::{expression, SyntaxResult};
use crate::error_handling::SyntaxError;
use crate::lexic::token::{Token, TokenType};

View File

@ -1,4 +1,4 @@
use super::ast_types::Expression;
use super::ast::Expression;
use crate::lexic::token::{Token, TokenType};
/// An expression can be:

View File

@ -1,13 +1,12 @@
use crate::ast_types::Binding;
use crate::error_handling::{MistiError, SyntaxError};
mod binding;
mod expression;
pub mod ast;
use super::ast_types;
use ast::{Binding, ModuleAST};
use crate::lexic::token::Token;
use ast_types::ModuleAST;
pub enum SyntaxResult {
///
@ -24,7 +23,7 @@ pub enum SyntaxResult {
/// Constructs the Misti AST from a vector of tokens
pub fn construct_ast<'a>(tokens: &'a Vec<Token>) -> Result<ModuleAST, MistiError> {
let _token_amount = tokens.len();
let mut current_pos = 0;
let current_pos = 0;
match next_construct(tokens, current_pos) {
SyntaxResult::Ok(module) => Ok(ModuleAST {

View File

@ -4,6 +4,7 @@ pub enum Result3<T> {
None,
}
#[allow(dead_code)]
impl<T> Result3<T> {
pub fn unwrap(&self) -> &T {
match self {