commit 546af734e7b3f9e80450b547eaeff31c87374858 Author: nganhkhoa Date: Fri Feb 16 02:07:52 2024 +0700 starting project Albireo diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..cb02948 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,212 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "albireo" +version = "0.1.0" +dependencies = [ + "pest", + "pest_derive", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "memchr" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "pest" +version = "2.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219c0dcc30b6a27553f9cc242972b67f75b60eb0db71f0b5462f38b058c41546" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e1288dbd7786462961e69bfd4df7848c1e37e8b74303dbdab82c3a9cdd2809" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1381c29a877c6d34b8c176e734f35d7f7f5b3adaefe940cb4d1bb7af94678e2e" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pest_meta" +version = "2.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0934d6907f148c22a3acbda520c7eed243ad7487a30f51f6ce52b58b7077a8a" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + +[[package]] +name = "proc-macro2" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "syn" +version = "2.0.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..b974598 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "albireo" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +pest = "2.7.6" +pest_derive = "2.7.6" diff --git a/README.md b/README.md new file mode 100644 index 0000000..b19eed7 --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ +# Albireo Programming Language + +## Purpose of this project + +For the sake of learning programming language theory, I decide to practice by applying what I knew and implementing them as I learn theories. + +The language should be strictly typed and everything is pure. In that context, I design a language where everything is an expression. Side-effects will be handled either by Monads (or Applicative programming) or by using Effect Handlers (so called Algebraic Effects). + +Complex types should be implemented, choices are Sub-typing, Row-Polymorphism, Algebraic Datatypes. Higher-Order Types (so called Kind) will also be implemented. + +Advanced theory on Graded Types, Substructural Types (Linear or Affine) will be considered for implementation. + +Everything is experimental and the current state of the language should reflect my personal experience as well as knowledge on programming language theory, including type theory and semantics. I do not intend to work extensively on compiler technology, although I am originated from learning assembly and binary analysis of programs. diff --git a/src/albireo.pest b/src/albireo.pest new file mode 100644 index 0000000..f810423 --- /dev/null +++ b/src/albireo.pest @@ -0,0 +1,117 @@ +keywords = { + "number" + | "bool" + | "string" + | "fn" + | "true" + | "false" + | "is" + | "in" + | "if" + | "then" + | "else" + | "let" + | "only" + | "as" + | "function" + | "import" + | "module" + | "export" +} +identifier = @{ !keywords ~ ASCII_ALPHA ~ ASCII_ALPHANUMERIC* } + +function_type_param = { type } +function_type_return = { type } +function_type = { + "fn" ~ function_type_param* ~ "=>" ~ function_type_return +} + +type = { + function_type + | "number" + | "bool" + | "string" +} + +number = @{ ASCII_DIGIT+ } +string = @{ "\"" ~ !("\"") ~ ASCII_ALPHANUMERIC* ~ "\"" } +bool = @{ "true" | "false" } +function = { "function" ~ function_param* ~ "is" ~ function_body } +function_param = { identifier } +function_body = { + binding* ~ expr +} +binding = { + "let" ~ identifier ~ "=" ~ expr ~ "in" +} + +// will be expr in later version of the language +if_cond = { identifier } +if_branch = { identifier } +else_branch = { identifier } +if_expr = { + // "if" ~ expr ~ "then" ~ expr ~ "else" ~ expr + "if" ~ if_cond ~ "then" ~ if_branch ~ "else" ~ else_branch +} + +call_function = { identifier } +call_param = { identifier | identifier ~ call_param } +call_expr = { + call_function ~ "(" ~ call_param? ~ ")" +} + +expr = { + if_expr + | call_expr + | identifier + | value +} + +// function is a value only if we allow to have thunks +// or that function is a first-class citizen, FG-CBV +// but it would a thunk if CBPV +value = _{ + number + | string + | bool + | function +} + +declaration = { + identifier ~ ":" ~ type ~ "=" ~ expr +} + +module_name = @{ identifier } +export_list = _{ + identifier + | identifier ~ "," ~ export_list +} +module_export = { + "export" ~ export_list +} + +// import module +// import module only name, name +// import module as change_name +import_list = _{ + identifier ~ "," ~ import_list + | identifier +} +import_selective = { "only" ~ import_list } +import_change_name = { "as" ~ module_name } +import_types = { + import_selective + | import_change_name +} +module_import = { "import" ~ module_name ~ import_types? } + +module_declare = { + "module" ~ module_name ~ module_export* ~ module_import* +} + +program = { + module_declare ~ declaration* +} + +WHITESPACE = _{ " " | NEWLINE } +COMMENT = _{ ";.*" ~ NEWLINE } diff --git a/src/albireo.rs b/src/albireo.rs new file mode 100644 index 0000000..26cb3cc --- /dev/null +++ b/src/albireo.rs @@ -0,0 +1,33 @@ +#[derive(pest_derive::Parser)] +#[grammar = "albireo.pest"] +pub struct AlbireoParser; + +use pest::iterators::Pair; + +struct Module { + name: String, + declaration: HashMap +} + +struct Declaration { + type: Type, + definition: Expression, +} + +enum Type { + Number, + String, + Bool, + Function(/*inputs*/Vec, /*output*/Type) +} + +// limitation as of now, everything must be passed in as identifier +enum Expression { + IfClause(String, String, String), + Application(/*function name*/String, /*params*/Vec), // function call + Identifier(String), + Number(u64), + String(String), + Bool(bool), + Function(String, Vec, Expression), +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..168dd65 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,17 @@ +mod albireo; + +use crate::albireo::{AlbireoParser, Rule}; + +use std::fs; +use pest::Parser; + +fn main() { + let input = fs::read_to_string("test/simple/main.air").expect("cannot read file"); + + let program = AlbireoParser::parse(Rule::program, &input) + .expect("file format is wrong or the parser is wrong") + .next() + .expect("cannot parse input file as a Albireo program"); + + println!("{:?}", program); +} diff --git a/test/simple/main.air b/test/simple/main.air new file mode 100644 index 0000000..ef7b4ab --- /dev/null +++ b/test/simple/main.air @@ -0,0 +1,9 @@ +module main + +c : fn => bool = function is + let a = b in + c(a) + +b : bool = false + +a : number = 1