├── .gitignore ├── eb ├── .gitignore ├── src │ └── main.rs └── Cargo.toml ├── eb_vm ├── .gitignore ├── Cargo.toml └── src │ └── lib.rs ├── eb_ast ├── .gitignore ├── src │ ├── lib.rs │ ├── function.rs │ └── expr.rs └── Cargo.toml ├── eb_lexer ├── .gitignore ├── src │ ├── location.rs │ ├── source.rs │ ├── lib.rs │ └── token.rs └── Cargo.toml ├── eb_parser ├── .gitignore ├── src │ ├── snapshots │ │ ├── eb_core__parser__function__test__parse1.snap │ │ ├── eb_parser__expr__test__parse1.snap │ │ ├── eb_core__parser__expr__test__parse1.snap │ │ ├── eb_core__parser__function__test__parse2.snap │ │ ├── eb_parser__function__test__parse1.snap │ │ ├── eb_core__parser__function__test__parse3.snap │ │ ├── eb_parser__expr__test__parse11.snap │ │ ├── eb_parser__expr__test__parse5.snap │ │ ├── eb_parser__function__test__parse2.snap │ │ ├── eb_core__parser__expr__test__parse5.snap │ │ ├── eb_core__parser__function__test__parse4.snap │ │ ├── eb_core__parser__function__test__parse5.snap │ │ ├── eb_parser__function__test__parse3.snap │ │ ├── eb_parser__expr__test__parse8.snap │ │ ├── eb_parser__expr__test__parse2.snap │ │ ├── eb_parser__expr__test__parse3.snap │ │ ├── eb_parser__expr__test__parse7.snap │ │ ├── eb_core__parser__expr__test__parse2.snap │ │ ├── eb_core__parser__expr__test__parse3.snap │ │ ├── eb_parser__function__test__parse4.snap │ │ ├── eb_parser__function__test__parse5.snap │ │ ├── eb_parser__expr__test__parse6.snap │ │ ├── eb_core__parser__expr__test__parse6.snap │ │ ├── eb_parser__expr__test__parse4.snap │ │ ├── eb_core__parser__expr__test__parse4.snap │ │ ├── eb_parser__expr__test__parse9.snap │ │ ├── eb_parser__expr__test__parse10.snap │ │ └── eb_parser__function__test__parse6.snap │ ├── function.rs │ ├── lib.rs │ └── expr.rs └── Cargo.toml ├── eb_vm_ctx ├── .gitignore ├── src │ ├── value.rs │ ├── lib.rs │ └── inst.rs └── Cargo.toml ├── eb_codegen_fast ├── .gitignore ├── src │ ├── lib.rs │ ├── snapshots │ │ ├── eb_codegen_fast__function__test__codegen1.snap │ │ ├── eb_codegen_fast__function__test__codegen2.snap │ │ └── eb_codegen_fast__function__test__codegen3.snap │ ├── function.rs │ └── expr.rs └── Cargo.toml ├── README.md └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | **/*.rs.bk 4 | -------------------------------------------------------------------------------- /eb/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | **/*.rs.bk 4 | -------------------------------------------------------------------------------- /eb_vm/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | **/*.rs.bk 4 | -------------------------------------------------------------------------------- /eb_ast/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | **/*.rs.bk 4 | -------------------------------------------------------------------------------- /eb_lexer/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | **/*.rs.bk 4 | -------------------------------------------------------------------------------- /eb_parser/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | **/*.rs.bk 4 | -------------------------------------------------------------------------------- /eb_vm_ctx/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | **/*.rs.bk 4 | -------------------------------------------------------------------------------- /eb_codegen_fast/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | **/*.rs.bk 4 | -------------------------------------------------------------------------------- /eb/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("Hello, world!"); 3 | } 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # eb 2 | 3 | Eb is a embeddable scripting programming language written in Rust 4 | -------------------------------------------------------------------------------- /eb_ast/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate eb_lexer as lexer; 2 | 3 | pub mod expr; 4 | pub mod function; 5 | -------------------------------------------------------------------------------- /eb_lexer/src/location.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, Copy, Eq, PartialEq)] 2 | pub struct Location(pub u32); 3 | 4 | impl Location { 5 | pub fn loc(self) -> u32 { 6 | self.0 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /eb_codegen_fast/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate eb_ast as ast; 2 | extern crate eb_parser as parser; 3 | extern crate eb_vm_ctx as vm_ctx; 4 | extern crate rustc_hash; 5 | 6 | pub mod expr; 7 | pub mod function; 8 | -------------------------------------------------------------------------------- /eb/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "eb" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /eb_vm_ctx/src/value.rs: -------------------------------------------------------------------------------- 1 | use super::FunctionContext; 2 | 3 | #[derive(Debug, Clone)] 4 | pub enum Value { 5 | Func(Box), 6 | Bool(bool), 7 | Int(i64), 8 | String(String), 9 | Nil, 10 | } 11 | -------------------------------------------------------------------------------- /eb_vm_ctx/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "eb_vm_ctx" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | 10 | -------------------------------------------------------------------------------- /eb_lexer/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "eb_lexer" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | nom = "6.1.2" 10 | -------------------------------------------------------------------------------- /eb_parser/src/snapshots/eb_core__parser__function__test__parse1.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/parser/function.rs 3 | expression: "parse(&mut ctx).expect(\"fail to parse\")" 4 | 5 | --- 6 | Node { 7 | name: "f", 8 | params: [], 9 | body: [], 10 | } 11 | -------------------------------------------------------------------------------- /eb_ast/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "eb_ast" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | eb_lexer = { path = "../eb_lexer" } 10 | -------------------------------------------------------------------------------- /eb_parser/src/snapshots/eb_parser__expr__test__parse1.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/expr.rs 3 | expression: "parse(&mut ctx).expect(\"fail to parse\")" 4 | 5 | --- 6 | Node { 7 | kind: Ident( 8 | "x", 9 | ), 10 | loc: Location( 11 | 0, 12 | ), 13 | } 14 | -------------------------------------------------------------------------------- /eb_codegen_fast/src/snapshots/eb_codegen_fast__function__test__codegen1.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/function.rs 3 | expression: ctx 4 | 5 | --- 6 | FunctionContext { 7 | name: "f", 8 | param_names: [], 9 | code: Code( 10 | [], 11 | ), 12 | children: [], 13 | } 14 | -------------------------------------------------------------------------------- /eb_parser/src/snapshots/eb_core__parser__expr__test__parse1.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/parser/expr.rs 3 | expression: "parse(&mut ctx).expect(\"fail to parse\")" 4 | 5 | --- 6 | Node { 7 | kind: Ident( 8 | "x", 9 | ), 10 | loc: Location( 11 | 0, 12 | ), 13 | } 14 | -------------------------------------------------------------------------------- /eb_parser/src/snapshots/eb_core__parser__function__test__parse2.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/parser/function.rs 3 | expression: "parse(&mut ctx).expect(\"fail to parse\")" 4 | 5 | --- 6 | Node { 7 | name: "f", 8 | params: [ 9 | Param { 10 | name: "x", 11 | }, 12 | ], 13 | body: [], 14 | } 15 | -------------------------------------------------------------------------------- /eb_parser/src/snapshots/eb_parser__function__test__parse1.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/function.rs 3 | expression: "parse(&mut ctx).expect(\"fail to parse\")" 4 | 5 | --- 6 | Node { 7 | name: "f", 8 | params: [], 9 | body: Node { 10 | kind: Exprs( 11 | [], 12 | ), 13 | loc: Location( 14 | 10, 15 | ), 16 | }, 17 | } 18 | -------------------------------------------------------------------------------- /eb_codegen_fast/src/snapshots/eb_codegen_fast__function__test__codegen2.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/function.rs 3 | expression: ctx 4 | 5 | --- 6 | FunctionContext { 7 | name: "f", 8 | param_names: [ 9 | "x", 10 | ], 11 | code: Code( 12 | [ 13 | Get( 14 | "x", 15 | ), 16 | ], 17 | ), 18 | children: [], 19 | } 20 | -------------------------------------------------------------------------------- /eb_parser/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "eb_parser" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | nom = "6.1.2" 10 | anyhow = "1.0" 11 | eb_lexer = { path = "../eb_lexer" } 12 | eb_ast = { path = "../eb_ast" } 13 | 14 | [dev-dependencies] 15 | insta = "= 1.7.1" 16 | -------------------------------------------------------------------------------- /eb_parser/src/snapshots/eb_core__parser__function__test__parse3.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/parser/function.rs 3 | expression: "parse(&mut ctx).expect(\"fail to parse\")" 4 | 5 | --- 6 | Node { 7 | name: "f", 8 | params: [ 9 | Param { 10 | name: "x", 11 | }, 12 | Param { 13 | name: "y", 14 | }, 15 | ], 16 | body: [], 17 | } 18 | -------------------------------------------------------------------------------- /eb_parser/src/snapshots/eb_parser__expr__test__parse11.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/expr.rs 3 | expression: "parse_str(r#\"return 123\"#)" 4 | 5 | --- 6 | Node { 7 | kind: Return( 8 | Node { 9 | kind: Int( 10 | 123, 11 | ), 12 | loc: Location( 13 | 7, 14 | ), 15 | }, 16 | ), 17 | loc: Location( 18 | 0, 19 | ), 20 | } 21 | -------------------------------------------------------------------------------- /eb_parser/src/snapshots/eb_parser__expr__test__parse5.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/expr.rs 3 | expression: "parse(&mut ctx).expect(\"fail to parse\")" 4 | 5 | --- 6 | Node { 7 | kind: Call( 8 | Node { 9 | kind: Ident( 10 | "f", 11 | ), 12 | loc: Location( 13 | 0, 14 | ), 15 | }, 16 | [], 17 | ), 18 | loc: Location( 19 | 1, 20 | ), 21 | } 22 | -------------------------------------------------------------------------------- /eb_parser/src/snapshots/eb_parser__function__test__parse2.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/function.rs 3 | expression: "parse(&mut ctx).expect(\"fail to parse\")" 4 | 5 | --- 6 | Node { 7 | name: "f", 8 | params: [ 9 | Param { 10 | name: "x", 11 | }, 12 | ], 13 | body: Node { 14 | kind: Exprs( 15 | [], 16 | ), 17 | loc: Location( 18 | 11, 19 | ), 20 | }, 21 | } 22 | -------------------------------------------------------------------------------- /eb_parser/src/snapshots/eb_core__parser__expr__test__parse5.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/parser/expr.rs 3 | expression: "parse(&mut ctx).expect(\"fail to parse\")" 4 | 5 | --- 6 | Node { 7 | kind: Call( 8 | Node { 9 | kind: Ident( 10 | "f", 11 | ), 12 | loc: Location( 13 | 0, 14 | ), 15 | }, 16 | [], 17 | ), 18 | loc: Location( 19 | 1, 20 | ), 21 | } 22 | -------------------------------------------------------------------------------- /eb_vm/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "eb_vm" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | rustc-hash = "1.0" 10 | eb_vm_ctx = { path = "../eb_vm_ctx" } 11 | 12 | [dev-dependencies] 13 | eb_codegen_fast = { path = "../eb_codegen_fast" } 14 | eb_parser = { path = "../eb_parser" } 15 | eb_ast = { path = "../eb_ast" } 16 | eb_lexer = { path = "../eb_lexer" } 17 | -------------------------------------------------------------------------------- /eb_codegen_fast/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "eb_codegen_fast" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | eb_parser = { path = "../eb_parser" } 10 | eb_ast = { path = "../eb_ast" } 11 | eb_vm_ctx = { path = "../eb_vm_ctx" } 12 | anyhow = "1.0" 13 | rustc-hash = "= 1.1.0" 14 | 15 | [dev-dependencies] 16 | eb_lexer = { path = "../eb_lexer" } 17 | insta = "= 1.7.1" 18 | -------------------------------------------------------------------------------- /eb_parser/src/snapshots/eb_core__parser__function__test__parse4.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/parser/function.rs 3 | expression: "parse(&mut ctx).expect(\"fail to parse\")" 4 | 5 | --- 6 | Node { 7 | name: "f", 8 | params: [ 9 | Param { 10 | name: "x", 11 | }, 12 | ], 13 | body: [ 14 | Node { 15 | kind: Ident( 16 | "x", 17 | ), 18 | loc: Location( 19 | 11, 20 | ), 21 | }, 22 | ], 23 | } 24 | -------------------------------------------------------------------------------- /eb_parser/src/snapshots/eb_core__parser__function__test__parse5.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/parser/function.rs 3 | expression: "parse(&mut ctx).expect(\"fail to parse\")" 4 | 5 | --- 6 | Node { 7 | name: "f", 8 | params: [ 9 | Param { 10 | name: "x", 11 | }, 12 | ], 13 | body: [ 14 | Node { 15 | kind: Ident( 16 | "x", 17 | ), 18 | loc: Location( 19 | 11, 20 | ), 21 | }, 22 | ], 23 | } 24 | -------------------------------------------------------------------------------- /eb_parser/src/snapshots/eb_parser__function__test__parse3.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/function.rs 3 | expression: "parse(&mut ctx).expect(\"fail to parse\")" 4 | 5 | --- 6 | Node { 7 | name: "f", 8 | params: [ 9 | Param { 10 | name: "x", 11 | }, 12 | Param { 13 | name: "y", 14 | }, 15 | ], 16 | body: Node { 17 | kind: Exprs( 18 | [], 19 | ), 20 | loc: Location( 21 | 14, 22 | ), 23 | }, 24 | } 25 | -------------------------------------------------------------------------------- /eb_parser/src/snapshots/eb_parser__expr__test__parse8.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/expr.rs 3 | expression: "parse_str(r#\"x != x\"#)" 4 | 5 | --- 6 | Node { 7 | kind: BinOp( 8 | Neq, 9 | Node { 10 | kind: Ident( 11 | "x", 12 | ), 13 | loc: Location( 14 | 0, 15 | ), 16 | }, 17 | Node { 18 | kind: Ident( 19 | "x", 20 | ), 21 | loc: Location( 22 | 5, 23 | ), 24 | }, 25 | ), 26 | loc: Location( 27 | 2, 28 | ), 29 | } 30 | -------------------------------------------------------------------------------- /eb_parser/src/snapshots/eb_parser__expr__test__parse2.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/expr.rs 3 | expression: "parse(&mut ctx).expect(\"fail to parse\")" 4 | 5 | --- 6 | Node { 7 | kind: BinOp( 8 | Add, 9 | Node { 10 | kind: Ident( 11 | "x", 12 | ), 13 | loc: Location( 14 | 0, 15 | ), 16 | }, 17 | Node { 18 | kind: Ident( 19 | "x", 20 | ), 21 | loc: Location( 22 | 3, 23 | ), 24 | }, 25 | ), 26 | loc: Location( 27 | 2, 28 | ), 29 | } 30 | -------------------------------------------------------------------------------- /eb_parser/src/snapshots/eb_parser__expr__test__parse3.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/expr.rs 3 | expression: "parse(&mut ctx).expect(\"fail to parse\")" 4 | 5 | --- 6 | Node { 7 | kind: BinOp( 8 | Add, 9 | Node { 10 | kind: Int( 11 | 123, 12 | ), 13 | loc: Location( 14 | 0, 15 | ), 16 | }, 17 | Node { 18 | kind: Ident( 19 | "x", 20 | ), 21 | loc: Location( 22 | 6, 23 | ), 24 | }, 25 | ), 26 | loc: Location( 27 | 4, 28 | ), 29 | } 30 | -------------------------------------------------------------------------------- /eb_parser/src/snapshots/eb_parser__expr__test__parse7.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/expr.rs 3 | expression: "parse(&mut ctx).expect(\"fail to parse\")" 4 | 5 | --- 6 | Node { 7 | kind: BinOp( 8 | Eq, 9 | Node { 10 | kind: Ident( 11 | "x", 12 | ), 13 | loc: Location( 14 | 0, 15 | ), 16 | }, 17 | Node { 18 | kind: Ident( 19 | "x", 20 | ), 21 | loc: Location( 22 | 5, 23 | ), 24 | }, 25 | ), 26 | loc: Location( 27 | 2, 28 | ), 29 | } 30 | -------------------------------------------------------------------------------- /eb_parser/src/snapshots/eb_core__parser__expr__test__parse2.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/parser/expr.rs 3 | expression: "parse(&mut ctx).expect(\"fail to parse\")" 4 | 5 | --- 6 | Node { 7 | kind: BinOp( 8 | Add, 9 | Node { 10 | kind: Ident( 11 | "x", 12 | ), 13 | loc: Location( 14 | 0, 15 | ), 16 | }, 17 | Node { 18 | kind: Ident( 19 | "x", 20 | ), 21 | loc: Location( 22 | 3, 23 | ), 24 | }, 25 | ), 26 | loc: Location( 27 | 2, 28 | ), 29 | } 30 | -------------------------------------------------------------------------------- /eb_parser/src/snapshots/eb_core__parser__expr__test__parse3.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/parser/expr.rs 3 | expression: "parse(&mut ctx).expect(\"fail to parse\")" 4 | 5 | --- 6 | Node { 7 | kind: BinOp( 8 | Add, 9 | Node { 10 | kind: Int( 11 | 123, 12 | ), 13 | loc: Location( 14 | 0, 15 | ), 16 | }, 17 | Node { 18 | kind: Ident( 19 | "x", 20 | ), 21 | loc: Location( 22 | 6, 23 | ), 24 | }, 25 | ), 26 | loc: Location( 27 | 4, 28 | ), 29 | } 30 | -------------------------------------------------------------------------------- /eb_parser/src/snapshots/eb_parser__function__test__parse4.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/function.rs 3 | expression: "parse(&mut ctx).expect(\"fail to parse\")" 4 | 5 | --- 6 | Node { 7 | name: "f", 8 | params: [ 9 | Param { 10 | name: "x", 11 | }, 12 | ], 13 | body: Node { 14 | kind: Exprs( 15 | [ 16 | Node { 17 | kind: Ident( 18 | "x", 19 | ), 20 | loc: Location( 21 | 11, 22 | ), 23 | }, 24 | ], 25 | ), 26 | loc: Location( 27 | 11, 28 | ), 29 | }, 30 | } 31 | -------------------------------------------------------------------------------- /eb_parser/src/snapshots/eb_parser__function__test__parse5.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/function.rs 3 | expression: "parse(&mut ctx).expect(\"fail to parse\")" 4 | 5 | --- 6 | Node { 7 | name: "f", 8 | params: [ 9 | Param { 10 | name: "x", 11 | }, 12 | ], 13 | body: Node { 14 | kind: Exprs( 15 | [ 16 | Node { 17 | kind: Ident( 18 | "x", 19 | ), 20 | loc: Location( 21 | 11, 22 | ), 23 | }, 24 | ], 25 | ), 26 | loc: Location( 27 | 11, 28 | ), 29 | }, 30 | } 31 | -------------------------------------------------------------------------------- /eb_vm_ctx/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod inst; 2 | pub mod value; 3 | 4 | #[derive(Debug, Clone)] 5 | pub struct FunctionContext { 6 | pub name: String, 7 | pub param_names: Vec, 8 | pub code: inst::Code, 9 | pub children: Vec, // TODO: Vec> 10 | } 11 | 12 | impl Default for FunctionContext { 13 | fn default() -> Self { 14 | Self { 15 | name: "".to_owned(), 16 | param_names: vec![], 17 | code: inst::Code(vec![]), 18 | children: vec![], 19 | } 20 | } 21 | } 22 | 23 | impl FunctionContext { 24 | pub fn push(&mut self, inst: inst::Inst) { 25 | self.code.0.push(inst) 26 | } 27 | 28 | pub fn add_child(&mut self, ctx: Self) { 29 | self.children.push(ctx) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /eb_ast/src/function.rs: -------------------------------------------------------------------------------- 1 | use super::expr; 2 | 3 | #[derive(Debug, Clone, PartialEq)] 4 | pub struct Node { 5 | name: String, 6 | params: Vec, 7 | body: expr::Node, 8 | } 9 | 10 | #[derive(Debug, Clone, PartialEq)] 11 | pub struct Param { 12 | name: String, 13 | } 14 | 15 | impl Node { 16 | pub fn new(name: String, params: Vec, body: expr::Node) -> Self { 17 | Self { name, params, body } 18 | } 19 | 20 | pub fn name(&self) -> &String { 21 | &self.name 22 | } 23 | 24 | pub fn params(&self) -> &[Param] { 25 | &self.params 26 | } 27 | 28 | pub fn body(&self) -> &expr::Node { 29 | &self.body 30 | } 31 | } 32 | 33 | impl Param { 34 | pub fn new(name: String) -> Self { 35 | Self { name } 36 | } 37 | 38 | pub fn name(&self) -> &String { 39 | &self.name 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /eb_parser/src/snapshots/eb_parser__expr__test__parse6.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/expr.rs 3 | expression: "parse(&mut ctx).expect(\"fail to parse\")" 4 | 5 | --- 6 | Node { 7 | kind: Call( 8 | Node { 9 | kind: Ident( 10 | "f", 11 | ), 12 | loc: Location( 13 | 0, 14 | ), 15 | }, 16 | [ 17 | Node { 18 | kind: Int( 19 | 1, 20 | ), 21 | loc: Location( 22 | 2, 23 | ), 24 | }, 25 | Node { 26 | kind: Ident( 27 | "x", 28 | ), 29 | loc: Location( 30 | 5, 31 | ), 32 | }, 33 | ], 34 | ), 35 | loc: Location( 36 | 1, 37 | ), 38 | } 39 | -------------------------------------------------------------------------------- /eb_parser/src/snapshots/eb_core__parser__expr__test__parse6.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/parser/expr.rs 3 | expression: "parse(&mut ctx).expect(\"fail to parse\")" 4 | 5 | --- 6 | Node { 7 | kind: Call( 8 | Node { 9 | kind: Ident( 10 | "f", 11 | ), 12 | loc: Location( 13 | 0, 14 | ), 15 | }, 16 | [ 17 | Node { 18 | kind: Int( 19 | 1, 20 | ), 21 | loc: Location( 22 | 2, 23 | ), 24 | }, 25 | Node { 26 | kind: Ident( 27 | "x", 28 | ), 29 | loc: Location( 30 | 5, 31 | ), 32 | }, 33 | ], 34 | ), 35 | loc: Location( 36 | 1, 37 | ), 38 | } 39 | -------------------------------------------------------------------------------- /eb_codegen_fast/src/snapshots/eb_codegen_fast__function__test__codegen3.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/function.rs 3 | expression: ctx 4 | 5 | --- 6 | FunctionContext { 7 | name: "f", 8 | param_names: [ 9 | "x", 10 | ], 11 | code: Code( 12 | [ 13 | Get( 14 | "x", 15 | ), 16 | PushInt( 17 | 1, 18 | ), 19 | Eq, 20 | Jne( 21 | 3, 22 | ), 23 | PushInt( 24 | 1, 25 | ), 26 | Ret, 27 | Get( 28 | "x", 29 | ), 30 | Get( 31 | "x", 32 | ), 33 | PushInt( 34 | 1, 35 | ), 36 | Sub, 37 | Get( 38 | "f", 39 | ), 40 | Call, 41 | Mul, 42 | ], 43 | ), 44 | children: [], 45 | } 46 | -------------------------------------------------------------------------------- /eb_ast/src/expr.rs: -------------------------------------------------------------------------------- 1 | use super::function; 2 | use lexer::location::Location; 3 | 4 | #[derive(Debug, Clone, PartialEq)] 5 | pub struct Node { 6 | kind: Kind, 7 | loc: Location, 8 | } 9 | 10 | #[derive(Debug, Clone, PartialEq)] 11 | pub enum Kind { 12 | Int(i64), 13 | Ident(String), 14 | Function(Box), 15 | BinOp(BinOpKind, Box, Box), 16 | Call(Box, Vec), 17 | If(Box, Box, Option>), 18 | Return(Box), 19 | Exprs(Vec), 20 | } 21 | 22 | #[derive(Debug, Clone, PartialEq)] 23 | pub enum BinOpKind { 24 | Add, 25 | Sub, 26 | Mul, 27 | Div, 28 | Eq, 29 | Neq, 30 | } 31 | 32 | impl Node { 33 | pub fn new(kind: Kind, loc: Location) -> Self { 34 | Self { kind, loc } 35 | } 36 | 37 | pub fn kind(&self) -> &Kind { 38 | &self.kind 39 | } 40 | 41 | pub fn loc(&self) -> &Location { 42 | &self.loc 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /eb_parser/src/snapshots/eb_parser__expr__test__parse4.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/expr.rs 3 | expression: "parse(&mut ctx).expect(\"fail to parse\")" 4 | 5 | --- 6 | Node { 7 | kind: BinOp( 8 | Add, 9 | Node { 10 | kind: BinOp( 11 | Mul, 12 | Node { 13 | kind: Int( 14 | 1, 15 | ), 16 | loc: Location( 17 | 0, 18 | ), 19 | }, 20 | Node { 21 | kind: Int( 22 | 2, 23 | ), 24 | loc: Location( 25 | 4, 26 | ), 27 | }, 28 | ), 29 | loc: Location( 30 | 2, 31 | ), 32 | }, 33 | Node { 34 | kind: Int( 35 | 3, 36 | ), 37 | loc: Location( 38 | 8, 39 | ), 40 | }, 41 | ), 42 | loc: Location( 43 | 6, 44 | ), 45 | } 46 | -------------------------------------------------------------------------------- /eb_parser/src/snapshots/eb_core__parser__expr__test__parse4.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/parser/expr.rs 3 | expression: "parse(&mut ctx).expect(\"fail to parse\")" 4 | 5 | --- 6 | Node { 7 | kind: BinOp( 8 | Add, 9 | Node { 10 | kind: BinOp( 11 | Mul, 12 | Node { 13 | kind: Int( 14 | 1, 15 | ), 16 | loc: Location( 17 | 0, 18 | ), 19 | }, 20 | Node { 21 | kind: Int( 22 | 2, 23 | ), 24 | loc: Location( 25 | 4, 26 | ), 27 | }, 28 | ), 29 | loc: Location( 30 | 2, 31 | ), 32 | }, 33 | Node { 34 | kind: Int( 35 | 3, 36 | ), 37 | loc: Location( 38 | 8, 39 | ), 40 | }, 41 | ), 42 | loc: Location( 43 | 6, 44 | ), 45 | } 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 uint256_t 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /eb_lexer/src/source.rs: -------------------------------------------------------------------------------- 1 | use std::{fs::read_to_string, io}; 2 | 3 | pub enum Source { 4 | File(SourceFile), 5 | String(String), 6 | } 7 | 8 | pub struct SourceFile { 9 | name: String, 10 | body: String, 11 | } 12 | 13 | impl Source { 14 | pub fn as_file(&self) -> Option<&SourceFile> { 15 | match self { 16 | Self::File(file) => Some(file), 17 | Self::String(_) => None, 18 | } 19 | } 20 | 21 | pub fn as_str(&self) -> Option<&String> { 22 | match self { 23 | Self::File(_) => None, 24 | Self::String(s) => Some(s), 25 | } 26 | } 27 | 28 | pub fn body(&self) -> &String { 29 | match self { 30 | Self::File(file) => file.body(), 31 | Self::String(s) => &s, 32 | } 33 | } 34 | } 35 | 36 | impl SourceFile { 37 | pub fn new(name: String) -> Result { 38 | Ok(Self { 39 | body: read_to_string(name.as_str())?, 40 | name, 41 | }) 42 | } 43 | 44 | pub fn name(&self) -> &str { 45 | self.name.as_str() 46 | } 47 | 48 | pub fn body(&self) -> &String { 49 | &self.body 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /eb_parser/src/snapshots/eb_parser__expr__test__parse9.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/expr.rs 3 | expression: "parse_str(r#\"if x == 1:\n 123;;\"#)" 4 | 5 | --- 6 | Node { 7 | kind: If( 8 | Node { 9 | kind: BinOp( 10 | Eq, 11 | Node { 12 | kind: Ident( 13 | "x", 14 | ), 15 | loc: Location( 16 | 3, 17 | ), 18 | }, 19 | Node { 20 | kind: Int( 21 | 1, 22 | ), 23 | loc: Location( 24 | 8, 25 | ), 26 | }, 27 | ), 28 | loc: Location( 29 | 5, 30 | ), 31 | }, 32 | Node { 33 | kind: Exprs( 34 | [ 35 | Node { 36 | kind: Int( 37 | 123, 38 | ), 39 | loc: Location( 40 | 27, 41 | ), 42 | }, 43 | ], 44 | ), 45 | loc: Location( 46 | 27, 47 | ), 48 | }, 49 | None, 50 | ), 51 | loc: Location( 52 | 0, 53 | ), 54 | } 55 | -------------------------------------------------------------------------------- /eb_vm_ctx/src/inst.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone)] 2 | pub enum Inst { 3 | PushInt(i64), 4 | PushStr(String), 5 | Get(String), 6 | Call, 7 | Sub, 8 | Mul, 9 | Eq, 10 | Jne(i32), 11 | Ret, 12 | } 13 | 14 | #[derive(Debug, Clone)] 15 | pub struct Code(pub Vec); 16 | 17 | impl Code { 18 | pub fn get(&mut self, idx: usize) -> Option<&Inst> { 19 | self.0.get(idx) 20 | } 21 | 22 | pub fn get_mut(&mut self, idx: usize) -> Option<&mut Inst> { 23 | self.0.get_mut(idx) 24 | } 25 | 26 | pub fn len(&self) -> usize { 27 | self.0.len() 28 | } 29 | } 30 | 31 | // pub struct Inst(u32); 32 | // 33 | // pub struct Code(pub Vec); 34 | // 35 | // const CALL: u8 = 0x00; 36 | // const ADD: u8 = 0x01; 37 | // const SUB: u8 = 0x02; 38 | // const MUL: u8 = 0x03; 39 | // const JEQ: u8 = 0x04; 40 | // const RET: u8 = 0x05; 41 | // 42 | // impl Inst { 43 | // pub fn opcode(self) -> u8 { 44 | // (self.0 >> 24) as u8 45 | // } 46 | // 47 | // pub fn new_call() -> Self { 48 | // Inst((CALL as u32) << 24) 49 | // } 50 | // 51 | // pub fn new_add() -> Self { 52 | // Inst((ADD as u32) << 24) 53 | // } 54 | // 55 | // pub fn new_sub() -> Self { 56 | // Inst((SUB as u32) << 24) 57 | // } 58 | // 59 | // pub fn new_mul() -> Self { 60 | // Inst((MUL as u32) << 24) 61 | // } 62 | // 63 | // pub fn new_jeq() -> Self { 64 | // Inst((MUL as u32) << 24) 65 | // } 66 | // 67 | // pub fn new_ret() -> Self { 68 | // Inst((RET as u32) << 24) 69 | // } 70 | // } 71 | -------------------------------------------------------------------------------- /eb_codegen_fast/src/function.rs: -------------------------------------------------------------------------------- 1 | use super::expr; 2 | use anyhow::Result; 3 | use ast::function as func; 4 | use vm_ctx::FunctionContext as Context; 5 | 6 | pub fn visit(ctx: &mut Context, func: &func::Node) -> Result<()> { 7 | ctx.name = func.name().to_owned(); 8 | ctx.param_names = func.params().iter().map(|p| p.name().to_owned()).collect(); 9 | expr::visit(ctx, func.body())?; 10 | Ok(()) 11 | } 12 | 13 | #[cfg(test)] 14 | mod test { 15 | extern crate eb_lexer as lexer; 16 | extern crate eb_parser as parser; 17 | extern crate insta; 18 | use super::*; 19 | use lexer::{source::Source, tokenize}; 20 | use parser::{function::parse, Context as ParserContext}; 21 | 22 | #[test] 23 | fn codegen1() { 24 | let source = Source::String(r#"func f(): ;;"#.to_string()); 25 | let mut ctx = ParserContext::new(tokenize(&source)); 26 | let node = parse(&mut ctx).expect("fail to parse"); 27 | let mut ctx = Context::default(); 28 | visit(&mut ctx, &node).unwrap(); 29 | insta::assert_debug_snapshot!(ctx); 30 | } 31 | 32 | #[test] 33 | fn codegen2() { 34 | let source = Source::String(r#"func f(x): x;;"#.to_string()); 35 | let mut ctx = ParserContext::new(tokenize(&source)); 36 | let node = parse(&mut ctx).expect("fail to parse"); 37 | let mut ctx = Context::default(); 38 | visit(&mut ctx, &node).unwrap(); 39 | insta::assert_debug_snapshot!(ctx); 40 | } 41 | 42 | #[test] 43 | fn codegen3() { 44 | let source = Source::String( 45 | r#" 46 | func f(x): 47 | if x == 1: 48 | return 1 ;; 49 | x * f(x - 1) ;;"# 50 | .to_string(), 51 | ); 52 | let mut ctx = ParserContext::new(tokenize(&source)); 53 | let node = parse(&mut ctx).expect("fail to parse"); 54 | let mut ctx = Context::default(); 55 | visit(&mut ctx, &node).unwrap(); 56 | insta::assert_debug_snapshot!(ctx); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /eb_codegen_fast/src/expr.rs: -------------------------------------------------------------------------------- 1 | use super::function; 2 | use anyhow::Result; 3 | use ast::expr as ast_expr; 4 | use vm_ctx::{inst::Inst, FunctionContext as Context}; 5 | 6 | pub fn visit(ctx: &mut Context, expr: &ast_expr::Node) -> Result<()> { 7 | match expr.kind() { 8 | ast_expr::Kind::Int(i) => { 9 | ctx.push(Inst::PushInt(*i)); // TODO 10 | } 11 | ast_expr::Kind::Ident(ident) => { 12 | ctx.push(Inst::Get(ident.to_owned())); 13 | } 14 | ast_expr::Kind::BinOp(op, lhs, rhs) => visit_binop(ctx, op, lhs, rhs)?, 15 | ast_expr::Kind::Function(func) => { 16 | let mut ctx_ = Context::default(); 17 | function::visit(&mut ctx_, func)?; 18 | ctx.add_child(ctx_); 19 | } 20 | ast_expr::Kind::Call(callee, args) => visit_call(ctx, callee, args)?, 21 | ast_expr::Kind::If(cond, then_, else_) => visit_if(ctx, cond, then_, else_)?, 22 | ast_expr::Kind::Return(val) => visit_ret(ctx, val)?, 23 | ast_expr::Kind::Exprs(exprs) => { 24 | for expr in exprs { 25 | visit(ctx, expr)?; 26 | } 27 | } 28 | } 29 | Ok(()) 30 | } 31 | 32 | fn visit_binop( 33 | ctx: &mut Context, 34 | op: &ast_expr::BinOpKind, 35 | lhs: &ast_expr::Node, 36 | rhs: &ast_expr::Node, 37 | ) -> Result<()> { 38 | visit(ctx, lhs)?; 39 | visit(ctx, rhs)?; 40 | match op { 41 | ast_expr::BinOpKind::Sub => ctx.push(Inst::Sub), 42 | ast_expr::BinOpKind::Mul => ctx.push(Inst::Mul), 43 | ast_expr::BinOpKind::Eq => ctx.push(Inst::Eq), 44 | _ => todo!(), 45 | } 46 | Ok(()) 47 | } 48 | 49 | fn visit_call(ctx: &mut Context, callee: &ast_expr::Node, args: &[ast_expr::Node]) -> Result<()> { 50 | for arg in args { 51 | visit(ctx, arg)?; 52 | } 53 | match callee.kind() { 54 | ast_expr::Kind::Ident(name) => { 55 | ctx.push(Inst::Get(name.to_owned())); 56 | } 57 | _ => todo!(), 58 | } 59 | ctx.push(Inst::Call); 60 | Ok(()) 61 | } 62 | 63 | fn visit_if( 64 | ctx: &mut Context, 65 | cond: &ast_expr::Node, 66 | then_: &ast_expr::Node, 67 | else_: &Option>, 68 | ) -> Result<()> { 69 | assert!(else_.is_none()); 70 | visit(ctx, cond)?; 71 | let cur = ctx.code.len() as i32; 72 | ctx.push(Inst::Jne(0)); 73 | visit(ctx, then_)?; 74 | let merge = ctx.code.len() as i32; 75 | match ctx.code.get_mut(cur as usize).unwrap() { 76 | Inst::Jne(ref mut offset) => *offset = merge - cur, 77 | _ => panic!(), 78 | } 79 | Ok(()) 80 | } 81 | 82 | fn visit_ret(ctx: &mut Context, val: &ast_expr::Node) -> Result<()> { 83 | visit(ctx, val)?; 84 | ctx.push(Inst::Ret); 85 | Ok(()) 86 | } 87 | -------------------------------------------------------------------------------- /eb_parser/src/snapshots/eb_parser__expr__test__parse10.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/expr.rs 3 | expression: "parse_str(r#\"if x == 1:\n x + 1 ; \n x ;;\n else:\n 42;;\"#)" 4 | 5 | --- 6 | Node { 7 | kind: If( 8 | Node { 9 | kind: BinOp( 10 | Eq, 11 | Node { 12 | kind: Ident( 13 | "x", 14 | ), 15 | loc: Location( 16 | 3, 17 | ), 18 | }, 19 | Node { 20 | kind: Int( 21 | 1, 22 | ), 23 | loc: Location( 24 | 8, 25 | ), 26 | }, 27 | ), 28 | loc: Location( 29 | 5, 30 | ), 31 | }, 32 | Node { 33 | kind: Exprs( 34 | [ 35 | Node { 36 | kind: BinOp( 37 | Add, 38 | Node { 39 | kind: Ident( 40 | "x", 41 | ), 42 | loc: Location( 43 | 28, 44 | ), 45 | }, 46 | Node { 47 | kind: Int( 48 | 1, 49 | ), 50 | loc: Location( 51 | 32, 52 | ), 53 | }, 54 | ), 55 | loc: Location( 56 | 30, 57 | ), 58 | }, 59 | Node { 60 | kind: Ident( 61 | "x", 62 | ), 63 | loc: Location( 64 | 54, 65 | ), 66 | }, 67 | ], 68 | ), 69 | loc: Location( 70 | 28, 71 | ), 72 | }, 73 | Some( 74 | Node { 75 | kind: Exprs( 76 | [ 77 | Node { 78 | kind: Int( 79 | 42, 80 | ), 81 | loc: Location( 82 | 97, 83 | ), 84 | }, 85 | ], 86 | ), 87 | loc: Location( 88 | 97, 89 | ), 90 | }, 91 | ), 92 | ), 93 | loc: Location( 94 | 0, 95 | ), 96 | } 97 | -------------------------------------------------------------------------------- /eb_lexer/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod location; 2 | pub mod source; 3 | pub mod token; 4 | 5 | use source::Source; 6 | 7 | pub fn tokenize<'a>(source: &'a Source) -> token::TokenStream<'a> { 8 | token::TokenStream::new(source) 9 | } 10 | 11 | #[test] 12 | fn tokenize1() { 13 | use location::Location; 14 | use token::Token; 15 | 16 | let source = Source::String(r#"func f(x i32) i32: x;;"#.to_string()); 17 | let tokenize: Vec = tokenize(&source).into_iter().collect(); 18 | let correct = vec![ 19 | Token::new(token::TokenKind::Ident("func"), Location(0)), 20 | Token::new(token::TokenKind::Ident("f"), Location(5)), 21 | Token::new( 22 | token::TokenKind::OpenDelim(token::DelimKind::Paren), 23 | Location(6), 24 | ), 25 | Token::new(token::TokenKind::Ident("x"), Location(7)), 26 | Token::new(token::TokenKind::Ident("i32"), Location(9)), 27 | Token::new( 28 | token::TokenKind::CloseDelim(token::DelimKind::Paren), 29 | Location(12), 30 | ), 31 | Token::new(token::TokenKind::Ident("i32"), Location(14)), 32 | Token::new( 33 | token::TokenKind::Punct(token::PunctKind::Colon), 34 | Location(17), 35 | ), 36 | Token::new(token::TokenKind::Ident("x"), Location(19)), 37 | Token::new( 38 | token::TokenKind::Punct(token::PunctKind::DoubleSemicolon), 39 | Location(20), 40 | ), 41 | ]; 42 | assert_eq!(tokenize.len(), correct.len()); 43 | assert!(tokenize.iter().zip(correct.iter()).all(|(a, b)| a == b)) 44 | } 45 | 46 | #[test] 47 | fn tokenize2() { 48 | use location::Location; 49 | use token::{DelimKind, PunctKind, Token, TokenKind}; 50 | 51 | let source = Source::String( 52 | r#" 53 | func f(x y i32) i32: 54 | x + 1 == y - 1;; 55 | "# 56 | .to_string(), 57 | ); 58 | let tokenize: Vec = tokenize(&source).into_iter().collect(); 59 | let correct = vec![ 60 | Token::new(TokenKind::Ident("func"), Location(9)), 61 | Token::new(TokenKind::Ident("f"), Location(14)), 62 | Token::new(TokenKind::OpenDelim(DelimKind::Paren), Location(15)), 63 | Token::new(TokenKind::Ident("x"), Location(16)), 64 | Token::new(TokenKind::Ident("y"), Location(18)), 65 | Token::new(TokenKind::Ident("i32"), Location(20)), 66 | Token::new(TokenKind::CloseDelim(DelimKind::Paren), Location(23)), 67 | Token::new(TokenKind::Ident("i32"), Location(25)), 68 | Token::new(TokenKind::Punct(token::PunctKind::Colon), Location(28)), 69 | Token::new(TokenKind::Ident("x"), Location(43)), 70 | Token::new(TokenKind::Punct(PunctKind::Plus), Location(45)), 71 | Token::new(TokenKind::Int("1"), Location(47)), 72 | Token::new(TokenKind::Punct(PunctKind::Eq), Location(49)), 73 | Token::new(TokenKind::Ident("y"), Location(52)), 74 | Token::new(TokenKind::Punct(PunctKind::Minus), Location(54)), 75 | Token::new(TokenKind::Int("1"), Location(56)), 76 | Token::new( 77 | TokenKind::Punct(token::PunctKind::DoubleSemicolon), 78 | Location(57), 79 | ), 80 | ]; 81 | assert_eq!(tokenize.len(), correct.len()); 82 | assert!(tokenize.iter().zip(correct.iter()).all(|(a, b)| a == b)) 83 | } 84 | -------------------------------------------------------------------------------- /eb_parser/src/function.rs: -------------------------------------------------------------------------------- 1 | use super::{expr, Context}; 2 | use crate::{ 3 | ast::function as ast_func, 4 | lexer::token::{DelimKind, PunctKind}, 5 | }; 6 | use anyhow::Result; 7 | 8 | pub fn parse(ctx: &mut Context) -> Result { 9 | ctx.expect_keyword("func")?; 10 | let ident = ctx 11 | .expect_any_ident()? 12 | .kind() 13 | .as_ident() 14 | .unwrap() 15 | .to_string(); 16 | ctx.expect_open_delim(DelimKind::Paren)?; 17 | let params = parse_parameters(ctx)?; 18 | ctx.expect_punct(PunctKind::Colon)?; 19 | let body = expr::parse_body(ctx)?; 20 | Ok(ast_func::Node::new(ident, params, body)) 21 | } 22 | 23 | fn parse_parameters(ctx: &mut Context) -> Result> { 24 | if ctx.skip_close_delim(DelimKind::Paren) { 25 | return Ok(vec![]); 26 | } 27 | let mut params = vec![]; 28 | 29 | loop { 30 | let param = ctx 31 | .expect_any_ident()? 32 | .kind() 33 | .as_ident() 34 | .unwrap() 35 | .to_string(); 36 | params.push(ast_func::Param::new(param)); 37 | 38 | if ctx.skip_punct(PunctKind::Comma) { 39 | continue; 40 | } 41 | 42 | ctx.expect_close_delim(DelimKind::Paren)?; 43 | 44 | return Ok(params); 45 | } 46 | } 47 | 48 | #[cfg(test)] 49 | mod test { 50 | extern crate insta; 51 | use super::*; 52 | use crate::lexer::{source::Source, tokenize}; 53 | 54 | #[test] 55 | fn parse1() { 56 | let source = Source::String(r#"func f(): ;;"#.to_string()); 57 | let mut ctx = Context::new(tokenize(&source)); 58 | insta::assert_debug_snapshot!(parse(&mut ctx).expect("fail to parse")); 59 | } 60 | 61 | #[test] 62 | fn parse2() { 63 | let source = Source::String(r#"func f(x): ;;"#.to_string()); 64 | let mut ctx = Context::new(tokenize(&source)); 65 | insta::assert_debug_snapshot!(parse(&mut ctx).expect("fail to parse")); 66 | } 67 | 68 | #[test] 69 | fn parse3() { 70 | let source = Source::String(r#"func f(x, y): ;;"#.to_string()); 71 | let mut ctx = Context::new(tokenize(&source)); 72 | insta::assert_debug_snapshot!(parse(&mut ctx).expect("fail to parse")); 73 | } 74 | 75 | #[test] 76 | fn parse4() { 77 | let source = Source::String(r#"func f(x): x;;"#.to_string()); 78 | let mut ctx = Context::new(tokenize(&source)); 79 | insta::assert_debug_snapshot!(parse(&mut ctx).expect("fail to parse")); 80 | } 81 | 82 | #[test] 83 | fn parse5() { 84 | let source = Source::String(r#"func f(x): x;;"#.to_string()); 85 | let mut ctx = Context::new(tokenize(&source)); 86 | insta::assert_debug_snapshot!(parse(&mut ctx).expect("fail to parse")); 87 | } 88 | 89 | #[test] 90 | fn parse6() { 91 | let source = Source::String( 92 | r#" 93 | func fact(x): 94 | if x == 1: 95 | return 1 ;; 96 | x * fact(x - 1) ;; 97 | "# 98 | .to_string(), 99 | ); 100 | let mut ctx = Context::new(tokenize(&source)); 101 | insta::assert_debug_snapshot!(parse(&mut ctx).expect("fail to parse")); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /eb_parser/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate eb_ast as ast; 2 | extern crate eb_lexer as lexer; 3 | 4 | pub mod expr; 5 | pub mod function; 6 | 7 | use anyhow::Result; 8 | use lexer::{ 9 | location::Location, 10 | token::{DelimKind, PunctKind, Token, TokenKind, TokenStream}, 11 | }; 12 | use std::{error::Error as StdErr, fmt, iter::Peekable}; 13 | 14 | #[derive(Debug)] 15 | pub enum Error { 16 | ExpectedKeyword(Location, &'static str), 17 | ExpectedAnyIdent(Location), 18 | ExpectedOpenDelim(Location, DelimKind), 19 | ExpectedCloseDelim(Location, DelimKind), 20 | ExpectedPunct(Location, PunctKind), 21 | ExpectedAny(Location, &'static str), 22 | EOF, 23 | } 24 | 25 | pub struct Context<'a> { 26 | tokens: Peekable>, 27 | } 28 | 29 | impl<'a> Context<'a> { 30 | pub fn new(tokens: TokenStream<'a>) -> Self { 31 | Self { 32 | tokens: tokens.peekable(), 33 | } 34 | } 35 | 36 | pub fn peek(&mut self) -> Option<&Token> { 37 | self.tokens.peek() 38 | } 39 | 40 | pub fn next(&mut self) -> Option { 41 | self.tokens.next() 42 | } 43 | 44 | pub fn cur_loc(&mut self) -> Result { 45 | self.peek().map_or(Err(Error::EOF.into()), |t| Ok(*t.loc())) 46 | } 47 | 48 | pub fn expect_keyword(&mut self, kwd: &'static str) -> Result { 49 | if let Some(tok) = self.peek() { 50 | return match tok.kind() { 51 | TokenKind::Ident(i) if i == &kwd => Ok(self.next().unwrap()), 52 | _ => Err(Error::ExpectedKeyword(*tok.loc(), kwd).into()), 53 | }; 54 | } 55 | Err(Error::EOF.into()) 56 | } 57 | 58 | pub fn expect_any_ident(&mut self) -> Result { 59 | if let Some(tok) = self.peek() { 60 | return match tok.kind() { 61 | TokenKind::Ident(_) => Ok(self.next().unwrap()), 62 | _ => Err(Error::ExpectedAnyIdent(*tok.loc()).into()), 63 | }; 64 | } 65 | Err(Error::EOF.into()) 66 | } 67 | 68 | pub fn expect_open_delim(&mut self, delim: DelimKind) -> Result { 69 | if let Some(tok) = self.peek() { 70 | return match tok.kind() { 71 | TokenKind::OpenDelim(d) if d == &delim => Ok(self.next().unwrap()), 72 | _ => Err(Error::ExpectedOpenDelim(*tok.loc(), delim).into()), 73 | }; 74 | } 75 | Err(Error::EOF.into()) 76 | } 77 | 78 | pub fn expect_close_delim(&mut self, delim: DelimKind) -> Result { 79 | match self.peek() { 80 | Some(tok) => match tok.kind() { 81 | TokenKind::CloseDelim(d) if d == &delim => Ok(self.next().unwrap()), 82 | _ => Err(Error::ExpectedCloseDelim(*tok.loc(), delim).into()), 83 | }, 84 | None => Err(Error::EOF.into()), 85 | } 86 | } 87 | 88 | pub fn expect_punct(&mut self, punct: PunctKind) -> Result { 89 | match self.peek() { 90 | Some(tok) => match tok.kind() { 91 | TokenKind::Punct(p) if p == &punct => Ok(self.next().unwrap()), 92 | _ => Err(Error::ExpectedPunct(*tok.loc(), punct).into()), 93 | }, 94 | None => Err(Error::EOF.into()), 95 | } 96 | } 97 | 98 | pub fn skip_keyword(&mut self, kwd: &'static str) -> bool { 99 | self.expect_keyword(kwd).is_ok() 100 | } 101 | 102 | pub fn skip_close_delim(&mut self, delim: DelimKind) -> bool { 103 | self.expect_close_delim(delim).is_ok() 104 | } 105 | 106 | pub fn skip_punct(&mut self, punct: PunctKind) -> bool { 107 | self.expect_punct(punct).is_ok() 108 | } 109 | } 110 | 111 | impl StdErr for Error {} 112 | 113 | impl fmt::Display for Error { 114 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 115 | write!(f, "{:?}", self) 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /eb_parser/src/snapshots/eb_parser__function__test__parse6.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/function.rs 3 | expression: "parse(&mut ctx).expect(\"fail to parse\")" 4 | 5 | --- 6 | Node { 7 | name: "fact", 8 | params: [ 9 | Param { 10 | name: "x", 11 | }, 12 | ], 13 | body: Node { 14 | kind: Exprs( 15 | [ 16 | Node { 17 | kind: If( 18 | Node { 19 | kind: BinOp( 20 | Eq, 21 | Node { 22 | kind: Ident( 23 | "x", 24 | ), 25 | loc: Location( 26 | 47, 27 | ), 28 | }, 29 | Node { 30 | kind: Int( 31 | 1, 32 | ), 33 | loc: Location( 34 | 52, 35 | ), 36 | }, 37 | ), 38 | loc: Location( 39 | 49, 40 | ), 41 | }, 42 | Node { 43 | kind: Exprs( 44 | [ 45 | Node { 46 | kind: Return( 47 | Node { 48 | kind: Int( 49 | 1, 50 | ), 51 | loc: Location( 52 | 82, 53 | ), 54 | }, 55 | ), 56 | loc: Location( 57 | 75, 58 | ), 59 | }, 60 | ], 61 | ), 62 | loc: Location( 63 | 75, 64 | ), 65 | }, 66 | None, 67 | ), 68 | loc: Location( 69 | 44, 70 | ), 71 | }, 72 | Node { 73 | kind: BinOp( 74 | Mul, 75 | Node { 76 | kind: Ident( 77 | "x", 78 | ), 79 | loc: Location( 80 | 103, 81 | ), 82 | }, 83 | Node { 84 | kind: Call( 85 | Node { 86 | kind: Ident( 87 | "fact", 88 | ), 89 | loc: Location( 90 | 107, 91 | ), 92 | }, 93 | [ 94 | Node { 95 | kind: BinOp( 96 | Sub, 97 | Node { 98 | kind: Ident( 99 | "x", 100 | ), 101 | loc: Location( 102 | 112, 103 | ), 104 | }, 105 | Node { 106 | kind: Int( 107 | 1, 108 | ), 109 | loc: Location( 110 | 116, 111 | ), 112 | }, 113 | ), 114 | loc: Location( 115 | 114, 116 | ), 117 | }, 118 | ], 119 | ), 120 | loc: Location( 121 | 111, 122 | ), 123 | }, 124 | ), 125 | loc: Location( 126 | 105, 127 | ), 128 | }, 129 | ], 130 | ), 131 | loc: Location( 132 | 44, 133 | ), 134 | }, 135 | } 136 | -------------------------------------------------------------------------------- /eb_lexer/src/token.rs: -------------------------------------------------------------------------------- 1 | use super::{location::Location, source::Source}; 2 | use nom::{ 3 | branch::alt, 4 | bytes::complete::{tag, take_until, take_while1}, 5 | character::complete::{char, digit1, multispace0}, 6 | combinator::map, 7 | error::VerboseError, 8 | multi::many1, 9 | sequence::{preceded, terminated, tuple}, 10 | IResult, 11 | }; 12 | 13 | #[derive(Debug, Clone, PartialEq)] 14 | pub struct Token<'a> { 15 | kind: TokenKind<'a>, 16 | loc: Location, 17 | } 18 | 19 | #[derive(Debug, Clone, PartialEq)] 20 | pub enum TokenKind<'a> { 21 | Int(&'a str), 22 | Ident(&'a str), 23 | OpenDelim(DelimKind), 24 | CloseDelim(DelimKind), 25 | Punct(PunctKind), 26 | } 27 | 28 | #[derive(Debug, Clone, Copy, PartialEq)] 29 | pub enum DelimKind { 30 | Paren, 31 | Bracket, 32 | Brace, 33 | } 34 | 35 | #[derive(Debug, Clone, Copy, PartialEq)] 36 | pub enum PunctKind { 37 | Plus, 38 | Minus, 39 | Star, 40 | Slash, 41 | Eq, 42 | Neq, 43 | Colon, 44 | Semicolon, 45 | DoubleSemicolon, 46 | Comma, 47 | } 48 | 49 | pub struct TokenStream<'a> { 50 | source: &'a Source, 51 | tokens: Vec>, 52 | body: &'a String, 53 | cur: &'a str, 54 | } 55 | 56 | impl<'a> Token<'a> { 57 | pub fn new(kind: TokenKind<'a>, loc: Location) -> Self { 58 | Self { kind, loc } 59 | } 60 | 61 | pub fn kind(&self) -> &TokenKind { 62 | &self.kind 63 | } 64 | 65 | pub fn loc(&self) -> &Location { 66 | &self.loc 67 | } 68 | } 69 | 70 | impl<'a> TokenKind<'a> { 71 | pub fn as_ident(&self) -> Option<&'a str> { 72 | match self { 73 | Self::Ident(i) => Some(i), 74 | _ => None, 75 | } 76 | } 77 | 78 | pub fn from_str(s: &str) -> Option { 79 | match s { 80 | ":" => Some(Self::Punct(PunctKind::Colon)), 81 | ";" => Some(Self::Punct(PunctKind::Semicolon)), 82 | ";;" => Some(Self::Punct(PunctKind::DoubleSemicolon)), 83 | "," => Some(Self::Punct(PunctKind::Comma)), 84 | "(" => Some(Self::OpenDelim(DelimKind::Paren)), 85 | ")" => Some(Self::CloseDelim(DelimKind::Paren)), 86 | "{" => Some(Self::OpenDelim(DelimKind::Brace)), 87 | "}" => Some(Self::CloseDelim(DelimKind::Brace)), 88 | "[" => Some(Self::OpenDelim(DelimKind::Bracket)), 89 | "]" => Some(Self::CloseDelim(DelimKind::Bracket)), 90 | "+" => Some(Self::Punct(PunctKind::Plus)), 91 | "-" => Some(Self::Punct(PunctKind::Minus)), 92 | "*" => Some(Self::Punct(PunctKind::Star)), 93 | "/" => Some(Self::Punct(PunctKind::Slash)), 94 | "==" => Some(Self::Punct(PunctKind::Eq)), 95 | "!=" => Some(Self::Punct(PunctKind::Neq)), 96 | _ => None, 97 | } 98 | } 99 | } 100 | 101 | impl<'a> TokenStream<'a> { 102 | pub fn new(source: &'a Source) -> Self { 103 | let body = source.body(); 104 | Self { 105 | source, 106 | tokens: vec![], 107 | body, 108 | cur: body.as_str(), 109 | } 110 | } 111 | 112 | pub fn source(&self) -> &Source { 113 | self.source 114 | } 115 | } 116 | 117 | impl<'a> Iterator for TokenStream<'a> { 118 | type Item = Token<'a>; 119 | 120 | fn next(&mut self) -> Option { 121 | let bgn = self.body.as_str().as_ptr() as usize; 122 | let loc = |source: &str| -> Location { Location((source.as_ptr() as usize - bgn) as u32) }; 123 | if let Some((source, token)) = preceded( 124 | spaces, 125 | alt(( 126 | map(digit1, |i: &str| Token::new(TokenKind::Int(i), loc(i))), 127 | map(delimiter, |s: &str| { 128 | Token::new(TokenKind::from_str(s).unwrap(), loc(s)) 129 | }), 130 | map(symbol, |s: &str| { 131 | Token::new(TokenKind::from_str(s).unwrap(), loc(s)) 132 | }), 133 | map(identifier, |i: &str| { 134 | Token::new(TokenKind::Ident(i), loc(i)) 135 | }), 136 | )), 137 | )(self.cur) 138 | .ok() 139 | { 140 | self.cur = source; 141 | self.tokens.push(token.clone()); 142 | return Some(token); 143 | } 144 | None 145 | } 146 | } 147 | 148 | pub fn symbol(source: &str) -> IResult<&str, &str, VerboseError<&str>> { 149 | alt(( 150 | tag(":"), 151 | tag(";;"), 152 | tag(";"), 153 | tag(","), 154 | tag("+"), 155 | tag("-"), 156 | tag("*"), 157 | tag("/"), 158 | tag("=="), 159 | tag("!="), 160 | ))(source) 161 | } 162 | 163 | pub fn delimiter(source: &str) -> IResult<&str, &str, VerboseError<&str>> { 164 | alt((tag("("), tag(")"), tag("["), tag("]"), tag("{"), tag("}")))(source) 165 | } 166 | 167 | pub fn identifier(source: &str) -> IResult<&str, &str, VerboseError<&str>> { 168 | take_while1(|c: char| c.is_alphanumeric() || c == '_')(source) 169 | } 170 | 171 | pub fn spaces(source: &str) -> IResult<&str, (), VerboseError<&str>> { 172 | alt(( 173 | map( 174 | many1(tuple(( 175 | multispace0, 176 | preceded(tag("//"), terminated(take_until("\n"), char('\n'))), 177 | multispace0, 178 | ))), 179 | |_| (), 180 | ), 181 | map(multispace0, |_| ()), 182 | ))(source) 183 | } 184 | -------------------------------------------------------------------------------- /eb_vm/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate eb_vm_ctx as vm_ctx; 2 | extern crate rustc_hash; 3 | 4 | use rustc_hash::FxHashMap; 5 | use vm_ctx::inst::Inst; 6 | use vm_ctx::value::Value; 7 | use vm_ctx::FunctionContext; 8 | 9 | pub struct VM { 10 | pub stack: Vec, 11 | pub env: Vec>, 12 | } 13 | 14 | impl Default for VM { 15 | fn default() -> Self { 16 | Self { 17 | stack: vec![], 18 | env: vec![], 19 | } 20 | } 21 | } 22 | 23 | impl VM { 24 | fn lookup(&mut self, s: &str) -> Option<&Value> { 25 | for e in self.env.iter().rev() { 26 | if let Some(v) = e.get(s) { 27 | return Some(v); 28 | } 29 | } 30 | None 31 | } 32 | 33 | pub fn run(&mut self, ctx: &FunctionContext) { 34 | self.env.push({ 35 | let mut map = FxHashMap::default(); 36 | for child in &ctx.children { 37 | map.insert(child.name.clone(), Value::Func(Box::new(child.clone()))); 38 | } 39 | map 40 | }); 41 | 42 | let mut pc_stack = vec![0]; 43 | let mut code_stack = vec![ctx.code.0.clone()]; 44 | loop { 45 | if *pc_stack.last().unwrap() >= code_stack.last().unwrap().len() { 46 | self.env.pop().unwrap(); 47 | code_stack.pop(); 48 | pc_stack.pop(); 49 | if self.env.len() == 1 { 50 | break; 51 | } 52 | } 53 | let inst = &code_stack.last().unwrap()[*pc_stack.last().unwrap()]; 54 | match inst { 55 | Inst::PushInt(i) => { 56 | self.stack.push(Value::Int(*i)); 57 | *pc_stack.last_mut().unwrap() += 1; 58 | } 59 | Inst::PushStr(s) => { 60 | self.stack.push(Value::String(s.clone())); 61 | *pc_stack.last_mut().unwrap() += 1; 62 | } 63 | Inst::Get(s) => { 64 | let val = self.lookup(s).unwrap().clone(); 65 | self.stack.push(val.clone()); 66 | *pc_stack.last_mut().unwrap() += 1; 67 | } 68 | Inst::Call => { 69 | *pc_stack.last_mut().unwrap() += 1; 70 | let callee = self.stack.pop().unwrap(); 71 | match callee { 72 | Value::Func(func) => { 73 | let mut args = vec![]; 74 | for _ in 0..func.param_names.len() { 75 | args.push(self.stack.pop().unwrap()); 76 | } 77 | self.env.push({ 78 | let mut map = FxHashMap::default(); 79 | for child in &func.children { 80 | map.insert( 81 | child.name.clone(), 82 | Value::Func(Box::new(child.clone())), 83 | ); 84 | } 85 | for (param, val) in 86 | func.param_names.iter().zip(args.into_iter().rev()) 87 | { 88 | map.insert(param.clone(), val); 89 | } 90 | map 91 | }); 92 | pc_stack.push(0); 93 | code_stack.push(func.code.0.clone()); 94 | continue; 95 | } 96 | _ => todo!(), 97 | } 98 | } 99 | Inst::Sub => { 100 | let rhs = self.stack.pop().unwrap(); 101 | let lhs = self.stack.pop().unwrap(); 102 | match (lhs, rhs) { 103 | (Value::Int(lhs), Value::Int(rhs)) => { 104 | self.stack.push(Value::Int(lhs - rhs)); 105 | } 106 | _ => todo!(), 107 | } 108 | *pc_stack.last_mut().unwrap() += 1; 109 | } 110 | Inst::Mul => { 111 | let rhs = self.stack.pop().unwrap(); 112 | let lhs = self.stack.pop().unwrap(); 113 | match (lhs, rhs) { 114 | (Value::Int(lhs), Value::Int(rhs)) => { 115 | self.stack.push(Value::Int(lhs * rhs)); 116 | } 117 | _ => todo!(), 118 | } 119 | *pc_stack.last_mut().unwrap() += 1; 120 | } 121 | Inst::Eq => { 122 | let rhs = self.stack.pop().unwrap(); 123 | let lhs = self.stack.pop().unwrap(); 124 | match (lhs, rhs) { 125 | (Value::Int(lhs), Value::Int(rhs)) => { 126 | self.stack.push(Value::Bool(lhs == rhs)); 127 | } 128 | _ => todo!(), 129 | } 130 | *pc_stack.last_mut().unwrap() += 1; 131 | } 132 | Inst::Jne(offset) => { 133 | let val = self.stack.pop().unwrap(); 134 | match val { 135 | Value::Bool(false) => { 136 | *pc_stack.last_mut().unwrap() += *offset as usize; 137 | } 138 | _ => { 139 | *pc_stack.last_mut().unwrap() += 1; 140 | } 141 | } 142 | } 143 | Inst::Ret => { 144 | self.env.pop().unwrap(); 145 | code_stack.pop(); 146 | pc_stack.pop(); 147 | continue; 148 | } 149 | } 150 | } 151 | } 152 | } 153 | 154 | #[test] 155 | fn vm1() { 156 | extern crate eb_codegen_fast as codegen; 157 | extern crate eb_lexer as lexer; 158 | extern crate eb_parser as parser; 159 | use codegen::expr::visit; 160 | use lexer::{source::Source, tokenize}; 161 | use parser::{expr::parse_body, Context as ParserContext}; 162 | 163 | let source = Source::String( 164 | r#" 165 | func f(x): 166 | if x == 1: 167 | return 1 ;; 168 | x * f(x - 1) ;; 169 | f(10) ;;"# 170 | .to_string(), 171 | ); 172 | let mut ctx = ParserContext::new(tokenize(&source)); 173 | let node = parse_body(&mut ctx).expect("fail to parse"); 174 | let mut ctx_ = FunctionContext::default(); 175 | visit(&mut ctx_, &node).unwrap(); 176 | let mut vm = VM::default(); 177 | vm.run(&ctx_); 178 | assert!(matches!(vm.stack.pop().unwrap(), Value::Int(3628800))); 179 | } 180 | -------------------------------------------------------------------------------- /eb_parser/src/expr.rs: -------------------------------------------------------------------------------- 1 | use super::{function, Context, Error}; 2 | use crate::{ 3 | ast::expr, 4 | lexer::token::{DelimKind, PunctKind, TokenKind}, 5 | }; 6 | use anyhow::Result; 7 | 8 | pub fn parse(ctx: &mut Context) -> Result { 9 | parse_binop_eq_ne(ctx) 10 | } 11 | 12 | fn parse_binop_eq_ne(ctx: &mut Context) -> Result { 13 | let mut lhs = parse_binop_add_sub(ctx)?; 14 | loop { 15 | let loc = ctx.cur_loc(); 16 | 17 | let eq = ctx.skip_punct(PunctKind::Eq); 18 | let neq = ctx.skip_punct(PunctKind::Neq); 19 | 20 | if !eq && !neq { 21 | break; 22 | } 23 | 24 | let loc = loc?; 25 | let rhs = parse_binop_add_sub(ctx)?; 26 | 27 | lhs = expr::Node::new( 28 | expr::Kind::BinOp( 29 | if eq { 30 | expr::BinOpKind::Eq 31 | } else { 32 | expr::BinOpKind::Neq 33 | }, 34 | Box::new(lhs.clone()), 35 | Box::new(rhs), 36 | ), 37 | loc, 38 | ); 39 | } 40 | Ok(lhs) 41 | } 42 | 43 | fn parse_binop_add_sub(ctx: &mut Context) -> Result { 44 | let mut lhs = parse_binop_mul_div(ctx)?; 45 | loop { 46 | let loc = ctx.cur_loc(); 47 | 48 | let plus = ctx.skip_punct(PunctKind::Plus); 49 | let minus = ctx.skip_punct(PunctKind::Minus); 50 | 51 | if !plus && !minus { 52 | break; 53 | } 54 | 55 | let loc = loc?; 56 | let rhs = parse_binop_mul_div(ctx)?; 57 | 58 | lhs = expr::Node::new( 59 | expr::Kind::BinOp( 60 | if plus { 61 | expr::BinOpKind::Add 62 | } else { 63 | expr::BinOpKind::Sub 64 | }, 65 | Box::new(lhs.clone()), 66 | Box::new(rhs), 67 | ), 68 | loc, 69 | ); 70 | } 71 | Ok(lhs) 72 | } 73 | 74 | fn parse_binop_mul_div(ctx: &mut Context) -> Result { 75 | let mut lhs = parse_postfix(ctx)?; 76 | loop { 77 | let loc = ctx.cur_loc(); 78 | 79 | let star = ctx.skip_punct(PunctKind::Star); 80 | let slash = ctx.skip_punct(PunctKind::Slash); 81 | 82 | if !star && !slash { 83 | break; 84 | } 85 | 86 | let loc = loc?; 87 | let rhs = parse_postfix(ctx)?; 88 | 89 | lhs = expr::Node::new( 90 | expr::Kind::BinOp( 91 | if star { 92 | expr::BinOpKind::Mul 93 | } else { 94 | expr::BinOpKind::Div 95 | }, 96 | Box::new(lhs.clone()), 97 | Box::new(rhs), 98 | ), 99 | loc, 100 | ); 101 | } 102 | Ok(lhs) 103 | } 104 | 105 | fn parse_postfix(ctx: &mut Context) -> Result { 106 | let base = parse_primary(ctx)?; 107 | let peek = match ctx.peek() { 108 | Some(peek) => peek, 109 | None => return Ok(base), 110 | }; 111 | let loc = *peek.loc(); 112 | match peek.kind() { 113 | // Call 114 | TokenKind::OpenDelim(DelimKind::Paren) => { 115 | assert!(ctx.next().is_some()); 116 | Ok(expr::Node::new( 117 | expr::Kind::Call(Box::new(base), parse_call_args(ctx)?), 118 | loc, 119 | )) 120 | } 121 | _ => Ok(base), 122 | } 123 | } 124 | 125 | fn parse_call_args(ctx: &mut Context) -> Result> { 126 | if ctx.skip_close_delim(DelimKind::Paren) { 127 | return Ok(vec![]); 128 | } 129 | 130 | let mut args = vec![]; 131 | 132 | loop { 133 | let arg = parse(ctx)?; 134 | args.push(arg); 135 | 136 | if ctx.skip_punct(PunctKind::Comma) { 137 | continue; 138 | } 139 | 140 | ctx.expect_close_delim(DelimKind::Paren)?; 141 | 142 | break; 143 | } 144 | 145 | Ok(args) 146 | } 147 | 148 | fn parse_primary(ctx: &mut Context) -> Result { 149 | let peek = ctx.peek().ok_or(Error::EOF)?; 150 | let loc = *peek.loc(); 151 | match peek.kind() { 152 | TokenKind::Int(int) => { 153 | let int = int.parse().unwrap(); 154 | ctx.next().unwrap(); 155 | Ok(expr::Node::new(expr::Kind::Int(int), loc)) 156 | } 157 | TokenKind::Ident(ident) if ident == &"func" => Ok(expr::Node::new( 158 | expr::Kind::Function(Box::new(function::parse(ctx)?)), 159 | loc, 160 | )), 161 | TokenKind::Ident(ident) if ident == &"if" => Ok(expr::Node::new(parse_if(ctx)?, loc)), 162 | TokenKind::Ident(ident) if ident == &"return" => { 163 | Ok(expr::Node::new(parse_return(ctx)?, loc)) 164 | } 165 | TokenKind::Ident(ident) => { 166 | let ident = ident.to_string(); 167 | ctx.next().unwrap(); 168 | Ok(expr::Node::new(expr::Kind::Ident(ident), loc)) 169 | } 170 | _ => Err(Error::ExpectedAny(loc, "integer value or identifier").into()), 171 | } 172 | } 173 | 174 | fn parse_if(ctx: &mut Context) -> Result { 175 | ctx.expect_keyword("if")?; 176 | let cond = parse(ctx)?; 177 | ctx.expect_punct(PunctKind::Colon)?; 178 | let then_expr = parse_body(ctx)?; 179 | let else_expr; 180 | if ctx.skip_keyword("else") { 181 | ctx.expect_punct(PunctKind::Colon)?; 182 | else_expr = Some(Box::new(parse_body(ctx)?)); 183 | } else { 184 | else_expr = None; 185 | } 186 | Ok(expr::Kind::If( 187 | Box::new(cond), 188 | Box::new(then_expr), 189 | else_expr, 190 | )) 191 | } 192 | 193 | fn parse_return(ctx: &mut Context) -> Result { 194 | ctx.expect_keyword("return")?; 195 | Ok(expr::Kind::Return(Box::new(parse(ctx)?))) 196 | } 197 | 198 | pub fn parse_body(ctx: &mut Context) -> Result { 199 | let loc = ctx.cur_loc(); 200 | 201 | if ctx.skip_punct(PunctKind::DoubleSemicolon) { 202 | return Ok(expr::Node::new(expr::Kind::Exprs(vec![]), loc?)); 203 | } 204 | 205 | let mut body = vec![]; 206 | 207 | loop { 208 | body.push(parse(ctx)?); 209 | 210 | if ctx.skip_punct(PunctKind::Semicolon) { 211 | continue; 212 | } 213 | 214 | if ctx.skip_punct(PunctKind::DoubleSemicolon) { 215 | return Ok(expr::Node::new(expr::Kind::Exprs(body), loc?)); 216 | } 217 | } 218 | } 219 | 220 | #[cfg(test)] 221 | mod test { 222 | extern crate insta; 223 | use super::*; 224 | use crate::lexer::{source::Source, tokenize}; 225 | 226 | fn parse_str(s: &str) -> expr::Node { 227 | let source = Source::String(s.to_string()); 228 | let mut ctx = Context::new(tokenize(&source)); 229 | parse(&mut ctx).expect("fail to parse") 230 | } 231 | 232 | #[test] 233 | fn parse1() { 234 | insta::assert_debug_snapshot!(parse_str(r#"x"#)); 235 | } 236 | 237 | #[test] 238 | fn parse2() { 239 | insta::assert_debug_snapshot!(parse_str(r#"x +x"#)); 240 | } 241 | 242 | #[test] 243 | fn parse3() { 244 | insta::assert_debug_snapshot!(parse_str(r#"123 + x"#)); 245 | } 246 | 247 | #[test] 248 | fn parse4() { 249 | insta::assert_debug_snapshot!(parse_str(r#"1 * 2 + 3"#)); 250 | } 251 | 252 | #[test] 253 | fn parse5() { 254 | insta::assert_debug_snapshot!(parse_str(r#"f()"#)); 255 | } 256 | 257 | #[test] 258 | fn parse6() { 259 | insta::assert_debug_snapshot!(parse_str(r#"f(1, x)"#)); 260 | } 261 | 262 | #[test] 263 | fn parse7() { 264 | insta::assert_debug_snapshot!(parse_str(r#"x == x"#)); 265 | } 266 | 267 | #[test] 268 | fn parse8() { 269 | insta::assert_debug_snapshot!(parse_str(r#"x != x"#)); 270 | } 271 | 272 | #[test] 273 | fn parse9() { 274 | insta::assert_debug_snapshot!(parse_str( 275 | r#"if x == 1: 276 | 123;;"# 277 | )); 278 | } 279 | 280 | #[test] 281 | fn parse10() { 282 | insta::assert_debug_snapshot!(parse_str( 283 | r#"if x == 1: 284 | x + 1 ; 285 | x ;; 286 | else: 287 | 42;;"# 288 | )); 289 | } 290 | 291 | #[test] 292 | fn parse11() { 293 | insta::assert_debug_snapshot!(parse_str(r#"return 123"#)); 294 | } 295 | } 296 | --------------------------------------------------------------------------------