Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Type checker #96

Draft
wants to merge 13 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
182 changes: 128 additions & 54 deletions src/ast/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
use crate::lexer::*;
use core::convert::TryFrom;
use std::collections::HashMap;
/**
* Copyright 2021 Garrit Franke
*
Expand All @@ -16,17 +13,16 @@ use std::collections::HashMap;
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use crate::lexer::{self, Keyword, Position, Token, TokenKind, Value};
use core::convert::TryFrom;
use std::collections::HashMap;
use std::collections::HashSet;

pub mod types;
use types::Type;

/// Table that contains all symbol and its types
pub type SymbolTable = HashMap<String, Option<Type>>;

#[derive(Debug, Clone)]
pub struct Module {
pub path: String,
pub imports: HashSet<String>,
pub func: Vec<Function>,
pub structs: Vec<StructDef>,
Expand All @@ -39,35 +35,39 @@ impl Module {
self.structs.append(&mut other.structs);
self.globals.append(&mut other.globals)
}

pub fn get_symbol_table(&self) -> SymbolTable {
let mut table = SymbolTable::new();

for func in self.func.clone() {
table.insert(func.name, func.ret_type);
}

table
}
}

#[derive(Debug, Clone)]
pub struct Function {
pub struct Callable {
pub pos: Position,
pub name: String,
pub arguments: Vec<Variable>,
pub body: Statement,
pub arguments: Vec<TypedVariable>,
pub ret_type: Option<Type>,
}

#[derive(Debug, Clone)]
pub struct Function {
pub callable: Callable,
pub body: Option<Statement>,
}

#[derive(Debug, Clone)]
pub struct StructDef {
pub pos: Position,
pub name: String,
pub fields: Vec<Variable>,
pub methods: Vec<Function>,
pub fields: Vec<TypedVariable>,
pub methods: Vec<Method>,
}

#[derive(Debug, Clone)]
pub struct Method {
pub callable: Callable,
pub body: Statement,
}

#[derive(Debug, Eq, PartialEq, Clone)]
pub struct Variable {
pub pos: Position,
pub name: String,
pub ty: Option<Type>,
}
Expand All @@ -78,8 +78,37 @@ impl AsRef<Variable> for Variable {
}
}

impl From<TypedVariable> for Variable {
fn from(typed: TypedVariable) -> Self {
Self {
pos: typed.pos,
name: typed.name,
ty: Some(typed.ty),
}
}
}

#[derive(Debug, Eq, PartialEq, Clone)]
pub enum Statement {
pub struct TypedVariable {
pub pos: Position,
pub name: String,
pub ty: Type,
}

impl AsRef<TypedVariable> for TypedVariable {
fn as_ref(&self) -> &Self {
self
}
}

#[derive(Debug, Eq, PartialEq, Clone)]
pub struct Statement {
pub pos: Position,
pub kind: StatementKind,
}

#[derive(Debug, Eq, PartialEq, Clone)]
pub enum StatementKind {
/// (Statements, Scoped variables)
Block {
statements: Vec<Statement>,
Expand All @@ -91,6 +120,7 @@ pub enum Statement {
},
Assign {
lhs: Box<Expression>,
op: AssignOp,
rhs: Box<Expression>,
},
Return(Option<Expression>),
Expand All @@ -117,24 +147,58 @@ pub enum Statement {
Exp(Expression),
}

#[derive(Debug, Eq, PartialEq, Clone, Copy)]
pub enum AssignOp {
/// '='
Set,
/// '+='
Add,
/// '-='
Subtract,
/// '*='
Multiply,
/// '/='
Divide,
}

impl TryFrom<TokenKind> for AssignOp {
type Error = String;
fn try_from(token: TokenKind) -> Result<AssignOp, String> {
match token {
TokenKind::Assign => Ok(AssignOp::Set),
TokenKind::PlusEqual => Ok(AssignOp::Add),
TokenKind::MinusEqual => Ok(AssignOp::Subtract),
TokenKind::StarEqual => Ok(AssignOp::Multiply),
TokenKind::SlashEqual => Ok(AssignOp::Divide),
other => Err(format!(
"Token {:?} cannot be converted into an AssignOp",
other
)),
}
}
}

#[derive(Debug, Eq, PartialEq, Clone)]
pub enum Expression {
pub struct Expression {
pub pos: Position,
pub kind: ExpressionKind,
}

#[derive(Debug, Eq, PartialEq, Clone)]
pub enum ExpressionKind {
Int(usize),
Str(String),
Bool(bool),
/// Represents "self" keyword
Selff,
Array {
capacity: usize,
elements: Vec<Expression>,
},
Array(Vec<Expression>),
FunctionCall {
fn_name: String,
expr: Box<Expression>,
args: Vec<Expression>,
},
Variable(String),
ArrayAccess {
name: String,
expr: Box<Expression>,
index: Box<Expression>,
},
BinOp {
Expand All @@ -148,30 +212,48 @@ pub enum Expression {
},
FieldAccess {
expr: Box<Expression>,
field: Box<Expression>,
field: String,
},
}

impl TryFrom<Token> for Expression {
type Error = String;
type Error = lexer::Error;

fn try_from(token: Token) -> std::result::Result<Self, String> {
fn try_from(token: Token) -> lexer::Result<Self> {
let kind = token.kind;
let pos = token.pos;
match kind {
TokenKind::Identifier(val) => Ok(Expression::Variable(val)),
TokenKind::Literal(Value::Int) => Ok(Expression::Int(
token
.raw
.parse()
.map_err(|_| "Int value could not be parsed")?,
TokenKind::Identifier(val) => Ok(Expression {
pos,
kind: ExpressionKind::Variable(val),
}),
TokenKind::Literal(Value::Int) => Ok(Expression {
pos,
kind: ExpressionKind::Int(token.raw.parse().map_err(|_| {
lexer::Error::new(pos, "Int value could not be parsed".to_owned())
})?),
}),
TokenKind::Keyword(Keyword::Boolean) => Ok(Expression {
pos,
kind: ExpressionKind::Bool(match token.raw.as_ref() {
"true" => true,
"false" => false,
_ => {
return Err(lexer::Error::new(
pos,
"Boolean value could not be parsed".to_owned(),
))
}
}),
}),
TokenKind::Literal(Value::Str(string)) => Ok(Expression {
pos,
kind: ExpressionKind::Str(string),
}),
_ => Err(lexer::Error::new(
pos,
"Value could not be parsed".to_owned(),
)),
TokenKind::Keyword(Keyword::Boolean) => match token.raw.as_ref() {
"true" => Ok(Expression::Bool(true)),
"false" => Ok(Expression::Bool(false)),
_ => Err("Boolean value could not be parsed".into()),
},
TokenKind::Literal(Value::Str(string)) => Ok(Expression::Str(string)),
_ => Err("Value could not be parsed".into()),
}
}
}
Expand All @@ -197,10 +279,6 @@ pub enum BinOp {
NotEqual,
And,
Or,
AddAssign,
SubtractAssign,
MultiplyAssign,
DivideAssign,
}

impl TryFrom<TokenKind> for BinOp {
Expand All @@ -220,10 +298,6 @@ impl TryFrom<TokenKind> for BinOp {
TokenKind::NotEqual => Ok(BinOp::NotEqual),
TokenKind::And => Ok(BinOp::And),
TokenKind::Or => Ok(BinOp::Or),
TokenKind::PlusEqual => Ok(BinOp::AddAssign),
TokenKind::MinusEqual => Ok(BinOp::SubtractAssign),
TokenKind::StarEqual => Ok(BinOp::MultiplyAssign),
TokenKind::SlashEqual => Ok(BinOp::DivideAssign),
other => Err(format!(
"Token {:?} cannot be converted into a BinOp",
other
Expand Down
11 changes: 9 additions & 2 deletions src/ast/types.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::lexer::Position;
/**
* Copyright 2021 Garrit Franke
*
Expand All @@ -16,7 +17,13 @@
use std::convert::TryFrom;

#[derive(Debug, Eq, PartialEq, Clone)]
pub enum Type {
pub struct Type {
pub pos: Position,
pub kind: TypeKind,
}

#[derive(Debug, Eq, PartialEq, Clone)]
pub enum TypeKind {
Any,
Int,
Str,
Expand All @@ -25,7 +32,7 @@ pub enum Type {
Struct(String),
}

impl TryFrom<String> for Type {
impl TryFrom<String> for TypeKind {
type Error = String;
fn try_from(s: String) -> Result<Self, Self::Error> {
match s.as_ref() {
Expand Down
Loading
Loading