Refactor AST location
This commit is contained in:
parent
c0b5dde9cf
commit
94f0b0c92d
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
target
|
@ -1,5 +1,5 @@
|
|||||||
use super::Transpilable;
|
use super::Transpilable;
|
||||||
use crate::ast_types::Binding;
|
use crate::syntax::ast::Binding;
|
||||||
|
|
||||||
impl Transpilable for Binding {
|
impl Transpilable for Binding {
|
||||||
/// Transpiles val and var bindings into JS.
|
/// Transpiles val and var bindings into JS.
|
||||||
@ -22,7 +22,7 @@ impl Transpilable for Binding {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::ast_types::{Binding, Expression, ValBinding};
|
use crate::syntax::ast::{Binding, Expression, ValBinding};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn binding_should_transpile() {
|
fn binding_should_transpile() {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use super::Transpilable;
|
use super::Transpilable;
|
||||||
use crate::ast_types::Expression;
|
use crate::syntax::ast::Expression;
|
||||||
|
|
||||||
impl Transpilable for Expression {
|
impl Transpilable for Expression {
|
||||||
/// Transpiles an Expression to JS
|
/// Transpiles an Expression to JS
|
||||||
@ -24,7 +24,7 @@ impl Transpilable for Expression {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::ast_types::Expression;
|
use crate::syntax::ast::Expression;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_transpile_number() {
|
fn should_transpile_number() {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use super::ast_types::ModuleAST;
|
use crate::syntax::ast::ModuleAST;
|
||||||
|
|
||||||
mod binding;
|
mod binding;
|
||||||
mod expression;
|
mod expression;
|
||||||
@ -25,7 +25,7 @@ mod tests {
|
|||||||
fn should_codegen_1() {
|
fn should_codegen_1() {
|
||||||
let input = String::from("val id = 322");
|
let input = String::from("val id = 322");
|
||||||
let tokens = lexic::get_tokens(&input).unwrap();
|
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);
|
let out_str = codegen(&ast);
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use super::Transpilable;
|
use super::Transpilable;
|
||||||
use crate::ast_types::ModuleAST;
|
use crate::syntax::ast::ModuleAST;
|
||||||
|
|
||||||
impl Transpilable for ModuleAST {
|
impl Transpilable for ModuleAST {
|
||||||
/// Transpiles the whole AST into JS, using this same trait on the
|
/// Transpiles the whole AST into JS, using this same trait on the
|
||||||
@ -18,7 +18,7 @@ impl Transpilable for ModuleAST {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::ast_types::{Binding, Expression, ValBinding};
|
use crate::syntax::ast::{Binding, Expression, ValBinding};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn module_ast_should_transpile() {
|
fn module_ast_should_transpile() {
|
||||||
|
@ -94,7 +94,7 @@ fn get_line(
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
error_handling::{MistiError, PrintableError, SyntaxError},
|
error_handling::{MistiError, PrintableError},
|
||||||
lexic::get_tokens,
|
lexic::get_tokens,
|
||||||
syntax::construct_ast,
|
syntax::construct_ast,
|
||||||
};
|
};
|
||||||
|
109
src/lexic/token.rs
Executable file
109
src/lexic/token.rs
Executable 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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -8,8 +8,6 @@ mod file;
|
|||||||
mod syntax;
|
mod syntax;
|
||||||
// Module to handle syntactic analysis
|
// Module to handle syntactic analysis
|
||||||
mod lexic;
|
mod lexic;
|
||||||
// Defines the AST
|
|
||||||
mod ast_types;
|
|
||||||
// Transforms an AST to JS
|
// Transforms an AST to JS
|
||||||
mod codegen;
|
mod codegen;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
@ -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));
|
|
||||||
}
|
|
||||||
}
|
|
@ -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
|
|
@ -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()));
|
|
||||||
}
|
|
||||||
}
|
|
@ -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());
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
use super::ast_types::{Binding, ValBinding, VarBinding};
|
use super::ast::{Binding, ValBinding, VarBinding};
|
||||||
use super::{expression, SyntaxResult};
|
use super::{expression, SyntaxResult};
|
||||||
use crate::error_handling::SyntaxError;
|
use crate::error_handling::SyntaxError;
|
||||||
use crate::lexic::token::{Token, TokenType};
|
use crate::lexic::token::{Token, TokenType};
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use super::ast_types::Expression;
|
use super::ast::Expression;
|
||||||
use crate::lexic::token::{Token, TokenType};
|
use crate::lexic::token::{Token, TokenType};
|
||||||
|
|
||||||
/// An expression can be:
|
/// An expression can be:
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
use crate::ast_types::Binding;
|
|
||||||
use crate::error_handling::{MistiError, SyntaxError};
|
use crate::error_handling::{MistiError, SyntaxError};
|
||||||
|
|
||||||
mod binding;
|
mod binding;
|
||||||
mod expression;
|
mod expression;
|
||||||
|
pub mod ast;
|
||||||
|
|
||||||
use super::ast_types;
|
use ast::{Binding, ModuleAST};
|
||||||
use crate::lexic::token::Token;
|
use crate::lexic::token::Token;
|
||||||
|
|
||||||
use ast_types::ModuleAST;
|
|
||||||
|
|
||||||
pub enum SyntaxResult {
|
pub enum SyntaxResult {
|
||||||
///
|
///
|
||||||
@ -24,7 +23,7 @@ pub enum SyntaxResult {
|
|||||||
/// Constructs the Misti AST from a vector of tokens
|
/// Constructs the Misti AST from a vector of tokens
|
||||||
pub fn construct_ast<'a>(tokens: &'a Vec<Token>) -> Result<ModuleAST, MistiError> {
|
pub fn construct_ast<'a>(tokens: &'a Vec<Token>) -> Result<ModuleAST, MistiError> {
|
||||||
let _token_amount = tokens.len();
|
let _token_amount = tokens.len();
|
||||||
let mut current_pos = 0;
|
let current_pos = 0;
|
||||||
|
|
||||||
match next_construct(tokens, current_pos) {
|
match next_construct(tokens, current_pos) {
|
||||||
SyntaxResult::Ok(module) => Ok(ModuleAST {
|
SyntaxResult::Ok(module) => Ok(ModuleAST {
|
||||||
|
@ -4,6 +4,7 @@ pub enum Result3<T> {
|
|||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
impl<T> Result3<T> {
|
impl<T> Result3<T> {
|
||||||
pub fn unwrap(&self) -> &T {
|
pub fn unwrap(&self) -> &T {
|
||||||
match self {
|
match self {
|
||||||
|
Loading…
Reference in New Issue
Block a user