moved to workspaces
This commit is contained in:
parent
79975ffcba
commit
7c0dc98ef7
16 changed files with 91 additions and 103 deletions
8
crates/akailang-parser/Cargo.toml
Normal file
8
crates/akailang-parser/Cargo.toml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "akailang-parser"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
[dependencies]
|
||||
logos = "0.15.0"
|
||||
chumsky = "0.10.1"
|
||||
49
crates/akailang-parser/src/abstract_syntax_tree/ast.rs
Normal file
49
crates/akailang-parser/src/abstract_syntax_tree/ast.rs
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
use crate::abstract_syntax_tree::definitions::*;
|
||||
|
||||
// Option and Result -> define in Std
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Expr {
|
||||
// var/fun_name
|
||||
Ident(Identifier),
|
||||
|
||||
// 4
|
||||
IntLiteral(i64),
|
||||
|
||||
// 12.5
|
||||
FloatLiteral(f64),
|
||||
|
||||
// "eepy"
|
||||
StringLiteral(String),
|
||||
|
||||
// true
|
||||
BoolLiteral(bool),
|
||||
|
||||
// 'c'
|
||||
CharLiteral(char),
|
||||
|
||||
// var x = intPlusOne(12)
|
||||
CallExpr(Call),
|
||||
|
||||
// !x
|
||||
UnaryExpr(Unary),
|
||||
|
||||
// 1 + 11
|
||||
BinaryExpr(Binary),
|
||||
|
||||
// x = 64
|
||||
AssignmentExpr(Assignment),
|
||||
|
||||
// var foo = "bar"
|
||||
VarExpr(Var),
|
||||
|
||||
// if(...) { ... } else { ... }
|
||||
Condition(Condition),
|
||||
|
||||
// fun helloWorld() { ... }
|
||||
FunctionExpr(Function),
|
||||
|
||||
// ->
|
||||
ReturnExpr,
|
||||
|
||||
Error,
|
||||
}
|
||||
161
crates/akailang-parser/src/abstract_syntax_tree/definitions.rs
Normal file
161
crates/akailang-parser/src/abstract_syntax_tree/definitions.rs
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
use std::{ops::Range, rc::Rc};
|
||||
|
||||
use crate::abstract_syntax_tree::ast::Expr;
|
||||
|
||||
// Abstract Syntax Tree
|
||||
|
||||
pub type BlockExpression = Vec<Expr>;
|
||||
|
||||
pub type Span = Range<usize>;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum BinaryOp {
|
||||
// Arithmetic
|
||||
Multiply,
|
||||
Divide,
|
||||
Add,
|
||||
Substract,
|
||||
|
||||
// Comparision
|
||||
Equals,
|
||||
NotEquals,
|
||||
Less,
|
||||
LessEquals,
|
||||
Greater,
|
||||
GreaterEquals,
|
||||
|
||||
// Logical
|
||||
And,
|
||||
Or,
|
||||
// todo: bitwise
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum UnaryOp {
|
||||
Not,
|
||||
Negate,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Literal {
|
||||
UnsignedInteger(u64),
|
||||
Bool(bool),
|
||||
Char(char),
|
||||
String(Rc<str>),
|
||||
Int(i64),
|
||||
Float(f64),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Type {
|
||||
Integer,
|
||||
Float,
|
||||
Bool,
|
||||
Char,
|
||||
String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Value {
|
||||
Integer(i64),
|
||||
Float(f64),
|
||||
Bool(bool),
|
||||
Char(char),
|
||||
String(String),
|
||||
}
|
||||
|
||||
impl Value {
|
||||
pub fn is_type(&self, ty: &Type) -> bool {
|
||||
match (ty, self) {
|
||||
(Type::Bool, Value::Bool(_)) => true,
|
||||
(Type::Char, Value::Char(_)) => true,
|
||||
(Type::Integer, Value::Integer(_)) => true,
|
||||
(Type::Float, Value::Float(_)) => true,
|
||||
(Type::String, Value::String(_)) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------
|
||||
// Structs
|
||||
//---------------------------------------
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Identifier(pub String);
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct While {
|
||||
pub condition: Box<Expr>,
|
||||
pub body: BlockExpression,
|
||||
}
|
||||
|
||||
/// Example: `if (a > 12) { ... }`
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Condition {
|
||||
pub condition: Box<Expr>,
|
||||
pub if_body: BlockExpression,
|
||||
pub else_body: Option<BlockExpression>,
|
||||
}
|
||||
|
||||
/// Example: `x = y`
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Assignment {
|
||||
pub target: String,
|
||||
pub value: Box<Expr>,
|
||||
}
|
||||
|
||||
/// Example: `var String: foo = "Test"`
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Var {
|
||||
pub ty: Option<Type>,
|
||||
pub ident: Identifier,
|
||||
pub value: Box<Expr>,
|
||||
}
|
||||
|
||||
/// Example: `x++`
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Unary {
|
||||
pub operator: UnaryOp,
|
||||
pub operand: Box<Expr>,
|
||||
}
|
||||
|
||||
/// Example: `1 + 1`
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Binary {
|
||||
pub lhs: Box<Expr>,
|
||||
pub operator: BinaryOp,
|
||||
pub rhs: Box<Expr>,
|
||||
}
|
||||
|
||||
/// Represents the Structure of a `Function` in AkaiLang
|
||||
///
|
||||
/// Examples:
|
||||
///```AkaiLang
|
||||
///fun helloWorld() {
|
||||
/// print("Hello World")
|
||||
///}
|
||||
///```
|
||||
/// <br>
|
||||
///
|
||||
///```AkaiLang
|
||||
///fun returnsIntPlusOne(i: int): int {
|
||||
/// -> i + 1
|
||||
///}
|
||||
///```
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Function {
|
||||
pub name: String,
|
||||
pub params: Option<Vec<(String, Type)>>,
|
||||
pub return_type: Option<Type>,
|
||||
pub body: Option<BlockExpression>,
|
||||
pub return_expr: Box<Option<Expr>>, // ' -> (return)'
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Call {
|
||||
/// name of the function being called
|
||||
pub name: Box<Identifier>,
|
||||
|
||||
/// arguments supplied
|
||||
pub arguments: Vec<Expr>,
|
||||
}
|
||||
52
crates/akailang-parser/src/abstract_syntax_tree/mod.rs
Normal file
52
crates/akailang-parser/src/abstract_syntax_tree/mod.rs
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
pub mod ast;
|
||||
pub mod definitions;
|
||||
pub mod parser;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! token {
|
||||
(var) => {
|
||||
just(Token::Var)
|
||||
};
|
||||
(=) => {
|
||||
just(Token::Assign)
|
||||
};
|
||||
(if) => {
|
||||
just(Token::If)
|
||||
};
|
||||
(else) => {
|
||||
just(Token::Else)
|
||||
};
|
||||
(->) => {
|
||||
just(Token::Return)
|
||||
};
|
||||
(:) => {
|
||||
just(Token::Colon)
|
||||
};
|
||||
(,) => {
|
||||
just(Token::Comma)
|
||||
};
|
||||
(*) => {
|
||||
just(Token::Multiply)
|
||||
};
|
||||
(/) => {
|
||||
just(Token::Divide)
|
||||
};
|
||||
(+) => {
|
||||
just(Token::Add)
|
||||
};
|
||||
(-) => {
|
||||
just(Token::Substract)
|
||||
};
|
||||
(lp) => {
|
||||
just(Token::LParen)
|
||||
};
|
||||
(rp) => {
|
||||
just(Token::RParen)
|
||||
};
|
||||
(lbrace) => {
|
||||
just(Token::LBrace)
|
||||
};
|
||||
(rbrace) => {
|
||||
just(Token::RBrace)
|
||||
};
|
||||
}
|
||||
324
crates/akailang-parser/src/abstract_syntax_tree/parser.rs
Normal file
324
crates/akailang-parser/src/abstract_syntax_tree/parser.rs
Normal file
|
|
@ -0,0 +1,324 @@
|
|||
use chumsky::{
|
||||
Boxed, ConfigIterParser, IterParser, ParseResult, Parser,
|
||||
combinator::Or,
|
||||
container::Seq,
|
||||
error::{Rich, Simple},
|
||||
extra,
|
||||
input::{Input, Stream, ValueInput},
|
||||
prelude::{choice, end, just, nested_delimiters, recursive, skip_then_retry_until, via_parser},
|
||||
primitive::select,
|
||||
recursive, select, select_ref,
|
||||
span::{self, SimpleSpan},
|
||||
text::{
|
||||
self,
|
||||
ascii::{ident, keyword},
|
||||
newline, whitespace,
|
||||
},
|
||||
};
|
||||
use logos::{Logos, source};
|
||||
|
||||
use crate::{
|
||||
token,
|
||||
{
|
||||
abstract_syntax_tree::{ast::Expr, definitions::*},
|
||||
lexer::tokens::Token,
|
||||
},
|
||||
};
|
||||
|
||||
// goal of parsing is to construct an abstract syntax tree
|
||||
|
||||
pub fn parse(source: &str) -> Result<Vec<Expr>, Vec<Rich<'_, Token>>> {
|
||||
let token_iter = Token::lexer(source)
|
||||
.spanned()
|
||||
.map(|(token, span)| (token.unwrap_or(Token::Error), span.into()));
|
||||
let end_of_input: SimpleSpan = (0..source.len()).into();
|
||||
let token_stream = Stream::from_iter(token_iter).map(
|
||||
(0..end_of_input.into_iter().len()).into(),
|
||||
|(t, s): (_, _)| (t, s),
|
||||
);
|
||||
|
||||
parser().parse(token_stream).into_result()
|
||||
}
|
||||
|
||||
fn parser<'src, I>() -> impl Parser<'src, I, Vec<Expr>, extra::Err<Rich<'src, Token>>>
|
||||
where
|
||||
I: ValueInput<'src, Token = Token, Span = SimpleSpan>,
|
||||
{
|
||||
let ident = select! { Token::Identifier(s) => s, }.labelled("identifier");
|
||||
|
||||
let expr = recursive(|expr| {
|
||||
let atom = select! {
|
||||
Token::FloatLiteral(x) => Expr::FloatLiteral(x),
|
||||
Token::IntLiteral(x) => Expr::IntLiteral(x),
|
||||
Token::BoolLiteral(x) => Expr::BoolLiteral(x),
|
||||
Token::StringLiteral(s) => Expr::StringLiteral(s),
|
||||
}
|
||||
.labelled("value")
|
||||
.or(expr.clone().delimited_by(token!(lp), token!(rp)));
|
||||
|
||||
// Product
|
||||
let mul_div = atom.clone().foldl(
|
||||
choice((
|
||||
token!(*).to(BinaryOp::Multiply),
|
||||
token!(/).to(BinaryOp::Divide),
|
||||
))
|
||||
.then(atom)
|
||||
.then_ignore(just(Token::NewLine).or_not())
|
||||
.repeated(),
|
||||
|lhs, (op, rhs)| {
|
||||
Expr::BinaryExpr(Binary {
|
||||
lhs: Box::new(lhs),
|
||||
operator: op,
|
||||
rhs: Box::new(rhs),
|
||||
})
|
||||
},
|
||||
);
|
||||
|
||||
// Sum
|
||||
let add_sub = mul_div.clone().foldl(
|
||||
choice((
|
||||
token!(+).to(BinaryOp::Add),
|
||||
token!(-).to(BinaryOp::Substract),
|
||||
))
|
||||
.then(mul_div)
|
||||
.then_ignore(just(Token::NewLine).or_not())
|
||||
.repeated(),
|
||||
|lhs, (op, rhs)| {
|
||||
Expr::BinaryExpr(Binary {
|
||||
lhs: Box::new(lhs),
|
||||
operator: op,
|
||||
rhs: Box::new(rhs),
|
||||
})
|
||||
},
|
||||
);
|
||||
|
||||
let assign_expr = ident
|
||||
.then_ignore(token!(=))
|
||||
.then(expr.clone())
|
||||
.map(|(name, value)| {
|
||||
Expr::AssignmentExpr(Assignment {
|
||||
target: name,
|
||||
value: Box::new(value),
|
||||
})
|
||||
});
|
||||
|
||||
assign_expr.or(add_sub)
|
||||
});
|
||||
|
||||
let decl = recursive(|decl| {
|
||||
let var = token!(var)
|
||||
.ignore_then(ident)
|
||||
.then_ignore(token!(=))
|
||||
.then(expr.clone())
|
||||
.then_ignore(just(Token::NewLine).or_not())
|
||||
.map(|(name, rhs)| {
|
||||
Expr::VarExpr(Var {
|
||||
ty: None,
|
||||
ident: Identifier(String::from(name)),
|
||||
value: Box::new(rhs),
|
||||
})
|
||||
});
|
||||
|
||||
let type_parser = choice((
|
||||
just(Token::IntType).to(Type::Integer),
|
||||
just(Token::FloatType).to(Type::Float),
|
||||
just(Token::BoolType).to(Type::Bool),
|
||||
just(Token::StringType).to(Type::String),
|
||||
));
|
||||
|
||||
let return_type_parser = token!(:).ignore_then(type_parser.clone()).or_not();
|
||||
|
||||
let return_expr = token!(->).ignore_then(expr.clone()).map(|expr| expr);
|
||||
|
||||
//---------------------------------------------------------------------------------------
|
||||
// Function Parser
|
||||
//---------------------------------------------------------------------------------------
|
||||
let fun = just(Token::Fun)
|
||||
.ignore_then(ident) // function name
|
||||
.then(
|
||||
// arguments
|
||||
ident
|
||||
.then_ignore(token!(:))
|
||||
.then(type_parser.clone())
|
||||
.separated_by(token!(,))
|
||||
.allow_trailing()
|
||||
.collect::<Vec<_>>()
|
||||
.delimited_by(token!(lp), token!(rp))
|
||||
.or_not(),
|
||||
)
|
||||
.then(return_type_parser.clone()) // return type
|
||||
.then_ignore(token!(lbrace)) // {
|
||||
.then_ignore(just(Token::NewLine).repeated().or_not())
|
||||
.then(
|
||||
expr.clone()
|
||||
.then_ignore(just(Token::NewLine))
|
||||
.repeated()
|
||||
.collect::<Vec<Expr>>()
|
||||
.then(return_expr.or_not()),
|
||||
)
|
||||
.then_ignore(just(Token::NewLine).repeated().or_not())
|
||||
.then_ignore(token!(rbrace)) // }
|
||||
.map(|(((name, params), return_ty), (stmts, return_value))| {
|
||||
Expr::FunctionExpr(Function {
|
||||
name: name,
|
||||
params,
|
||||
return_type: return_ty,
|
||||
body: Some(stmts),
|
||||
return_expr: Box::new(return_value),
|
||||
})
|
||||
});
|
||||
|
||||
var.or(fun).or(expr)
|
||||
});
|
||||
|
||||
decl.clone()
|
||||
.then_ignore(just(Token::NewLine).repeated())
|
||||
.repeated()
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_unary_expr() {
|
||||
let negate_two = parse("!2");
|
||||
assert!(negate_two.is_ok());
|
||||
assert_eq!(
|
||||
negate_two.clone().unwrap(),
|
||||
vec![Expr::UnaryExpr(Unary {
|
||||
operator: UnaryOp::Negate,
|
||||
operand: Box::new(Expr::IntLiteral(2)),
|
||||
})]
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bool() {
|
||||
let var_bool = parse("var isUwU = true");
|
||||
assert!(var_bool.is_ok());
|
||||
assert_eq!(
|
||||
var_bool.clone().unwrap(),
|
||||
vec![Expr::VarExpr(Var {
|
||||
ty: None,
|
||||
ident: Identifier(String::from("isUwU")),
|
||||
value: Box::new(Expr::BoolLiteral(true))
|
||||
})]
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_binary_expr() {
|
||||
let sum = parse("1 + 2");
|
||||
assert!(sum.is_ok());
|
||||
assert_eq!(
|
||||
sum.clone().unwrap(),
|
||||
vec![Expr::BinaryExpr(Binary {
|
||||
lhs: Box::new(Expr::IntLiteral(1)),
|
||||
operator: BinaryOp::Add,
|
||||
rhs: Box::new(Expr::IntLiteral(2))
|
||||
})]
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_variable_decl() {
|
||||
let var_without_expl_type = parse("var x = 12");
|
||||
assert!(var_without_expl_type.is_ok());
|
||||
assert_eq!(
|
||||
var_without_expl_type.clone().unwrap(),
|
||||
vec![Expr::VarExpr(Var {
|
||||
ty: None,
|
||||
ident: Identifier(String::from("x")),
|
||||
value: Box::new(Expr::IntLiteral(12))
|
||||
})]
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_assignment() {
|
||||
let assign = parse("x = 12");
|
||||
assert!(assign.is_ok());
|
||||
assert_eq!(
|
||||
assign.clone().unwrap(),
|
||||
vec![Expr::AssignmentExpr(Assignment {
|
||||
target: String::from("x"),
|
||||
value: Box::new(Expr::IntLiteral(12))
|
||||
})]
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_function_decl() {
|
||||
// test without a body or args
|
||||
let empty_fun = parse("fun helloWorld() { }");
|
||||
assert!(empty_fun.is_ok());
|
||||
assert_eq!(
|
||||
empty_fun.clone().unwrap(),
|
||||
vec![Expr::FunctionExpr(Function {
|
||||
name: String::from("helloWorld"),
|
||||
params: Some([].to_vec()),
|
||||
return_type: None,
|
||||
body: Some([].to_vec()),
|
||||
return_expr: Box::new(None),
|
||||
})]
|
||||
);
|
||||
|
||||
// tests if empty new lines within a function works
|
||||
let empty_fun_with_new_lines = parse(
|
||||
r"fun emptyMulLines() {
|
||||
|
||||
}
|
||||
",
|
||||
);
|
||||
assert_eq!(
|
||||
empty_fun_with_new_lines.clone().unwrap(),
|
||||
vec![Expr::FunctionExpr(Function {
|
||||
name: String::from("emptyMulLines"),
|
||||
params: Some([].to_vec()),
|
||||
return_type: None,
|
||||
body: Some([].to_vec()),
|
||||
return_expr: Box::new(None),
|
||||
})]
|
||||
);
|
||||
|
||||
// tests for return expr in functions
|
||||
let fun_that_returns_int = parse(
|
||||
r"fun returnsInt(): int {
|
||||
-> 12
|
||||
}
|
||||
",
|
||||
);
|
||||
assert_eq!(
|
||||
fun_that_returns_int.clone().unwrap(),
|
||||
vec![Expr::FunctionExpr(Function {
|
||||
name: String::from("returnsInt"),
|
||||
params: Some([].to_vec()),
|
||||
return_type: Some(Type::Integer),
|
||||
body: Some([].to_vec()),
|
||||
return_expr: Box::new(Some(Expr::IntLiteral(12))),
|
||||
})]
|
||||
);
|
||||
|
||||
// tests for return expr with previous statements in functions
|
||||
let fun_multi_line_return = parse(
|
||||
r"fun returnsInt(): int {
|
||||
var x = 12
|
||||
x = x + 1
|
||||
-> x
|
||||
}
|
||||
",
|
||||
);
|
||||
assert_eq!(
|
||||
fun_multi_line_return.clone().unwrap(),
|
||||
vec![Expr::FunctionExpr(Function {
|
||||
name: String::from("returnsInt"),
|
||||
params: Some([].to_vec()),
|
||||
return_type: Some(Type::Integer),
|
||||
body: Some(vec![Expr::IntLiteral(12)]),
|
||||
return_expr: Box::new(Some(Expr::ReturnExpr)),
|
||||
})]
|
||||
)
|
||||
}
|
||||
}
|
||||
1
crates/akailang-parser/src/lexer/mod.rs
Normal file
1
crates/akailang-parser/src/lexer/mod.rs
Normal file
|
|
@ -0,0 +1 @@
|
|||
pub mod tokens;
|
||||
205
crates/akailang-parser/src/lexer/tokens.rs
Normal file
205
crates/akailang-parser/src/lexer/tokens.rs
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
use std::fmt;
|
||||
|
||||
use logos::Logos;
|
||||
|
||||
#[derive(Logos, Debug, Clone, PartialEq)]
|
||||
#[regex(r"[\t\f]+", logos::skip)]
|
||||
pub enum Token {
|
||||
// Identifier
|
||||
#[regex(r"[a-zA-Z_][a-zA-Z0-9_]*", |lex| lex.slice().to_owned())]
|
||||
Identifier(String),
|
||||
|
||||
// Keywords
|
||||
#[token("fun")]
|
||||
Fun,
|
||||
|
||||
#[token("class")]
|
||||
Class,
|
||||
|
||||
#[token("var")]
|
||||
Var,
|
||||
|
||||
#[token("interface")]
|
||||
Interface,
|
||||
|
||||
#[token("derive")]
|
||||
Derive,
|
||||
|
||||
#[token("impl")]
|
||||
Impl,
|
||||
|
||||
#[token("if")]
|
||||
If,
|
||||
|
||||
#[token("else")]
|
||||
Else,
|
||||
|
||||
#[token("->")]
|
||||
Return,
|
||||
|
||||
#[token("enum")]
|
||||
Enum,
|
||||
|
||||
// Types
|
||||
#[token("int")]
|
||||
IntType,
|
||||
|
||||
#[token("float")]
|
||||
FloatType,
|
||||
|
||||
#[token("bool")]
|
||||
BoolType,
|
||||
|
||||
#[token("String")]
|
||||
StringType,
|
||||
|
||||
// Literals
|
||||
#[regex(r#""([^"\\]|\\.)*""#, |lex| lex.slice().to_owned())]
|
||||
StringLiteral(String),
|
||||
|
||||
#[regex(r"[0-9]+", |lex| lex.slice().parse::<i64>().ok())]
|
||||
IntLiteral(i64),
|
||||
|
||||
#[regex(r"[0-9]+\.[0-9]+", |lex| lex.slice().parse::<f64>().ok())]
|
||||
FloatLiteral(f64),
|
||||
|
||||
#[token("true", |_| true)]
|
||||
#[token("false", |_| false)]
|
||||
BoolLiteral(bool),
|
||||
|
||||
// Operators
|
||||
#[token("=")]
|
||||
Assign,
|
||||
|
||||
#[token("==")]
|
||||
Equals,
|
||||
|
||||
#[token("!=")]
|
||||
NotEquals,
|
||||
|
||||
#[token("<", priority = 2)]
|
||||
Less,
|
||||
|
||||
#[token("<=")]
|
||||
LessEquals,
|
||||
|
||||
#[token(">", priority = 2)]
|
||||
Greater,
|
||||
|
||||
#[token(">=")]
|
||||
GreaterEquals,
|
||||
|
||||
#[token("*")]
|
||||
Multiply,
|
||||
|
||||
#[token("/")]
|
||||
Divide,
|
||||
|
||||
#[token("+")]
|
||||
Add,
|
||||
|
||||
#[token("-")]
|
||||
Substract,
|
||||
|
||||
#[token("&&")]
|
||||
And,
|
||||
|
||||
#[token("||")]
|
||||
Or,
|
||||
|
||||
// Punctiuation
|
||||
#[token("(")]
|
||||
LParen,
|
||||
|
||||
#[token(")")]
|
||||
RParen,
|
||||
|
||||
#[token("{")]
|
||||
LBrace,
|
||||
|
||||
#[token("}")]
|
||||
RBrace,
|
||||
|
||||
#[token("[")]
|
||||
LBracket,
|
||||
|
||||
#[token("]")]
|
||||
RBracket,
|
||||
|
||||
#[token(":")]
|
||||
Colon,
|
||||
|
||||
#[token(",")]
|
||||
Comma,
|
||||
|
||||
#[token(".")]
|
||||
Dot,
|
||||
|
||||
// Special
|
||||
#[regex(r"\n")]
|
||||
NewLine,
|
||||
|
||||
#[regex(r"//[^\r]*", logos::skip)]
|
||||
#[regex(r"/\*([^*]|\*[^/])*\*/", logos::skip)]
|
||||
Comment,
|
||||
|
||||
#[regex(r"[ \t\f]+", logos::skip)]
|
||||
Whitespace,
|
||||
|
||||
Eof,
|
||||
|
||||
Error,
|
||||
}
|
||||
|
||||
impl fmt::Display for Token {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Token::Identifier(ident) => write!(f, "{ident}"),
|
||||
Token::Fun => write!(f, "fun"),
|
||||
Token::Class => write!(f, "class"),
|
||||
Token::Var => write!(f, "var"),
|
||||
Token::Interface => write!(f, "interface"),
|
||||
Token::Derive => write!(f, "derive"),
|
||||
Token::Impl => write!(f, "impl"),
|
||||
Token::If => write!(f, "if"),
|
||||
Token::Else => write!(f, "else"),
|
||||
Token::Return => write!(f, "->"),
|
||||
Token::Enum => write!(f, "enum"),
|
||||
Token::IntType => write!(f, "int"),
|
||||
Token::FloatType => write!(f, "float"),
|
||||
Token::BoolType => write!(f, "bool"),
|
||||
Token::StringType => write!(f, "String"),
|
||||
Token::StringLiteral(s) => write!(f, "{s}"),
|
||||
Token::IntLiteral(i) => write!(f, "{i}"),
|
||||
Token::FloatLiteral(fl) => write!(f, "{fl}"),
|
||||
Token::BoolLiteral(b) => write!(f, "{b}"),
|
||||
Token::Assign => write!(f, "="),
|
||||
Token::Equals => write!(f, "=="),
|
||||
Token::NotEquals => write!(f, "!="),
|
||||
Token::Less => write!(f, "<"),
|
||||
Token::LessEquals => write!(f, "<="),
|
||||
Token::Greater => write!(f, ">"),
|
||||
Token::GreaterEquals => write!(f, ">="),
|
||||
Token::Multiply => write!(f, "*"),
|
||||
Token::Divide => write!(f, "/"),
|
||||
Token::Add => write!(f, "+"),
|
||||
Token::Substract => write!(f, "-"),
|
||||
Token::And => write!(f, "&&"),
|
||||
Token::Or => write!(f, "||"),
|
||||
Token::LParen => write!(f, "("),
|
||||
Token::RParen => write!(f, ")"),
|
||||
Token::LBrace => write!(f, "{{"),
|
||||
Token::RBrace => write!(f, "}}"),
|
||||
Token::LBracket => write!(f, "["),
|
||||
Token::RBracket => write!(f, "]"),
|
||||
Token::Colon => write!(f, ":"),
|
||||
Token::Comma => write!(f, ","),
|
||||
Token::Dot => write!(f, "."),
|
||||
Token::Comment => write!(f, ""),
|
||||
Token::NewLine => write!(f, "\n"),
|
||||
Token::Whitespace => write!(f, ""),
|
||||
Token::Eof => write!(f, ""),
|
||||
Token::Error => write!(f, "<error>"),
|
||||
}
|
||||
}
|
||||
}
|
||||
17
crates/akailang-parser/src/lib.rs
Normal file
17
crates/akailang-parser/src/lib.rs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
pub mod abstract_syntax_tree;
|
||||
pub mod lexer;
|
||||
|
||||
pub fn add(left: u64, right: u64) -> u64 {
|
||||
left + right
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
let result = add(2, 2);
|
||||
assert_eq!(result, 4);
|
||||
}
|
||||
}
|
||||
8
crates/akailang/Cargo.toml
Normal file
8
crates/akailang/Cargo.toml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "akailang"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
[dependencies]
|
||||
akailang-parser = {path = "../akailang-parser" }
|
||||
akailang-backend = {path = "../akailang-backend"}
|
||||
26
crates/akailang/src/main.rs
Normal file
26
crates/akailang/src/main.rs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
use akailang_parser::abstract_syntax_tree::parser::parse;
|
||||
|
||||
/*
|
||||
Simple Compiler -> 4 Stages:
|
||||
- lex
|
||||
- parse
|
||||
- type-check
|
||||
- translate to machine instructions
|
||||
*/
|
||||
|
||||
fn main() {
|
||||
let sourcecode = std::fs::read_to_string("sample.akai").unwrap();
|
||||
//println!("Token Stream:");
|
||||
//for (token, span) in token_iter.clone() {
|
||||
// println!("{:?} at {:?}", token, span);
|
||||
//}
|
||||
|
||||
println!("{:?}", sourcecode);
|
||||
|
||||
match parse(&sourcecode) {
|
||||
Ok(res) => println!("{:#?}", res),
|
||||
Err(e) => {
|
||||
panic!("{:#?}", e)
|
||||
}
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue