diff --git a/Cargo.lock b/Cargo.lock index 0b44e3c..4411f41 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,22 +2,90 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + [[package]] name = "beef" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" +[[package]] +name = "cc" +version = "1.2.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3a42d84bb6b69d3a8b3eaacf0d88f179e1929695e1ad012b6cf64d9caaa5fd2" +dependencies = [ + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" + +[[package]] +name = "chumsky" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14377e276b2c8300513dff55ba4cc4142b44e5d6de6d00eb5b2307d650bb4ec1" +dependencies = [ + "hashbrown", + "regex-automata", + "serde", + "stacker", + "unicode-ident", + "unicode-segmentation", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "hashbrown" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + [[package]] name = "lang" version = "0.1.0" dependencies = [ + "chumsky", "logos", ] @@ -27,6 +95,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +[[package]] +name = "libc" +version = "0.2.174" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" + [[package]] name = "logos" version = "0.15.0" @@ -47,7 +121,7 @@ dependencies = [ "lazy_static", "proc-macro2", "quote", - "regex-syntax", + "regex-syntax 0.8.5", "rustc_version", "syn", ] @@ -61,6 +135,12 @@ dependencies = [ "logos-codegen", ] +[[package]] +name = "memchr" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" + [[package]] name = "proc-macro2" version = "1.0.95" @@ -70,6 +150,15 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "psm" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e944464ec8536cd1beb0bbfd96987eb5e3b72f2ecdafdc5c769a37f1fa2ae1f" +dependencies = [ + "cc", +] + [[package]] name = "quote" version = "1.0.40" @@ -79,6 +168,23 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "regex-automata" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59b23e92ee4318893fa3fe3e6fb365258efbfe6ac6ab30f090cdcbb7aa37efa9" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.7.5", +] + +[[package]] +name = "regex-syntax" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" + [[package]] name = "regex-syntax" version = "0.8.5" @@ -100,6 +206,45 @@ version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "stacker" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cddb07e32ddb770749da91081d8d0ac3a16f1a569a18b20348cd371f5dead06b" +dependencies = [ + "cc", + "cfg-if", + "libc", + "psm", + "windows-sys", +] + [[package]] name = "syn" version = "2.0.104" @@ -116,3 +261,82 @@ name = "unicode-ident" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/Cargo.toml b/Cargo.toml index 090227e..f6c6272 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,3 +5,4 @@ edition = "2024" [dependencies] logos = "0.15.0" +chumsky = "0.10.1" diff --git a/src/ast/evaluator.rs b/src/ast/evaluator.rs new file mode 100644 index 0000000..69a52da --- /dev/null +++ b/src/ast/evaluator.rs @@ -0,0 +1,18 @@ +use crate::ast::Expression; + + +impl Expression { + pub fn eval(&self) -> isize { + match self { + Expression::Integer(n) => *n, + + + Expression::Negate(rhs) => -rhs.eval(), + + Expression::Add(lhs, rhs) => lhs.eval() + rhs.eval(), + Expression::Substract(lhs, rhs) => lhs.eval() - rhs.eval(), + Expression::Multiply(lhs, rhs) => lhs.eval() * rhs.eval(), + Expression::Divide(lhs, rhs) => lhs.eval() / rhs.eval(), + } + } +} \ No newline at end of file diff --git a/src/ast/mod.rs b/src/ast/mod.rs new file mode 100644 index 0000000..24d7150 --- /dev/null +++ b/src/ast/mod.rs @@ -0,0 +1,12 @@ +pub mod evaluator; + +#[derive(Debug)] +pub enum Expression { + Integer(isize), + Negate(Box), + // Binary operators, + Add(Box, Box), + Substract(Box, Box), + Multiply(Box, Box), + Divide(Box, Box), +} diff --git a/src/lib.rs b/src/lib.rs deleted file mode 100644 index 1c185d8..0000000 --- a/src/lib.rs +++ /dev/null @@ -1,16 +0,0 @@ -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); - } -} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..96a31ae --- /dev/null +++ b/src/main.rs @@ -0,0 +1,36 @@ +use chumsky::Parser; +use logos::Logos; + +use crate::{parser::parser, tokens::Token}; + +mod tokens; +mod ast; +mod parser; + +fn main() { + let lexer = Token::lexer("(1 + 1) * 3"); + + let mut tokens = vec![]; + for (token, span) in lexer.spanned() { + match token { + Ok(token) => tokens.push(token), + Err(e) => { + println!("lexer error at {:?}: {:?}", span, e); + return; + } + } + } + + let ast = match parser().parse(&tokens).into_result() { + Ok(expr) => { + println!("[AST]\n{:#?}", expr); + expr + } + Err(e) => { + println!("parse error: {:#?}", e); + return; + } + }; + + println!("\n[result]\n{}", ast.eval()); +} diff --git a/src/parser.rs b/src/parser.rs new file mode 100644 index 0000000..e7114ef --- /dev/null +++ b/src/parser.rs @@ -0,0 +1,56 @@ +use chumsky::{prelude::{just, recursive}, recursive, select, IterParser, Parser}; + +use crate::{ast::Expression, tokens::Token}; + + +#[allow(clippy::let_and_return)] +/* ANCHOR: parser */ +pub fn parser<'src>( +) -> impl Parser<'src, &'src [Token<'src>], Expression, chumsky::extra::Err>>> +{ + recursive( + |p| + { + let atom = { + let parenthesized = p + .clone() + .delimited_by(just(Token::ParenBegin), just(Token::ParenEnd)); + + let integer = select! { + Token::Integer(n) => Expression::Integer(n), + }; + + parenthesized.or(integer) + }; + + let unary = just(Token::Substract) + .repeated() + .foldr(atom, |_op, rhs| Expression::Negate(Box::new(rhs))); + + let binary_1 = unary.clone().foldl( + just(Token::Multiply) + .or(just(Token::Divide)) + .then(unary) + .repeated(), + |lhs, (op, rhs)| match op { + Token::Multiply => Expression::Multiply(Box::new(lhs), Box::new(rhs)), + Token::Divide => Expression::Divide(Box::new(lhs), Box::new(rhs)), + _ => unreachable!(), + }, + ); + + let binary_2 = binary_1.clone().foldl( + just(Token::Add) + .or(just(Token::Substract)) + .then(binary_1) + .repeated(), + |lhs, (op, rhs)| match op { + Token::Add => Expression::Add(Box::new(lhs), Box::new(rhs)), + Token::Substract => Expression::Substract(Box::new(lhs), Box::new(rhs)), + _ => unreachable!(), + }, + ); + + binary_2 + }) +} \ No newline at end of file diff --git a/src/lexer.rs b/src/tokens.rs similarity index 54% rename from src/lexer.rs rename to src/tokens.rs index 610b4dc..30a5b41 100644 --- a/src/lexer.rs +++ b/src/tokens.rs @@ -2,7 +2,7 @@ use logos::{Lexer, Logos}; #[derive(Logos, Debug, Clone, PartialEq)] #[logos(skip r"[ \t\r\n\f]+")] // Skips whitespace -enum Token<'source> { +pub enum Token<'source> { #[token("false", |_| false)] #[token("true", |_| true)] Bool(bool), @@ -18,16 +18,40 @@ enum Token<'source> { #[token("/")] Divide, + + #[token("=")] + Equals, + + #[token(":")] + Colon, + + #[token("(")] + ParenBegin, + + #[token(")")] + ParenEnd, + + #[token("{")] + BraceBegin, + + #[token("}")] + BraceEnd, + + #[regex("[0-9]+", |lex| lex.slice().parse::().unwrap())] + Integer(isize), #[regex(r"[_a-zA-Z][_0-9a-zA-Z]*")] Ident(&'source str), #[regex(r#""([^"\\\x00-\x1F]|\\(["\\bnfrt/]|u[a-fA-F0-9]{4}))*""#, |lex| lex.slice().to_owned())] String(String), -} -fn float<'a>(lex: &mut Lexer<'a, Token<'a>>) -> Result { - lex.slice().parse().map_err(|_| ()) + #[token("class")] + #[token("fun")] + #[token("var")] + #[token("if")] + #[token("else")] + Keyword(&'source str), } diff --git a/syntax.akai b/syntax.akai index fa07ff9..b4293f4 100644 --- a/syntax.akai +++ b/syntax.akai @@ -1,3 +1,20 @@ +class Position: + // Properties + var int: x + var int: y + + // Constructor + Position(_x, _y) { + x = _x + y = _y + } + +// Inheritance +class Cat derive Animal: + /* + code goes here + */ + fun helloWorld() { // Variables either dynamically or statically typed var String: test = "I'm a string" @@ -6,4 +23,24 @@ fun helloWorld() { var bar = foo + 10 print("Hello World " + bar) -} \ No newline at end of file +} + +/* +Keywords/ Tokens: + - class + - fun + - var + - bool + - if + - else + - ( + - ) + - { + - } + - : + - + + - - + - / + - * + - = +*/