├── showcase ├── library │ ├── init.wu │ └── other.wu ├── samples │ ├── lover.wu │ ├── importer.wu │ └── traits.wu ├── tuples.wu ├── splats2.wu ├── optionals.wu ├── stress_stest.wu ├── wulibs_test.wu ├── switch.wu ├── compound_ops.wu ├── extern_implement.wu ├── screenshot.wu ├── struct.wu ├── example.wu ├── for.wu ├── splats.wu └── for.lua ├── src ├── wu │ ├── handler │ │ ├── mod.rs │ │ └── handler.rs │ ├── mod.rs │ ├── compiler │ │ ├── mod.rs │ │ └── compiler.rs │ ├── parser │ │ ├── mod.rs │ │ ├── ast.rs │ │ └── parser.rs │ ├── visitor │ │ ├── mod.rs │ │ └── symtab.rs │ ├── lexer │ │ ├── mod.rs │ │ ├── token.rs │ │ ├── tokenizer.rs │ │ ├── lexer.rs │ │ └── matcher.rs │ ├── error.rs │ └── source.rs └── main.rs ├── .github ├── FUNDING.yml └── workflows │ └── ci.yml ├── .gitignore ├── mkdocs.yml ├── docs └── index.md ├── Cargo.toml ├── LICENSE ├── README.md └── Cargo.lock /showcase/library/init.wu: -------------------------------------------------------------------------------- 1 | import other { lol } -------------------------------------------------------------------------------- /src/wu/handler/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod handler; 2 | pub use self::handler::*; 3 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [nilq] 4 | -------------------------------------------------------------------------------- /showcase/samples/lover.wu: -------------------------------------------------------------------------------- 1 | love: extern module { 2 | pub conf: fun(t: any) {} 3 | } 4 | 5 | love conf = fun(t: any) { 6 | t window width = 800 7 | } 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # These are backup files generated by rustfmt 6 | **/*.rs.bk 7 | -------------------------------------------------------------------------------- /showcase/library/other.wu: -------------------------------------------------------------------------------- 1 | bar: module { 2 | pub foo: fun() -> int { 42 } 3 | oof: fun() -> int { 24 } 4 | } 5 | 6 | a := bar foo() # 42 7 | 8 | pub lol := 100 -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: The Wu Language 2 | theme: 3 | name: material 4 | palette: 5 | - scheme: default 6 | primary: purple 7 | accent: deep-purple 8 | -------------------------------------------------------------------------------- /showcase/samples/importer.wu: -------------------------------------------------------------------------------- 1 | import traits { foo , Player } 2 | import lover { love } 3 | 4 | a := new Player { 5 | x: 100.0 6 | y: 100.0 7 | } 8 | 9 | a move(10, 10) -------------------------------------------------------------------------------- /src/wu/mod.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | pub mod error; 3 | pub mod compiler; 4 | pub mod handler; 5 | pub mod lexer; 6 | pub mod parser; 7 | pub mod source; 8 | pub mod visitor; 9 | -------------------------------------------------------------------------------- /showcase/tuples.wu: -------------------------------------------------------------------------------- 1 | foo: (int, float) = (1, 1.0) 2 | 3 | bar: fun -> (int, float) { 4 | foo 5 | } 6 | 7 | lol: fun -> (float, float, float) { 8 | (1.0, 2.0, 3.0) 9 | } -------------------------------------------------------------------------------- /src/wu/compiler/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod compiler; 2 | 3 | use super::lexer::*; 4 | use super::parser::*; 5 | use super::source::*; 6 | use super::visitor::*; 7 | 8 | pub use self::compiler::*; 9 | -------------------------------------------------------------------------------- /src/wu/parser/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod ast; 2 | pub mod parser; 3 | 4 | use super::lexer::*; 5 | use super::source::*; 6 | use super::visitor::*; 7 | 8 | pub use self::ast::*; 9 | pub use self::parser::*; 10 | -------------------------------------------------------------------------------- /showcase/splats2.wu: -------------------------------------------------------------------------------- 1 | foo: int 2 | bar: int 3 | 4 | foo, bar = 100, 100, 1 5 | 6 | a, b := 10, 10 7 | 8 | y: int = b 9 | 10 | waps: fun -> ...int { 11 | 1, 2, 3 12 | } 13 | 14 | foo, bar, b := 1, 2, 3 -------------------------------------------------------------------------------- /src/wu/visitor/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod symtab; 2 | pub mod visitor; 3 | 4 | use super::lexer::*; 5 | use super::parser::*; 6 | use super::source::*; 7 | 8 | pub use self::symtab::*; 9 | pub use self::visitor::*; 10 | -------------------------------------------------------------------------------- /showcase/optionals.wu: -------------------------------------------------------------------------------- 1 | print: extern fun(...?) 2 | 3 | bee: int? = 100 + 10 4 | buzz: int = bee! 5 | foo: int? = bee 6 | 7 | print(bee, buzz, foo, nil) 8 | 9 | foo: fun -> [int] { 10 | [1, 2, 3, 4] 11 | } -------------------------------------------------------------------------------- /showcase/stress_stest.wu: -------------------------------------------------------------------------------- 1 | babs: fun(x: float?) -> nil { 2 | x = nil 3 | x 4 | } 5 | 6 | print: extern fun(...?) 7 | 8 | while true { 9 | print("hey") 10 | 11 | skip 12 | 13 | print("not hey") 14 | } -------------------------------------------------------------------------------- /showcase/wulibs_test.wu: -------------------------------------------------------------------------------- 1 | import test { lol } 2 | import lover { graphics } 3 | 4 | graphics setColor(1, 1, 0) 5 | 6 | import library { lol} 7 | 8 | love: extern module { 9 | foo: extern int 10 | } 11 | 12 | print(lol) -------------------------------------------------------------------------------- /showcase/switch.wu: -------------------------------------------------------------------------------- 1 | a := 10 2 | 3 | print: extern fun(...?) 4 | 5 | b: str? = switch a { 6 | 0 => { 7 | a := 10 8 | print("hey") 9 | nil 10 | } 11 | 1 => print("hello hoy yuo") 12 | 10 => print("it was 10??? all along") 13 | } -------------------------------------------------------------------------------- /src/wu/lexer/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod lexer; 2 | pub mod matcher; 3 | pub mod token; 4 | pub mod tokenizer; 5 | 6 | use super::source::Source; 7 | 8 | pub use self::lexer::*; 9 | pub use self::matcher::*; 10 | pub use self::token::*; 11 | pub use self::tokenizer::*; 12 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # Welcome to Wu 2 | 3 | ## Getting started 4 | 5 | ### Prerequisites 6 | 7 | In order to install the Wu compiler, you first need to have Rust/Cargo installed on your system. 8 | 9 | * `curl https://sh.rustup.rs -sSf | sh` Install Rust. 10 | 11 | ### Installation 12 | 13 | * `cargo install wu` Install the Wu compiler. 14 | -------------------------------------------------------------------------------- /showcase/compound_ops.wu: -------------------------------------------------------------------------------- 1 | Foo: struct { 2 | b: int 3 | } 4 | 5 | grr := new Foo { 6 | b: 100 7 | } 8 | 9 | grr b += 10 10 | 11 | a: int = 100 12 | 13 | a *= 100 14 | a += 10 15 | a /= 10 16 | 17 | c: str = "duggiduggiduk" 18 | 19 | c ++= "hey" 20 | c ++= a 21 | 22 | 23 | lol: fun(x: int) -> int { 24 | return x 25 | } 26 | 27 | print(lol <| 10) 28 | print(10 |> lol |> lol |> lol) -------------------------------------------------------------------------------- /showcase/extern_implement.wu: -------------------------------------------------------------------------------- 1 | File: struct {} 2 | 3 | implement File { 4 | close: extern fun() 5 | flush: extern fun() 6 | lines: extern fun() -> fun 7 | read: extern fun(...?) -> ...? 8 | seek: extern fun(str?, int?) -> int? 9 | setvbuf: extern fun(str?, int?) 10 | write: extern fun(...) 11 | } 12 | 13 | file := new File {} 14 | 15 | file close() -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | on: 3 | push: 4 | branches: 5 | - master 6 | - main 7 | jobs: 8 | deploy: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | - uses: actions/setup-python@v2 13 | with: 14 | python-version: 3.x 15 | - run: pip install mkdocs-material 16 | - run: mkdocs gh-deploy --force 17 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wu" 3 | version = "0.1.0" 4 | authors = ["nilq "] 5 | edition = "2021" 6 | license = "MIT" 7 | description = "A practical game and data language." 8 | 9 | [dependencies] 10 | colored = "2.0.0" 11 | rustyline = "9.0.0" 12 | backtrace = "0.3" 13 | toml = "0.5" 14 | git2 = "0.14" 15 | dirs = "4.0.0" 16 | fs_extra = "1.1.0" 17 | -------------------------------------------------------------------------------- /showcase/screenshot.wu: -------------------------------------------------------------------------------- 1 | Player: struct { 2 | x: float 3 | y: float 4 | name: str? 5 | } 6 | 7 | Moving: trait { 8 | move: fun(self, float, float) 9 | } 10 | 11 | implement Player: Moving { 12 | move: fun(self, dx: float, dy: float) { 13 | self x += dx 14 | self y += dy 15 | } 16 | } 17 | 18 | niels := new Player { 19 | x: 100 20 | y: 200 21 | } 22 | 23 | niels name = "boss man" -------------------------------------------------------------------------------- /showcase/struct.wu: -------------------------------------------------------------------------------- 1 | Foo: struct {} 2 | 3 | Bar: trait { 4 | foobar: fun(int) 5 | } 6 | 7 | implement Foo: Bar { 8 | foobar: fun(a: int) { 9 | nil 10 | } 11 | } 12 | 13 | implement Foo { 14 | boo: fun -> Self { 15 | new Self {} 16 | } 17 | } 18 | 19 | implement Foo { 20 | foo: fun() -> Self { 21 | new Self { 22 | } 23 | } 24 | 25 | bob: fun(self, a: Self) -> Self { 26 | new Self {} 27 | } 28 | } 29 | 30 | fo := Foo foo() -------------------------------------------------------------------------------- /showcase/example.wu: -------------------------------------------------------------------------------- 1 | Vector: struct { 2 | x: float 3 | y: float 4 | } 5 | 6 | Movable: trait { 7 | move: fun(self, float, float) 8 | } 9 | 10 | implement Vector: Movable { 11 | move: fun(self, dx: float, dy: float) { 12 | self x += dx 13 | self y += dy 14 | } 15 | } 16 | 17 | implement Vector { 18 | length: fun(self) -> float { 19 | (self x^2 + self y^2)^0.5 20 | } 21 | } 22 | 23 | position := new Vector { 24 | x: 100 25 | y: 200 26 | } 27 | 28 | position move(10, 10) -------------------------------------------------------------------------------- /showcase/samples/traits.wu: -------------------------------------------------------------------------------- 1 | foo: module { 2 | Moving: trait { 3 | move: fun(self, float, float) 4 | } 5 | } 6 | 7 | Player: struct { 8 | x: float 9 | y: float 10 | } 11 | 12 | implement Player: foo Moving { 13 | move: fun(self, dx: float, dy: float) { 14 | self x = self x + dx 15 | self y = self y + dy 16 | } 17 | } 18 | 19 | here_we_go: fun(hmm: foo Moving) { 20 | hmm move(10, 10) 21 | 22 | print: extern fun(...) 23 | 24 | print((hmm as Player) x) 25 | } 26 | 27 | here_we_go( 28 | new Player { 29 | x: 100 30 | y: 100 31 | } 32 | ) -------------------------------------------------------------------------------- /showcase/for.wu: -------------------------------------------------------------------------------- 1 | i := 0 2 | 3 | for 10 { 4 | if i >= 5 { 5 | break 6 | } 7 | 8 | print("ten times!") 9 | i += 1 10 | } 11 | 12 | list := [1, 2, 3, 3] 13 | 14 | for (x, y) in ipairs(list) { 15 | print(x, y) 16 | } 17 | 18 | # hackerman 19 | range: fun(a: int, b: int) -> ...any { 20 | i := 0 21 | 22 | funky: fun(_: any, last: int) -> int? { 23 | if last + 1 <= b { 24 | return last + 1 25 | } 26 | } 27 | 28 | (funky, nil, a - 1) 29 | } 30 | 31 | for x in range(0, 100) { 32 | print("going to 100 !!", x) 33 | } -------------------------------------------------------------------------------- /showcase/splats.wu: -------------------------------------------------------------------------------- 1 | Vector: struct { 2 | x: float 3 | y: float 4 | z: float 5 | } 6 | 7 | implement Vector { 8 | length: fun(self) -> float { 9 | (self x^2 + self y^2 + self z^2)^0.5 10 | } 11 | 12 | normalize: fun(self) { 13 | len := self length() 14 | 15 | self x /= len 16 | self y /= len 17 | self z /= len 18 | } 19 | } 20 | 21 | # binding lua-code is ez 22 | len: extern fun([any]) -> int = r"function(a) return #a end" 23 | println: extern fun(...) = "print" 24 | 25 | normalize_all: fun(bulk: ...Vector?) { 26 | i := 1 27 | while i < len(bulk) { 28 | vector := bulk[i]! 29 | 30 | println(vector length()) 31 | 32 | vector normalize() 33 | 34 | println(vector length()) 35 | 36 | i += 1 37 | } 38 | } 39 | 40 | a := new Vector { 41 | x: 100 42 | y: 200 43 | z: 300 44 | } 45 | 46 | b := new Vector { 47 | x: 200 48 | y: 300 49 | z: 400 50 | } 51 | 52 | normalize_all(a, b) -------------------------------------------------------------------------------- /src/wu/error.rs: -------------------------------------------------------------------------------- 1 | use colored::Colorize; 2 | use std::fmt; 3 | 4 | pub enum Response { 5 | Wrong(T), 6 | Weird(T), 7 | Note(T), 8 | } 9 | 10 | use self::Response::*; 11 | 12 | #[macro_export] 13 | macro_rules! response { 14 | ( $( $r:expr ),+ ) => {{ 15 | $( 16 | print!("{}", $r); 17 | )* 18 | println!(); 19 | }}; 20 | } 21 | 22 | impl fmt::Display for Response { 23 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 24 | let (color, message_type, message) = match *self { 25 | Wrong(ref m) => ("red", "wrong", m), 26 | Weird(ref m) => ("yellow", "weird", m), 27 | Note(ref m) => ("cyan", "note", m), 28 | }; 29 | 30 | let message_type = format!("\n{}", message_type).color(color).bold(); 31 | let message = format!("{}", message); 32 | 33 | let message = format!("{}: {}", message_type, message); 34 | 35 | write!(f, "{}", message) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/wu/source.rs: -------------------------------------------------------------------------------- 1 | use std::fs::File; 2 | use std::io::prelude::*; 3 | 4 | use std::fmt; 5 | 6 | use colored::Colorize; 7 | 8 | #[derive(Debug)] 9 | pub struct FilePath(pub String); 10 | 11 | impl fmt::Display for FilePath { 12 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 13 | write!(f, "\n{:>8} {}", "-->".blue().bold(), self.0) 14 | } 15 | } 16 | 17 | #[derive(Debug)] 18 | pub struct Source { 19 | pub file: FilePath, 20 | pub lines: Vec, 21 | } 22 | 23 | impl Source { 24 | pub fn new(path: String) -> Self { 25 | let mut source = File::open(path.as_str()).unwrap(); 26 | let mut content = String::new(); 27 | 28 | source.read_to_string(&mut content).unwrap(); 29 | 30 | Source { 31 | file: FilePath(path), 32 | lines: content.lines().map(|x| x.to_string()).collect(), 33 | } 34 | } 35 | 36 | pub fn from(path: &str, lines: Vec) -> Self { 37 | Source { 38 | file: FilePath(path.into()), 39 | lines, 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /showcase/for.lua: -------------------------------------------------------------------------------- 1 | return (function() 2 | local i = 0 3 | 4 | for __iterator_0 = 1, 10 do 5 | 6 | local __brk_0 = false 7 | repeat 8 | if (i >= 5) then 9 | __brk_0 = true break 10 | end 11 | 12 | print("ten times!") 13 | i = (i + 1) 14 | until true 15 | if __brk_0 then break end 16 | end 17 | 18 | local list = { 19 | [1] = 1, 20 | [2] = 2, 21 | [3] = 3, 22 | [4] = 3 23 | } 24 | 25 | for x, y in ipairs(list) do 26 | local __brk_0 = false 27 | repeat 28 | print(x, y) 29 | until true 30 | if __brk_0 then break end 31 | end 32 | 33 | function range(a, b) 34 | local i = 0 35 | function funky(_, last) 36 | if ((last + 1) <= b) then 37 | return (last + 1) 38 | end 39 | end 40 | return funky, nil, (a - 1) 41 | end 42 | 43 | for x in range(0, 100) do 44 | local __brk_0 = false 45 | repeat 46 | print("going to 100 !!", x) 47 | until true 48 | if __brk_0 then break end 49 | end 50 | 51 | return { 52 | i = i, 53 | list = list, 54 | range = range, 55 | } 56 | end)() -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 wu-lang 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | wu_dragon 2 | 3 | # Wu 4 | 5 | [![Foo](https://user-images.githubusercontent.com/7288322/34429152-141689f8-ecb9-11e7-8003-b5a10a5fcb29.png)](https://discord.gg/qm92sPP) 6 | [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/wu-lang/wu/blob/master/LICENSE) 7 | 8 | An expression oriented, gradually typed and mission-critical programming language. 9 | 10 | ## Syntax 11 | 12 | A full walk-through of the language can be found over at the [wu-lang documentation](https://wu-lang.gitbook.io/guide/). 13 | 14 | ### Details 15 | 16 | Wu strives to be a decently useful language with focus on control, readability and scalability. The syntax of Wu is heavily inspired by the strong and safe one of Rust, while keeping the advantages of being high-level and gradually typed. The language is meant and designed to be a solid alternative to Python, Lua and MoonScript, while being superior on control and maintainability. 17 | 18 | ### Example 19 | 20 | code 21 | 22 | ## Selling points 23 | 24 | - [x] Compiles to Lua 25 | - [x] Gradual typing 26 | - [x] Rust-like trait system 27 | - [x] Expression oriented design 28 | - [x] Perfect Lua interoperability 29 | - [x] Match patterns 30 | - [x] Cool logo 31 | - [ ] You are using it 32 | 33 | ## Libraries 34 | 35 | - [`lover`](https://github.com/nilq/lover): Type-safe bindings for the Love2D game engine. 36 | - [`std`](https://github.com/wu-lang/std): Wrapper for the Lua standard library. 37 | 38 | ## Disclaimer 39 | 40 | Wu is built and maintained by a minimal team of people and was primarily developed during boring primary school classes, to help make time pass faster. At the current point in time it is not actively maintained due to work and studies all of us are occupied with, this may change in the future. However, you can still make suggestions, report bugs and open pull requests, one of us will definitely review them. 41 | 42 | ## Contributors 43 | 44 | - [nilq](https://github.com/nilq) 45 | 46 | - [evolbug](https://github.com/evolbug) 47 | 48 | - [fuzzylitchi](https://github.com/fuzzylitchi) 49 | 50 | ### License 51 | 52 | [MIT License](https://github.com/wu-lang/wu/blob/master/LICENSE) 53 | -------------------------------------------------------------------------------- /src/wu/lexer/token.rs: -------------------------------------------------------------------------------- 1 | use colored::Colorize; 2 | use std::fmt; 3 | 4 | #[derive(Debug, Clone, PartialEq)] 5 | pub enum TokenType { 6 | Identifier, 7 | Int, 8 | Float, 9 | Keyword, 10 | Str, 11 | Char, 12 | Symbol, 13 | Operator, 14 | Bool, 15 | Whitespace, 16 | EOL, 17 | EOF, 18 | } 19 | 20 | impl fmt::Display for TokenType { 21 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 22 | use self::TokenType::*; 23 | 24 | match *self { 25 | Identifier => write!(f, "Identifier"), 26 | Int => write!(f, "Int"), 27 | Float => write!(f, "Float"), 28 | Str => write!(f, "Str"), 29 | Char => write!(f, "Char"), 30 | Keyword => write!(f, "Keyword"), 31 | Bool => write!(f, "Bool"), 32 | Symbol => write!(f, "Symbol"), 33 | Operator => write!(f, "Operator"), 34 | Whitespace => write!(f, "Whitespace"), 35 | EOL => write!(f, "EOL"), 36 | EOF => write!(f, "EOF"), 37 | } 38 | } 39 | } 40 | 41 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] 42 | pub struct Pos(pub (usize, String), pub (usize, usize)); 43 | 44 | impl Pos { 45 | pub fn get_lexeme(&self) -> String { 46 | (self.0).1[(self.1).0 - if (self.1).0 > 0 { 1 } else { 0 }..(self.1).1].to_string() 47 | } 48 | } 49 | 50 | impl fmt::Display for Pos { 51 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 52 | let linepad = format!("{:5} │", " ").blue().bold(); 53 | let lineno = format!("{:5} │ ", (self.0).0).blue().bold(); 54 | let mut mark = (self.0).1[(self.1).0.saturating_sub(1)..(self.1).1].to_string(); 55 | 56 | if mark.split_whitespace().count() == 0 { 57 | mark = format!("{:─>count$}", ">".red().bold(), count = mark.len()); 58 | } else { 59 | mark = format!("{}", mark.red().bold()); 60 | } 61 | 62 | let mut arrows = format!("{: Self { 97 | Token { 98 | token_type, 99 | line, 100 | slice, 101 | lexeme: lexeme.to_string(), 102 | } 103 | } 104 | } 105 | 106 | impl fmt::Display for Token { 107 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 108 | write!( 109 | f, 110 | "{}", 111 | Pos( 112 | (self.line.0, self.line.1.clone()), 113 | (self.slice.0, self.slice.1) 114 | ) 115 | ) 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/wu/lexer/tokenizer.rs: -------------------------------------------------------------------------------- 1 | use super::token::*; 2 | use super::{Matcher, Source}; 3 | 4 | pub struct Snapshot { 5 | pub index: usize, 6 | pub pos: (usize, usize), 7 | } 8 | 9 | impl Snapshot { 10 | fn new(index: usize, pos: (usize, usize)) -> Self { 11 | Snapshot { index, pos } 12 | } 13 | } 14 | 15 | pub struct Tokenizer<'t> { 16 | pub pos: (usize, usize), 17 | 18 | pub index: usize, 19 | pub items: Vec, 20 | pub source: &'t Source, 21 | pub snapshots: Vec, 22 | } 23 | 24 | impl<'t> Tokenizer<'t> { 25 | pub fn new(items: Vec, source: &'t Source) -> Self { 26 | Tokenizer { 27 | pos: (1, 0), 28 | 29 | items, 30 | source, 31 | index: 0, 32 | snapshots: Vec::new(), 33 | } 34 | } 35 | 36 | pub fn end(&self) -> bool { 37 | self.index >= self.items.len() 38 | } 39 | 40 | pub fn advance(&mut self) { 41 | if self.items.get(self.index + 1).is_some() { 42 | self.pos.1 += 1 43 | } 44 | 45 | self.index += 1 46 | } 47 | 48 | pub fn advance_n(&mut self, n: usize) { 49 | for _ in 0..n { 50 | self.advance() 51 | } 52 | } 53 | 54 | pub fn peek_range(&self, n: usize) -> Option { 55 | self.items 56 | .get(self.index..self.index + n) 57 | .map(|chars| chars.iter().collect::()) 58 | } 59 | 60 | pub fn peek_n(&self, n: usize) -> Option { 61 | self.items.get(self.index + n).cloned() 62 | } 63 | 64 | pub fn peek(&self) -> Option { 65 | self.peek_n(0) 66 | } 67 | 68 | pub fn take_snapshot(&mut self) { 69 | self.snapshots.push(Snapshot::new(self.index, self.pos)); 70 | } 71 | 72 | pub fn peek_snapshot(&self) -> Option<&Snapshot> { 73 | self.snapshots.last() 74 | } 75 | 76 | pub fn rollback_snapshot(&mut self) { 77 | let snapshot = self.snapshots.pop().unwrap(); 78 | self.index = snapshot.index; 79 | self.pos = snapshot.pos; 80 | } 81 | 82 | pub fn commit_snapshot(&mut self) { 83 | self.snapshots.pop(); 84 | } 85 | 86 | pub fn last_position(&self) -> (usize, usize) { 87 | self.peek_snapshot() 88 | .unwrap_or(&Snapshot::new(0, (0, 0))) 89 | .pos 90 | } 91 | 92 | pub fn try_match_token(&mut self, matcher: &dyn Matcher<'t>) -> Result, ()> { 93 | if self.end() { 94 | return Ok(Some(Token::new( 95 | TokenType::EOF, 96 | ( 97 | self.pos.0, 98 | if self.source.lines.len() > 0 { 99 | self.source 100 | .lines 101 | .get(self.pos.0) 102 | .unwrap_or(self.source.lines.first().unwrap()) 103 | .to_string() 104 | } else { 105 | String::new() 106 | }, 107 | ), 108 | (self.pos.1, 0), 109 | "", 110 | ))); 111 | } 112 | 113 | self.take_snapshot(); 114 | 115 | match matcher.try_match(self)? { 116 | Some(t) => { 117 | self.commit_snapshot(); 118 | Ok(Some(t)) 119 | } 120 | 121 | None => { 122 | self.rollback_snapshot(); 123 | Ok(None) 124 | } 125 | } 126 | } 127 | 128 | pub fn collect_while(&mut self, func: fn(char) -> bool) -> String { 129 | let mut accum = String::new(); 130 | while let Some(c) = self.peek() { 131 | if func(c) { 132 | accum.push(c); 133 | } else { 134 | break; 135 | } 136 | 137 | self.advance(); 138 | } 139 | 140 | accum 141 | } 142 | } 143 | 144 | impl<'t> Iterator for Tokenizer<'t> { 145 | type Item = char; 146 | 147 | fn next(&mut self) -> Option { 148 | let c = self.items.get(self.index).cloned(); 149 | self.advance(); 150 | c 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /src/wu/visitor/symtab.rs: -------------------------------------------------------------------------------- 1 | use std::cell::RefCell; 2 | use std::collections::HashMap; 3 | 4 | use super::visitor::*; 5 | 6 | #[derive(Debug, Clone)] 7 | pub struct Frame { 8 | pub table: RefCell>, 9 | } 10 | 11 | impl Frame { 12 | pub fn new() -> Self { 13 | Frame { 14 | table: RefCell::new(HashMap::new()), 15 | } 16 | } 17 | 18 | pub fn from(table: HashMap) -> Self { 19 | Frame { 20 | table: RefCell::new(table), 21 | } 22 | } 23 | 24 | pub fn get(&self, name: &String) -> Option { 25 | if let Some(v) = self.table.borrow().get(name) { 26 | Some(v.clone()) 27 | } else { 28 | None 29 | } 30 | } 31 | 32 | pub fn assign(&mut self, name: String, t: Type) { 33 | self.table.borrow_mut().insert(name, t); 34 | } 35 | 36 | #[allow(dead_code)] 37 | pub fn debug(&self) { 38 | println!("======= frame"); 39 | for (name, t) in self.table.borrow().iter() { 40 | println!("{} = {}", name, t) 41 | } 42 | 43 | println!() 44 | } 45 | } 46 | 47 | #[derive(Debug, Clone)] 48 | pub struct SymTab { 49 | pub stack: Vec, // active frames 50 | pub last: Frame, // last frame 51 | 52 | pub implementations: HashMap>, 53 | pub foreign_imports: HashMap>, 54 | } 55 | 56 | impl SymTab { 57 | pub fn new() -> Self { 58 | SymTab { 59 | stack: vec![Frame::new()], 60 | last: Frame::new(), 61 | 62 | implementations: HashMap::new(), 63 | foreign_imports: HashMap::new(), 64 | } 65 | } 66 | 67 | pub fn from(table: HashMap) -> Self { 68 | SymTab { 69 | stack: vec![Frame::from(table)], 70 | last: Frame::new(), 71 | 72 | implementations: HashMap::new(), 73 | foreign_imports: HashMap::new(), 74 | } 75 | } 76 | 77 | pub fn assign(&mut self, name: String, t: Type) { 78 | self.current_frame_mut().assign(name, t) 79 | } 80 | 81 | pub fn assign_str(&mut self, name: &str, t: Type) { 82 | self.current_frame_mut().assign(name.to_string(), t) 83 | } 84 | 85 | pub fn fetch(&self, name: &String) -> Option { 86 | let mut offset = self.stack.len() - 1; 87 | 88 | loop { 89 | if let Some(t) = self.stack[offset].get(name) { 90 | return Some(t); 91 | } else { 92 | if offset == 0 { 93 | return None; 94 | } 95 | 96 | offset -= 1; 97 | } 98 | } 99 | } 100 | 101 | pub fn current_frame_mut(&mut self) -> &mut Frame { 102 | self.stack.last_mut().unwrap() 103 | } 104 | 105 | pub fn put_frame(&mut self, frame: Frame) { 106 | self.stack.push(frame) 107 | } 108 | 109 | pub fn push(&mut self) { 110 | self.stack.push(Frame::new()) 111 | } 112 | 113 | pub fn pop(&mut self) { 114 | self.last = self.stack.pop().unwrap() 115 | } 116 | 117 | pub fn get_implementations(&self, id: &String) -> Option<&HashMap> { 118 | self.implementations.get(id) 119 | } 120 | 121 | pub fn get_implementation_force(&self, id: &String, method_name: &String) -> Type { 122 | self.get_implementations(id) 123 | .unwrap() 124 | .get(method_name) 125 | .unwrap() 126 | .clone() 127 | } 128 | 129 | pub fn implement(&mut self, id: &String, method_name: String, method_type: Type) { 130 | if let Some(ref mut content) = self.implementations.get_mut(id) { 131 | content.insert(method_name, method_type); 132 | 133 | return; 134 | } 135 | 136 | let mut hash = HashMap::new(); 137 | 138 | hash.insert(method_name, method_type); 139 | 140 | self.implementations.insert(id.to_owned(), hash); 141 | } 142 | 143 | pub fn get_foreign_module(&self, id: &String) -> Option<&HashMap> { 144 | self.foreign_imports.get(id) 145 | } 146 | 147 | pub fn import(&mut self, id: String, origin: HashMap) { 148 | self.foreign_imports.insert(id, origin); 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /src/wu/handler/handler.rs: -------------------------------------------------------------------------------- 1 | use git2::build::{CheckoutBuilder, RepoBuilder}; 2 | use git2::{FetchOptions, RemoteCallbacks}; 3 | 4 | use toml::Value; 5 | 6 | use std::fs; 7 | use std::fs::File; 8 | use std::io::prelude::*; 9 | use std::io::Write; 10 | 11 | use std::path::Path; 12 | 13 | use colored::Colorize; 14 | 15 | pub fn new(name: Option<&str>) { 16 | if let Some(name) = name { 17 | if Path::new(name).exists() { 18 | wrong(&format!("path '{}' already exists", name)); 19 | } else { 20 | fs::create_dir_all(format!("{}/src", name)).unwrap(); 21 | 22 | let mut init = File::create(&format!("{}/init.wu", name)).unwrap(); 23 | init.write_all(b"import src\n").unwrap(); 24 | 25 | let mut wu_toml = File::create(&format!("{}/wu.toml", name)).unwrap(); 26 | wu_toml.write_all(b"[dependencies]\n").unwrap(); 27 | 28 | File::create(&format!("{}/src/init.wu", name)).unwrap(); 29 | } 30 | } else { 31 | let mut wu_toml = File::create("wu.toml").unwrap(); 32 | wu_toml.write_all(b"[dependencies]").unwrap(); 33 | 34 | File::create("src/init.wu").unwrap(); 35 | } 36 | } 37 | 38 | pub fn get() { 39 | if Path::new("wu.toml").exists() { 40 | let mut config = File::open("wu.toml").unwrap(); 41 | 42 | let mut contents = String::new(); 43 | config.read_to_string(&mut contents).unwrap(); 44 | 45 | match toml::from_str::(&contents) { 46 | Ok(value) => match value.get("dependencies") { 47 | Some(depends) => match *depends { 48 | Value::Table(ref t) => { 49 | let mut modules = Vec::new(); 50 | 51 | let mut dep_path = "libs/".to_string(); 52 | 53 | if let Some(ref path) = value.get("libpath") { 54 | if let Value::String(ref path) = path { 55 | dep_path = format!("{}", path); 56 | } else { 57 | wrong("Expected string `libpath` value") 58 | } 59 | } 60 | 61 | 62 | for member in t { 63 | if !Path::new(&dep_path).exists() { 64 | fs::create_dir_all(&dep_path).unwrap(); 65 | } 66 | 67 | if let Value::String(ref url) = *member.1 { 68 | let path = &format!("{}{}", dep_path, member.0); 69 | 70 | if Path::new(path).exists() { 71 | fs::remove_dir_all(path).unwrap() 72 | } 73 | 74 | println!( 75 | "{}", 76 | format!( 77 | "{} {} => `{}`", 78 | "Cloning".green().bold(), 79 | member.0, 80 | dep_path 81 | ) 82 | ); 83 | clone(&format!("https://github.com/{}", url), path); 84 | 85 | modules.push(format!("import {}", member.0)) 86 | } else { 87 | wrong("Expected string URL value") 88 | } 89 | } 90 | } 91 | 92 | _ => wrong(r#"Expected key e.g. `a = "b"`"#), 93 | }, 94 | _ => (), 95 | }, 96 | 97 | Err(_) => wrong("Something went wrong in 'wu.toml'"), 98 | } 99 | } else { 100 | wrong("Couldn't find 'wu.toml'"); 101 | } 102 | } 103 | 104 | fn clone(url: &str, path: &str) { 105 | let cb = RemoteCallbacks::new(); 106 | let co = CheckoutBuilder::new(); 107 | let mut fo = FetchOptions::new(); 108 | 109 | fo.remote_callbacks(cb); 110 | 111 | match RepoBuilder::new() 112 | .fetch_options(fo) 113 | .with_checkout(co) 114 | .clone(url, Path::new(path)) 115 | { 116 | Ok(_) => (), 117 | Err(why) => wrong(&format!("Failed to download '{}' :: {}", url, why)), 118 | } 119 | 120 | println!() 121 | } 122 | 123 | fn wrong(message: &str) { 124 | println!("{} {}", "wrong:".red().bold(), message) 125 | } 126 | -------------------------------------------------------------------------------- /src/wu/lexer/lexer.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | use super::super::error::Response::Wrong; 4 | 5 | use std::rc::Rc; 6 | 7 | pub struct Lexer<'l> { 8 | tokenizer: Tokenizer<'l>, 9 | matchers: Vec>>, 10 | source: &'l Source, 11 | } 12 | 13 | impl<'l> Lexer<'l> { 14 | pub fn new(tokenizer: Tokenizer<'l>, source: &'l Source) -> Self { 15 | Lexer { 16 | tokenizer, 17 | matchers: Vec::new(), 18 | source, 19 | } 20 | } 21 | 22 | pub fn default(data: Vec, source: &'l Source) -> Self { 23 | use self::TokenType::*; 24 | 25 | let tokenizer = Tokenizer::new(data, source); 26 | let mut lexer = Self::new(tokenizer, source); 27 | 28 | lexer.matchers.push(Rc::new(CommentMatcher)); 29 | 30 | lexer.matchers.push(Rc::new(EOLMatcher)); 31 | lexer.matchers.push(Rc::new(StringLiteralMatcher)); 32 | 33 | lexer.matchers.push(Rc::new(KeyMatcher::new( 34 | Keyword, 35 | &[ 36 | "fun", 37 | "->", 38 | "=>", 39 | "return", 40 | "as", 41 | "if", 42 | "elif", 43 | "else", 44 | "switch", 45 | "while", 46 | "skip", 47 | "break", 48 | "module", 49 | "extern", 50 | "struct", 51 | "new", 52 | "implement", 53 | "import", 54 | "interface", 55 | "trait", 56 | "nil", 57 | "switch", 58 | "for", 59 | "in", 60 | "pub" 61 | ], 62 | ))); 63 | 64 | lexer 65 | .matchers 66 | .push(Rc::new(KeyMatcher::new(Bool, &["false", "true"]))); 67 | 68 | lexer 69 | .matchers 70 | .push(Rc::new(ConstantStringMatcher::new(Symbol, &["...", ".."]))); 71 | 72 | lexer.matchers.push(Rc::new(NumberLiteralMatcher)); 73 | lexer.matchers.push(Rc::new(WhitespaceMatcher)); 74 | 75 | lexer.matchers.push(Rc::new(ConstantStringMatcher::new( 76 | Operator, 77 | &[ 78 | "|>", "<|", "^", "++", "+", "-", "*", "/", "%", "==", "!=", "<=", ">=", "<", ">", 79 | ], 80 | ))); 81 | 82 | lexer 83 | .matchers 84 | .push(Rc::new(KeyMatcher::new(Operator, &["or", "and", "not"]))); 85 | 86 | lexer.matchers.push(Rc::new(IdentifierMatcher)); 87 | 88 | lexer.matchers.push(Rc::new(ConstantCharMatcher::new( 89 | Symbol, 90 | &[ 91 | '?', '!', '(', ')', '[', ']', '{', '}', ',', ':', ';', '=', '.', '|', 92 | ], 93 | ))); 94 | 95 | lexer 96 | } 97 | 98 | pub fn match_token(&mut self) -> Result, ()> { 99 | for matcher in &mut self.matchers { 100 | match self.tokenizer.try_match_token(matcher.as_ref())? { 101 | Some(t) => return Ok(Some(t)), 102 | None => continue, 103 | } 104 | } 105 | 106 | Ok(None) 107 | } 108 | } 109 | 110 | impl<'l> Iterator for Lexer<'l> { 111 | type Item = Result; 112 | 113 | fn next(&mut self) -> Option> { 114 | let token = match self.match_token() { 115 | Ok(hmm) => match hmm { 116 | Some(n) => n, 117 | None => { 118 | let pos = self.tokenizer.pos; 119 | 120 | return Some(Err(response!( 121 | Wrong("bumped into weird character"), 122 | self.source.file, 123 | Pos( 124 | ( 125 | pos.0, 126 | self.source 127 | .lines 128 | .get(pos.0.saturating_sub(1)) 129 | .unwrap_or(self.source.lines.last().unwrap_or(&String::new())) 130 | .to_string() 131 | ), 132 | (pos.1 + 1, pos.1 + 1), 133 | ) 134 | ))); 135 | } 136 | }, 137 | 138 | Err(_) => return Some(Err(())), 139 | }; 140 | 141 | match token.token_type { 142 | TokenType::EOF => None, 143 | TokenType::Whitespace => self.next(), 144 | _ => Some(Ok(token)), 145 | } 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/wu/parser/ast.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use std::rc::Rc; 3 | 4 | use super::*; 5 | 6 | #[derive(Debug, Clone, PartialEq)] 7 | pub enum StatementNode { 8 | Expression(Expression), 9 | Variable(Type, String, Option, bool), // pub: bool 10 | SplatVariable(Type, Vec, Option, bool), // pub: u guessed it 11 | Assignment(Expression, Expression), 12 | SplatAssignment(Vec, Expression), 13 | Return(Option>), 14 | Implement(Expression, Expression, Option), 15 | Import(String, Vec, bool), // pub: bool 16 | //TODO: Never instantiated? 17 | ExternBlock(Rc), 18 | Skip, 19 | Break, 20 | } 21 | 22 | #[derive(Debug, Clone, PartialEq)] 23 | pub struct Statement { 24 | pub node: StatementNode, 25 | pub pos: Pos, 26 | } 27 | 28 | impl Statement { 29 | pub fn new(node: StatementNode, pos: Pos) -> Self { 30 | Statement { node, pos } 31 | } 32 | } 33 | 34 | #[derive(Debug, Clone, PartialEq)] 35 | pub enum ExpressionNode { 36 | Int(i64), 37 | Float(f64), 38 | Str(String), 39 | Char(char), 40 | Bool(bool), 41 | UnwrapSplat(Rc), 42 | Unwrap(Rc), 43 | 44 | Tuple(Vec), 45 | 46 | Neg(Rc), 47 | Not(Rc), 48 | 49 | Identifier(String), 50 | Binary(Rc, Operator, Rc), 51 | Array(Vec), 52 | 53 | Call(Rc, Vec), 54 | Index(Rc, Rc, bool), // whether_index_is_an_array_index: bool 55 | 56 | Cast(Rc, Type), 57 | Block(Vec), 58 | 59 | Function(Vec<(String, Type)>, Type, Rc, bool), // is_method: bool 60 | If( 61 | Rc, 62 | Rc, 63 | Option, Expression, Pos)>>, 64 | ), 65 | For((Rc, Option>), Rc), 66 | Splat(Vec), 67 | 68 | While(Rc, Rc), 69 | Module(Rc), 70 | Extern(Type, Option), 71 | ExternExpression(Rc), 72 | Struct(String, Vec<(String, Type)>, String), 73 | Trait(String, Vec<(String, Type)>), 74 | Initialization(Rc, Vec<(String, Expression)>), 75 | 76 | Empty, 77 | EOF, 78 | } 79 | 80 | #[derive(Debug, Clone, PartialEq)] 81 | pub struct Expression { 82 | pub node: ExpressionNode, 83 | pub pos: Pos, 84 | } 85 | 86 | impl Expression { 87 | pub fn new(node: ExpressionNode, pos: Pos) -> Self { 88 | Expression { node, pos } 89 | } 90 | } 91 | 92 | #[derive(Debug, Clone, PartialEq)] 93 | pub enum Operator { 94 | Add, 95 | Sub, 96 | Mul, 97 | Div, 98 | Mod, 99 | Pow, 100 | Concat, 101 | Eq, 102 | Lt, 103 | Gt, 104 | NEq, 105 | LtEq, 106 | GtEq, 107 | Or, 108 | And, 109 | PipeLeft, 110 | PipeRight, 111 | } 112 | 113 | impl Operator { 114 | pub fn is_right_ass(&self) -> bool { 115 | &Operator::Pow == self 116 | } 117 | 118 | pub fn from_str(operator: &str) -> Option<(Operator, u8)> { 119 | use self::Operator::*; 120 | 121 | let op_prec = match operator { 122 | "or" => (Or, 0), 123 | "and" => (And, 0), 124 | "<|" => (PipeLeft, 0), 125 | "|>" => (PipeRight, 0), 126 | "==" => (Eq, 1), 127 | "<" => (Lt, 1), 128 | ">" => (Gt, 1), 129 | "!=" => (NEq, 1), 130 | "<=" => (LtEq, 1), 131 | ">=" => (GtEq, 1), 132 | "+" => (Add, 2), 133 | "-" => (Sub, 2), 134 | "++" => (Concat, 2), 135 | "*" => (Mul, 3), 136 | "/" => (Div, 3), 137 | "%" => (Mod, 3), 138 | "^" => (Pow, 4), 139 | _ => return None, 140 | }; 141 | 142 | Some(op_prec) 143 | } 144 | 145 | pub fn as_str(&self) -> &str { 146 | use self::Operator::*; 147 | 148 | match *self { 149 | Add => "+", 150 | Sub => "-", 151 | Concat => "++", 152 | Pow => "^", 153 | Mul => "*", 154 | Div => "/", 155 | Mod => "%", 156 | Eq => "==", 157 | Lt => "<", 158 | Gt => ">", 159 | NEq => "!=", 160 | LtEq => "<=", 161 | GtEq => ">=", 162 | Or => "or", 163 | And => "and", 164 | PipeLeft => "<|", 165 | PipeRight => "|>", 166 | } 167 | } 168 | 169 | pub fn is_compoundable(operator: &str) -> bool { 170 | ["+", "-", "*", "/", "++", "%", "^", "not", "or", "and"].contains(&operator) 171 | } 172 | } 173 | 174 | impl fmt::Display for Operator { 175 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 176 | write!(f, "{}", self.as_str()) 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | #![deny(mutable_borrow_reservation_conflict)] 2 | extern crate colored; 3 | extern crate dirs; 4 | extern crate fs_extra; 5 | extern crate git2; 6 | extern crate rustyline; 7 | extern crate toml; 8 | 9 | use self::colored::Colorize; 10 | 11 | mod wu; 12 | 13 | use self::wu::compiler::*; 14 | use self::wu::error::*; 15 | use self::wu::handler; 16 | use self::wu::lexer::*; 17 | use self::wu::parser::*; 18 | use self::wu::source::*; 19 | use self::wu::visitor::*; 20 | 21 | use std::fs; 22 | use std::fs::metadata; 23 | use std::fs::File; 24 | 25 | use std::env; 26 | 27 | use std::io::prelude::*; 28 | use std::path::Path; 29 | use std::time::Instant; 30 | 31 | const HELP: &'static str = "\ 32 | The Wu Compiler 33 | 34 | Usage: 35 | wu # Show this message 36 | wu # Compile .wu file to corresponding .lua file 37 | wu # Compile all .wu files in given folder 38 | wu clean # Removes all compiled .lua files from given folder 39 | 40 | Project usage: 41 | wu new # Create a new Wu project 42 | wu sync # Installs/synchronizes dependencies 43 | wu build # Installs dependencies and builds current project 44 | "; 45 | 46 | fn compile_path(path: &str, root: &String) { 47 | let meta = match metadata(path) { 48 | Ok(m) => m, 49 | Err(why) => panic!("{}", why), 50 | }; 51 | 52 | if meta.is_file() { 53 | let split: Vec<&str> = path.split('.').collect(); 54 | 55 | println!( 56 | "{} {}", 57 | "Compiling".green().bold(), 58 | path.to_string().replace("./", "") 59 | ); 60 | 61 | if *split.last().unwrap() == "wu" { 62 | let meta = match metadata(root) { 63 | Ok(m) => Some(m), 64 | Err(_) => None, 65 | }; 66 | 67 | let mut root = root.to_string(); 68 | 69 | if let Some(meta) = meta { 70 | if !meta.is_dir() { 71 | root = Path::new(&root).parent().unwrap().display().to_string(); 72 | } 73 | } 74 | 75 | if let Some(n) = file_content(path, &root) { 76 | write(path, &n); 77 | } 78 | } 79 | } else { 80 | let paths = fs::read_dir(path).unwrap(); 81 | 82 | for folder_path in paths { 83 | let folder_path = format!("{}", folder_path.unwrap().path().display()); 84 | let split: Vec<&str> = folder_path.split('.').collect(); 85 | 86 | if Path::new(&folder_path).is_dir() || *split.last().unwrap() == "wu" { 87 | compile_path(&folder_path, root) 88 | } 89 | } 90 | } 91 | } 92 | 93 | fn file_content(path: &str, root: &String) -> Option { 94 | let display = Path::new(path).display(); 95 | 96 | let mut file = match File::open(&path) { 97 | Err(why) => panic!("failed to open {}: {}", display, why), 98 | Ok(file) => file, 99 | }; 100 | 101 | let mut s = String::new(); 102 | 103 | match file.read_to_string(&mut s) { 104 | Err(why) => panic!("failed to read {}: {}", display, why), 105 | Ok(_) => run(&s, path, root), 106 | } 107 | } 108 | 109 | fn write(path: &str, data: &str) { 110 | let path = Path::new(path); 111 | 112 | let split_name = path.file_name().unwrap().to_str().unwrap().split('.'); 113 | let split: Vec<&str> = split_name.collect(); 114 | 115 | let path_split = path.to_str().unwrap().split('/').collect::>(); 116 | 117 | let path_real = if path_split.len() > 1 { 118 | format!( 119 | "{}/{}.lua", 120 | path_split[0..path_split.len() - 1].join("/"), 121 | split[0] 122 | ) 123 | } else { 124 | format!("{}.lua", split[0]) 125 | }; 126 | 127 | let mut output_file = File::create(&path_real).unwrap(); 128 | match output_file.write_all(data.as_bytes()) { 129 | Ok(_) => (), 130 | Err(why) => println!("{}", why), 131 | } 132 | } 133 | 134 | pub fn run(content: &str, file: &str, root: &String) -> Option { 135 | let source = Source::from( 136 | file, 137 | content.lines().map(|x| x.into()).collect::>(), 138 | ); 139 | let lexer = Lexer::default(content.chars().collect(), &source); 140 | 141 | let mut tokens = Vec::new(); 142 | 143 | for token_result in lexer { 144 | if let Ok(token) = token_result { 145 | tokens.push(token) 146 | } else { 147 | return None; 148 | } 149 | } 150 | 151 | let mut parser = Parser::new(tokens, &source); 152 | 153 | match parser.parse() { 154 | Ok(ref ast) => { 155 | let mut symtab = SymTab::new(); 156 | 157 | let splat_any = Type::new(TypeNode::Any, TypeMode::Splat(None)); 158 | 159 | symtab.assign_str( 160 | "print", 161 | Type::function(vec![splat_any.clone()], Type::from(TypeNode::Nil), false), 162 | ); 163 | 164 | symtab.assign_str( 165 | "ipairs", 166 | Type::function(vec![splat_any.clone()], splat_any.clone(), false), 167 | ); 168 | 169 | symtab.assign_str( 170 | "pairs", 171 | Type::function(vec![splat_any.clone()], splat_any, false), 172 | ); 173 | 174 | let mut visitor = Visitor::from_symtab(ast, &source, symtab, root.clone()); 175 | 176 | match visitor.visit() { 177 | Ok(_) => (), 178 | _ => return None, 179 | } 180 | 181 | let mut generator = Generator::new(&source, &visitor.method_calls, &visitor.import_map); 182 | 183 | Some(generator.generate(&ast)) 184 | } 185 | 186 | _ => None, 187 | } 188 | } 189 | 190 | fn clean_path(path: &str) { 191 | let meta = match metadata(path) { 192 | Ok(m) => m, 193 | Err(why) => panic!("{}", why), 194 | }; 195 | 196 | if meta.is_dir() { 197 | let paths = fs::read_dir(path).unwrap(); 198 | 199 | for path in paths { 200 | let path = path.unwrap().path(); 201 | if path.is_dir() { 202 | clean_path(&path.display().to_string()) 203 | } else { 204 | let path = format!("{}", path.display()); 205 | let split: Vec<&str> = path.split('.').collect(); 206 | 207 | // removes lua file if wu source exists 208 | match split.last() { 209 | Some(n) if *n == "wu" => { 210 | let path = format!("{}.lua", split[0..split.len() - 1].to_vec().join(".")); 211 | 212 | if Path::new(&path).is_file() { 213 | println!("{} {}", "Removing".red().bold(), path.replace("./", "")); 214 | 215 | match fs::remove_file(&path) { 216 | Ok(_) => (), 217 | Err(why) => panic!("{}", why), 218 | } 219 | } 220 | } 221 | _ => continue, 222 | } 223 | } 224 | } 225 | } else { 226 | let split: Vec<&str> = path.split('.').collect(); 227 | 228 | let path = format!("{}.lua", split[0..split.len() - 1].to_vec().join(".")); 229 | 230 | if Path::new(&path).is_file() { 231 | match fs::remove_file(&path) { 232 | Ok(_) => println!("{} {}", "removed".red().bold(), path.replace("./", "")), 233 | Err(why) => panic!("{}", why), 234 | } 235 | } 236 | } 237 | } 238 | 239 | fn confirm_home() { 240 | if env::var("WU_HOME").is_err() { 241 | let dir = if let Some(dir) = dirs::home_dir() { 242 | format!("{}/.wu/libs/", dir.display()) 243 | } else { 244 | return response!( 245 | Response::Weird(format!("missing environment variable `WU_HOME`")), 246 | Response::Note("failed to find home directory, you can set the variable yourself") 247 | ); 248 | }; 249 | 250 | if !Path::new(&dir).exists() { 251 | if fs::create_dir_all(dir).is_err() { 252 | response!( 253 | Response::Weird(format!("missing environment variable `WU_HOME`")), 254 | Response::Note("run again as super-user to fix this automatically") 255 | ) 256 | } 257 | } else { 258 | env::set_var("WU_HOME", dir) 259 | } 260 | } 261 | } 262 | 263 | fn main() { 264 | confirm_home(); 265 | 266 | let args = env::args().collect::>(); 267 | 268 | let root = Path::new(&args[0].to_string()) 269 | .parent() 270 | .unwrap() 271 | .display() 272 | .to_string(); 273 | 274 | if args.len() > 1 { 275 | match args[1].as_str() { 276 | "clean" => { 277 | if args.len() > 2 { 278 | clean_path(&args[2]) 279 | } 280 | } 281 | 282 | "new" => { 283 | if args.len() > 2 { 284 | handler::new(Some(&args[2])) 285 | } else { 286 | handler::new(None) 287 | } 288 | } 289 | 290 | "build" => { 291 | handler::get(); 292 | 293 | if args.len() > 2 { 294 | compile_path(&args[2], &root) 295 | } else { 296 | compile_path(".", &root) 297 | } 298 | } 299 | 300 | "sync" => handler::get(), 301 | 302 | file => { 303 | let now = Instant::now(); 304 | 305 | compile_path(&file, &file.to_string()); 306 | 307 | println!( 308 | "{} things in {}ms", 309 | " Finished".green().bold(), 310 | now.elapsed().as_millis() 311 | ); 312 | } 313 | } 314 | } else { 315 | println!("{}", HELP) 316 | } 317 | } 318 | -------------------------------------------------------------------------------- /src/wu/lexer/matcher.rs: -------------------------------------------------------------------------------- 1 | use super::super::error::Response::*; 2 | use super::*; 3 | 4 | macro_rules! token { 5 | ($tokenizer:expr, $token_type:ident, $accum:expr) => {{ 6 | token!($tokenizer, TokenType::$token_type, $accum) 7 | }}; 8 | ($tokenizer:expr, $token_type:expr, $accum:expr) => {{ 9 | let tokenizer = $tokenizer as &$crate::wu::lexer::tokenizer::Tokenizer<'t>; 10 | let token_type = $token_type as $crate::wu::lexer::token::TokenType; 11 | 12 | let accum: String = $accum; 13 | let pos = tokenizer.last_position(); 14 | 15 | let line = tokenizer 16 | .source 17 | .lines 18 | .get(pos.0.saturating_sub(1)) 19 | .unwrap_or(tokenizer.source.lines.last().unwrap()) 20 | .to_string(); 21 | 22 | if TokenType::Str == token_type || TokenType::Char == token_type { 23 | Token::new( 24 | token_type, 25 | (pos.0, line), 26 | (pos.1 + 1, pos.1 + accum.len() + 2), 27 | &accum, 28 | ) // delimeters 29 | } else { 30 | Token::new( 31 | token_type, 32 | (pos.0, line), 33 | (pos.1 + 1, pos.1 + accum.len()), 34 | &accum, 35 | ) 36 | } 37 | }}; 38 | } 39 | 40 | pub trait Matcher<'t> { 41 | fn try_match(&self, tokenizer: &mut Tokenizer<'t>) -> Result, ()>; 42 | } 43 | 44 | pub struct CommentMatcher; 45 | 46 | impl<'t> Matcher<'t> for CommentMatcher { 47 | fn try_match(&self, tokenizer: &mut Tokenizer<'t>) -> Result, ()> { 48 | if tokenizer.peek_range(1).unwrap_or_else(String::new) == "#" { 49 | while !tokenizer.end() && tokenizer.peek() != Some('\n') { 50 | tokenizer.advance() 51 | } 52 | 53 | Ok(Some(token!(tokenizer, EOL, "\n".into()))) 54 | } else { 55 | Ok(None) 56 | } 57 | } 58 | } 59 | 60 | pub struct ConstantStringMatcher { 61 | token_type: TokenType, 62 | constants: &'static [&'static str], 63 | } 64 | 65 | impl ConstantStringMatcher { 66 | pub fn new(token_type: TokenType, constants: &'static [&'static str]) -> Self { 67 | ConstantStringMatcher { 68 | token_type, 69 | constants, 70 | } 71 | } 72 | } 73 | 74 | impl<'t> Matcher<'t> for ConstantStringMatcher { 75 | fn try_match(&self, tokenizer: &mut Tokenizer<'t>) -> Result, ()> { 76 | for constant in self.constants { 77 | let len = constant.len(); 78 | let c = match tokenizer.peek_range(len) { 79 | Some(len) => len, 80 | _ => return Ok(None), 81 | }; 82 | 83 | if c == *constant { 84 | tokenizer.advance_n(len); 85 | 86 | let token = token!(tokenizer, self.token_type.clone(), constant.to_string()); 87 | 88 | if c == "\n" { 89 | tokenizer.pos.0 += 1; 90 | tokenizer.pos.1 = 0; 91 | } 92 | 93 | return Ok(Some(token)); 94 | } 95 | } 96 | 97 | Ok(None) 98 | } 99 | } 100 | 101 | pub struct ConstantCharMatcher { 102 | token_type: TokenType, 103 | constants: &'static [char], 104 | } 105 | 106 | impl ConstantCharMatcher { 107 | pub fn new(token_type: TokenType, constants: &'static [char]) -> Self { 108 | ConstantCharMatcher { 109 | token_type, 110 | constants, 111 | } 112 | } 113 | } 114 | 115 | impl<'t> Matcher<'t> for ConstantCharMatcher { 116 | fn try_match(&self, tokenizer: &mut Tokenizer<'t>) -> Result, ()> { 117 | let c = tokenizer.peek().unwrap(); 118 | 119 | for constant in self.constants { 120 | if c == *constant { 121 | tokenizer.advance(); 122 | 123 | let token = token!(tokenizer, self.token_type.clone(), constant.to_string()); 124 | 125 | if c == '\n' { 126 | tokenizer.pos.0 += 1; 127 | tokenizer.pos.1 = 0; 128 | } 129 | 130 | return Ok(Some(token)); 131 | } 132 | } 133 | Ok(None) 134 | } 135 | } 136 | 137 | pub struct StringLiteralMatcher; 138 | 139 | impl<'t> Matcher<'t> for StringLiteralMatcher { 140 | fn try_match(&self, tokenizer: &mut Tokenizer<'t>) -> Result, ()> { 141 | let mut raw_marker = false; 142 | 143 | let mut pos = tokenizer.pos; 144 | 145 | let delimeter = match tokenizer.peek().unwrap() { 146 | '"' => '"', 147 | '\'' => '\'', 148 | 'r' => { 149 | if tokenizer.peek_n(1) == Some('"') { 150 | raw_marker = true; 151 | tokenizer.advance(); 152 | 153 | pos = tokenizer.pos; 154 | 155 | '"' 156 | } else if tokenizer.peek_n(1) == Some('\'') { 157 | return Err(response!( 158 | Wrong("no such thing as a raw character literal"), 159 | tokenizer.source.file, 160 | Pos( 161 | ( 162 | pos.0, 163 | tokenizer 164 | .source 165 | .lines 166 | .get(pos.0.saturating_sub(1)) 167 | .unwrap_or(tokenizer.source.lines.last().unwrap()) 168 | .to_string() 169 | ), 170 | (pos.1 - 1, pos.1), 171 | ) 172 | )); 173 | } else { 174 | return Ok(None); 175 | } 176 | } 177 | _ => return Ok(None), 178 | }; 179 | 180 | tokenizer.advance(); 181 | 182 | let mut string = String::new(); 183 | let mut found_escape = false; 184 | 185 | loop { 186 | if tokenizer.end() { 187 | return Err(response!( 188 | Wrong(format!("unterminated delimeter `{}`", delimeter)), 189 | tokenizer.source.file, 190 | Pos( 191 | ( 192 | pos.0 + 1, 193 | tokenizer 194 | .source 195 | .lines 196 | .get(pos.0.saturating_sub(1)) 197 | .unwrap_or(tokenizer.source.lines.last().unwrap()) 198 | .to_string() 199 | ), 200 | (pos.1.saturating_sub(1), pos.1 + 1), 201 | ) 202 | )); 203 | } 204 | 205 | if raw_marker { 206 | if tokenizer.peek().unwrap() == '"' { 207 | break; 208 | } 209 | string.push(tokenizer.next().unwrap()) 210 | } else if found_escape { 211 | string.push(match tokenizer.next().unwrap() { 212 | c @ '\\' | c @ '\'' | c @ '"' => c, 213 | 'n' => '\n', 214 | 'r' => '\r', 215 | 't' => '\t', 216 | escaped => { 217 | return Err(response!( 218 | Wrong(format!("unexpected escape character: {}", escaped)), 219 | tokenizer.source.file, 220 | Pos( 221 | ( 222 | tokenizer.pos.0, 223 | tokenizer 224 | .source 225 | .lines 226 | .get(pos.0.saturating_sub(1)) 227 | .unwrap_or(tokenizer.source.lines.last().unwrap()) 228 | .to_string() 229 | ), 230 | (tokenizer.pos.1 - 1, tokenizer.pos.1), 231 | ) 232 | )) 233 | } 234 | }); 235 | 236 | found_escape = false 237 | } else if tokenizer.peek().unwrap() == '"' { 238 | break; 239 | } else { 240 | match tokenizer.peek().unwrap() { 241 | '\\' => { 242 | string.push('\\'); 243 | tokenizer.next(); 244 | found_escape = true 245 | } 246 | 247 | // check for valid closing delimeter and alternative 248 | c => { 249 | if c == delimeter { 250 | if string.len() > 0 && string != " " { 251 | break; 252 | } else { 253 | string.push(tokenizer.next().unwrap()) 254 | } 255 | } else { 256 | string.push(tokenizer.next().unwrap()) 257 | } 258 | } 259 | } 260 | } 261 | } 262 | 263 | tokenizer.advance(); 264 | 265 | if delimeter == '"' { 266 | let mut token = token!(tokenizer, Str, string); 267 | 268 | if raw_marker { 269 | token.slice.1 += 1 270 | } 271 | 272 | Ok(Some(token)) 273 | } else { 274 | if string.len() > 1 { 275 | let pos = tokenizer.last_position(); 276 | 277 | Err(response!( 278 | Wrong("char literals may not contain more than one codepoint"), 279 | tokenizer.source.file, 280 | Pos( 281 | ( 282 | pos.0, 283 | tokenizer 284 | .source 285 | .lines 286 | .get(pos.0.saturating_sub(1)) 287 | .unwrap_or(tokenizer.source.lines.last().unwrap()) 288 | .to_string() 289 | ), 290 | ( 291 | pos.1 + 2, 292 | pos.1 + string.len() + 1 + if raw_marker { 1 } else { 0 } 293 | ), 294 | ) 295 | )) 296 | } else { 297 | Ok(Some(token!(tokenizer, Char, string))) 298 | } 299 | } 300 | } 301 | } 302 | 303 | pub struct IdentifierMatcher; 304 | 305 | impl<'t> Matcher<'t> for IdentifierMatcher { 306 | fn try_match(&self, tokenizer: &mut Tokenizer<'t>) -> Result, ()> { 307 | let peeked = tokenizer.peek().unwrap(); 308 | 309 | if !peeked.is_alphabetic() && peeked != '_' { 310 | return Ok(None); 311 | } 312 | 313 | let accum = tokenizer.collect_while(|c| c.is_alphanumeric() || "_-".contains(c)); 314 | 315 | if accum.is_empty() { 316 | Ok(None) 317 | } else { 318 | Ok(Some(token!(tokenizer, Identifier, accum))) 319 | } 320 | } 321 | } 322 | 323 | pub struct NumberLiteralMatcher; 324 | 325 | impl<'t> Matcher<'t> for NumberLiteralMatcher { 326 | fn try_match(&self, tokenizer: &mut Tokenizer<'t>) -> Result, ()> { 327 | let mut accum = String::new(); 328 | 329 | let curr = tokenizer.next().unwrap(); 330 | if curr.is_digit(10) { 331 | accum.push(curr) 332 | } else if curr == '.' { 333 | accum.push_str("0.") 334 | } else if curr == '-' { 335 | accum.push('-') 336 | } else { 337 | return Ok(None); 338 | } 339 | 340 | while !tokenizer.end() { 341 | let current = tokenizer.peek().unwrap(); 342 | if !current.is_whitespace() && current.is_digit(10) || current == '.' { 343 | if current == '.' && accum.contains('.') { 344 | let pos = tokenizer.pos; 345 | 346 | return Err(response!( 347 | Wrong("unexpected extra decimal point"), 348 | tokenizer.source.file, 349 | Pos( 350 | ( 351 | pos.0, 352 | tokenizer 353 | .source 354 | .lines 355 | .get(pos.0.saturating_sub(1)) 356 | .unwrap_or(tokenizer.source.lines.last().unwrap()) 357 | .to_string() 358 | ), 359 | (pos.1 + 1, pos.1 + 1), 360 | ) 361 | )); 362 | } 363 | accum.push(tokenizer.next().unwrap()) 364 | } else { 365 | break; 366 | } 367 | } 368 | 369 | if ["-", "-0.", "-.", "0."].contains(&accum.as_str()) { 370 | Ok(None) 371 | } else { 372 | if accum.contains(".") { 373 | let literal: String = match accum.parse::() { 374 | Ok(result) => result.to_string(), 375 | Err(error) => panic!("unable to parse float `{}`: {}", accum, error), 376 | }; 377 | 378 | Ok(Some(token!(tokenizer, Float, literal))) 379 | } else { 380 | let literal: String = match accum.parse::() { 381 | Ok(result) => result.to_string(), 382 | Err(error) => panic!("unable to parse int `{}`: {}", accum, error), 383 | }; 384 | 385 | Ok(Some(token!(tokenizer, Int, literal))) 386 | } 387 | } 388 | } 389 | } 390 | 391 | pub struct KeyMatcher { 392 | token_type: TokenType, 393 | constants: &'static [&'static str], 394 | } 395 | 396 | impl KeyMatcher { 397 | pub fn new(token_type: TokenType, constants: &'static [&'static str]) -> Self { 398 | KeyMatcher { 399 | token_type, 400 | constants, 401 | } 402 | } 403 | } 404 | 405 | impl<'t> Matcher<'t> for KeyMatcher { 406 | fn try_match(&self, tokenizer: &mut Tokenizer<'t>) -> Result, ()> { 407 | for constant in self.constants { 408 | if let Some(s) = tokenizer.peek_range(constant.len()) { 409 | if s == *constant { 410 | if let Some(c) = tokenizer.peek_n(constant.len()) { 411 | if "_!?".contains(c) || c.is_alphanumeric() { 412 | return Ok(None); 413 | } 414 | } 415 | 416 | tokenizer.advance_n(constant.len()); 417 | return Ok(Some(token!( 418 | tokenizer, 419 | self.token_type.clone(), 420 | constant.to_string() 421 | ))); 422 | } 423 | } 424 | } 425 | 426 | Ok(None) 427 | } 428 | } 429 | 430 | pub struct EOLMatcher; 431 | 432 | impl<'t> Matcher<'t> for EOLMatcher { 433 | fn try_match(&self, tokenizer: &mut Tokenizer<'t>) -> Result, ()> { 434 | if tokenizer.peek() == Some('\n') { 435 | tokenizer.pos.0 += 1; 436 | tokenizer.pos.1 = 0; 437 | tokenizer.index += 1; 438 | 439 | Ok(Some(token!(tokenizer, TokenType::EOL, String::from("\n")))) 440 | } else { 441 | Ok(None) 442 | } 443 | } 444 | } 445 | 446 | pub struct WhitespaceMatcher; 447 | 448 | impl<'t> Matcher<'t> for WhitespaceMatcher { 449 | fn try_match(&self, tokenizer: &mut Tokenizer<'t>) -> Result, ()> { 450 | let string = tokenizer.collect_while(|c| c.is_whitespace() && c != '\n'); 451 | 452 | if !string.is_empty() { 453 | Ok(Some(token!(tokenizer, Whitespace, string))) 454 | } else { 455 | Ok(None) 456 | } 457 | } 458 | } 459 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.17.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler" 16 | version = "1.0.2" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 19 | 20 | [[package]] 21 | name = "atty" 22 | version = "0.2.14" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 25 | dependencies = [ 26 | "hermit-abi", 27 | "libc", 28 | "winapi", 29 | ] 30 | 31 | [[package]] 32 | name = "autocfg" 33 | version = "1.0.1" 34 | source = "registry+https://github.com/rust-lang/crates.io-index" 35 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" 36 | 37 | [[package]] 38 | name = "backtrace" 39 | version = "0.3.63" 40 | source = "registry+https://github.com/rust-lang/crates.io-index" 41 | checksum = "321629d8ba6513061f26707241fa9bc89524ff1cd7a915a97ef0c62c666ce1b6" 42 | dependencies = [ 43 | "addr2line", 44 | "cc", 45 | "cfg-if", 46 | "libc", 47 | "miniz_oxide", 48 | "object", 49 | "rustc-demangle", 50 | ] 51 | 52 | [[package]] 53 | name = "bitflags" 54 | version = "1.3.2" 55 | source = "registry+https://github.com/rust-lang/crates.io-index" 56 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 57 | 58 | [[package]] 59 | name = "cc" 60 | version = "1.0.72" 61 | source = "registry+https://github.com/rust-lang/crates.io-index" 62 | checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" 63 | dependencies = [ 64 | "jobserver", 65 | ] 66 | 67 | [[package]] 68 | name = "cfg-if" 69 | version = "1.0.0" 70 | source = "registry+https://github.com/rust-lang/crates.io-index" 71 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 72 | 73 | [[package]] 74 | name = "clipboard-win" 75 | version = "4.3.0" 76 | source = "registry+https://github.com/rust-lang/crates.io-index" 77 | checksum = "1951fb8aa063a2ee18b4b4d217e4aa2ec9cc4f2430482983f607fa10cd36d7aa" 78 | dependencies = [ 79 | "error-code", 80 | "str-buf", 81 | "winapi", 82 | ] 83 | 84 | [[package]] 85 | name = "colored" 86 | version = "2.0.0" 87 | source = "registry+https://github.com/rust-lang/crates.io-index" 88 | checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" 89 | dependencies = [ 90 | "atty", 91 | "lazy_static", 92 | "winapi", 93 | ] 94 | 95 | [[package]] 96 | name = "dirs" 97 | version = "4.0.0" 98 | source = "registry+https://github.com/rust-lang/crates.io-index" 99 | checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" 100 | dependencies = [ 101 | "dirs-sys", 102 | ] 103 | 104 | [[package]] 105 | name = "dirs-next" 106 | version = "2.0.0" 107 | source = "registry+https://github.com/rust-lang/crates.io-index" 108 | checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" 109 | dependencies = [ 110 | "cfg-if", 111 | "dirs-sys-next", 112 | ] 113 | 114 | [[package]] 115 | name = "dirs-sys" 116 | version = "0.3.6" 117 | source = "registry+https://github.com/rust-lang/crates.io-index" 118 | checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" 119 | dependencies = [ 120 | "libc", 121 | "redox_users", 122 | "winapi", 123 | ] 124 | 125 | [[package]] 126 | name = "dirs-sys-next" 127 | version = "0.1.2" 128 | source = "registry+https://github.com/rust-lang/crates.io-index" 129 | checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" 130 | dependencies = [ 131 | "libc", 132 | "redox_users", 133 | "winapi", 134 | ] 135 | 136 | [[package]] 137 | name = "endian-type" 138 | version = "0.1.2" 139 | source = "registry+https://github.com/rust-lang/crates.io-index" 140 | checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" 141 | 142 | [[package]] 143 | name = "error-code" 144 | version = "2.3.0" 145 | source = "registry+https://github.com/rust-lang/crates.io-index" 146 | checksum = "b5115567ac25674e0043e472be13d14e537f37ea8aa4bdc4aef0c89add1db1ff" 147 | dependencies = [ 148 | "libc", 149 | "str-buf", 150 | ] 151 | 152 | [[package]] 153 | name = "fd-lock" 154 | version = "3.0.2" 155 | source = "registry+https://github.com/rust-lang/crates.io-index" 156 | checksum = "a16910e685088843d53132b04e0f10a571fdb193224fc589685b3ba1ce4cb03d" 157 | dependencies = [ 158 | "cfg-if", 159 | "libc", 160 | "windows-sys", 161 | ] 162 | 163 | [[package]] 164 | name = "form_urlencoded" 165 | version = "1.0.1" 166 | source = "registry+https://github.com/rust-lang/crates.io-index" 167 | checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" 168 | dependencies = [ 169 | "matches", 170 | "percent-encoding", 171 | ] 172 | 173 | [[package]] 174 | name = "fs_extra" 175 | version = "1.2.0" 176 | source = "registry+https://github.com/rust-lang/crates.io-index" 177 | checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394" 178 | 179 | [[package]] 180 | name = "getrandom" 181 | version = "0.2.4" 182 | source = "registry+https://github.com/rust-lang/crates.io-index" 183 | checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c" 184 | dependencies = [ 185 | "cfg-if", 186 | "libc", 187 | "wasi", 188 | ] 189 | 190 | [[package]] 191 | name = "gimli" 192 | version = "0.26.1" 193 | source = "registry+https://github.com/rust-lang/crates.io-index" 194 | checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" 195 | 196 | [[package]] 197 | name = "git2" 198 | version = "0.14.2" 199 | source = "registry+https://github.com/rust-lang/crates.io-index" 200 | checksum = "3826a6e0e2215d7a41c2bfc7c9244123969273f3476b939a226aac0ab56e9e3c" 201 | dependencies = [ 202 | "bitflags", 203 | "libc", 204 | "libgit2-sys", 205 | "log", 206 | "openssl-probe", 207 | "openssl-sys", 208 | "url", 209 | ] 210 | 211 | [[package]] 212 | name = "hermit-abi" 213 | version = "0.1.19" 214 | source = "registry+https://github.com/rust-lang/crates.io-index" 215 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 216 | dependencies = [ 217 | "libc", 218 | ] 219 | 220 | [[package]] 221 | name = "idna" 222 | version = "0.2.3" 223 | source = "registry+https://github.com/rust-lang/crates.io-index" 224 | checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" 225 | dependencies = [ 226 | "matches", 227 | "unicode-bidi", 228 | "unicode-normalization", 229 | ] 230 | 231 | [[package]] 232 | name = "jobserver" 233 | version = "0.1.24" 234 | source = "registry+https://github.com/rust-lang/crates.io-index" 235 | checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" 236 | dependencies = [ 237 | "libc", 238 | ] 239 | 240 | [[package]] 241 | name = "lazy_static" 242 | version = "1.4.0" 243 | source = "registry+https://github.com/rust-lang/crates.io-index" 244 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 245 | 246 | [[package]] 247 | name = "libc" 248 | version = "0.2.112" 249 | source = "registry+https://github.com/rust-lang/crates.io-index" 250 | checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" 251 | 252 | [[package]] 253 | name = "libgit2-sys" 254 | version = "0.13.2+1.4.2" 255 | source = "registry+https://github.com/rust-lang/crates.io-index" 256 | checksum = "3a42de9a51a5c12e00fc0e4ca6bc2ea43582fc6418488e8f615e905d886f258b" 257 | dependencies = [ 258 | "cc", 259 | "libc", 260 | "libssh2-sys", 261 | "libz-sys", 262 | "openssl-sys", 263 | "pkg-config", 264 | ] 265 | 266 | [[package]] 267 | name = "libssh2-sys" 268 | version = "0.2.23" 269 | source = "registry+https://github.com/rust-lang/crates.io-index" 270 | checksum = "b094a36eb4b8b8c8a7b4b8ae43b2944502be3e59cd87687595cf6b0a71b3f4ca" 271 | dependencies = [ 272 | "cc", 273 | "libc", 274 | "libz-sys", 275 | "openssl-sys", 276 | "pkg-config", 277 | "vcpkg", 278 | ] 279 | 280 | [[package]] 281 | name = "libz-sys" 282 | version = "1.1.3" 283 | source = "registry+https://github.com/rust-lang/crates.io-index" 284 | checksum = "de5435b8549c16d423ed0c03dbaafe57cf6c3344744f1242520d59c9d8ecec66" 285 | dependencies = [ 286 | "cc", 287 | "libc", 288 | "pkg-config", 289 | "vcpkg", 290 | ] 291 | 292 | [[package]] 293 | name = "log" 294 | version = "0.4.14" 295 | source = "registry+https://github.com/rust-lang/crates.io-index" 296 | checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" 297 | dependencies = [ 298 | "cfg-if", 299 | ] 300 | 301 | [[package]] 302 | name = "matches" 303 | version = "0.1.9" 304 | source = "registry+https://github.com/rust-lang/crates.io-index" 305 | checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" 306 | 307 | [[package]] 308 | name = "memchr" 309 | version = "2.4.1" 310 | source = "registry+https://github.com/rust-lang/crates.io-index" 311 | checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" 312 | 313 | [[package]] 314 | name = "memoffset" 315 | version = "0.6.5" 316 | source = "registry+https://github.com/rust-lang/crates.io-index" 317 | checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" 318 | dependencies = [ 319 | "autocfg", 320 | ] 321 | 322 | [[package]] 323 | name = "miniz_oxide" 324 | version = "0.4.4" 325 | source = "registry+https://github.com/rust-lang/crates.io-index" 326 | checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" 327 | dependencies = [ 328 | "adler", 329 | "autocfg", 330 | ] 331 | 332 | [[package]] 333 | name = "nibble_vec" 334 | version = "0.1.0" 335 | source = "registry+https://github.com/rust-lang/crates.io-index" 336 | checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" 337 | dependencies = [ 338 | "smallvec", 339 | ] 340 | 341 | [[package]] 342 | name = "nix" 343 | version = "0.23.1" 344 | source = "registry+https://github.com/rust-lang/crates.io-index" 345 | checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6" 346 | dependencies = [ 347 | "bitflags", 348 | "cc", 349 | "cfg-if", 350 | "libc", 351 | "memoffset", 352 | ] 353 | 354 | [[package]] 355 | name = "object" 356 | version = "0.27.1" 357 | source = "registry+https://github.com/rust-lang/crates.io-index" 358 | checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9" 359 | dependencies = [ 360 | "memchr", 361 | ] 362 | 363 | [[package]] 364 | name = "openssl-probe" 365 | version = "0.1.5" 366 | source = "registry+https://github.com/rust-lang/crates.io-index" 367 | checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" 368 | 369 | [[package]] 370 | name = "openssl-sys" 371 | version = "0.9.72" 372 | source = "registry+https://github.com/rust-lang/crates.io-index" 373 | checksum = "7e46109c383602735fa0a2e48dd2b7c892b048e1bf69e5c3b1d804b7d9c203cb" 374 | dependencies = [ 375 | "autocfg", 376 | "cc", 377 | "libc", 378 | "pkg-config", 379 | "vcpkg", 380 | ] 381 | 382 | [[package]] 383 | name = "percent-encoding" 384 | version = "2.1.0" 385 | source = "registry+https://github.com/rust-lang/crates.io-index" 386 | checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" 387 | 388 | [[package]] 389 | name = "pkg-config" 390 | version = "0.3.24" 391 | source = "registry+https://github.com/rust-lang/crates.io-index" 392 | checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe" 393 | 394 | [[package]] 395 | name = "radix_trie" 396 | version = "0.2.1" 397 | source = "registry+https://github.com/rust-lang/crates.io-index" 398 | checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" 399 | dependencies = [ 400 | "endian-type", 401 | "nibble_vec", 402 | ] 403 | 404 | [[package]] 405 | name = "redox_syscall" 406 | version = "0.2.10" 407 | source = "registry+https://github.com/rust-lang/crates.io-index" 408 | checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" 409 | dependencies = [ 410 | "bitflags", 411 | ] 412 | 413 | [[package]] 414 | name = "redox_users" 415 | version = "0.4.0" 416 | source = "registry+https://github.com/rust-lang/crates.io-index" 417 | checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" 418 | dependencies = [ 419 | "getrandom", 420 | "redox_syscall", 421 | ] 422 | 423 | [[package]] 424 | name = "rustc-demangle" 425 | version = "0.1.21" 426 | source = "registry+https://github.com/rust-lang/crates.io-index" 427 | checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" 428 | 429 | [[package]] 430 | name = "rustyline" 431 | version = "9.1.2" 432 | source = "registry+https://github.com/rust-lang/crates.io-index" 433 | checksum = "db7826789c0e25614b03e5a54a0717a86f9ff6e6e5247f92b369472869320039" 434 | dependencies = [ 435 | "bitflags", 436 | "cfg-if", 437 | "clipboard-win", 438 | "dirs-next", 439 | "fd-lock", 440 | "libc", 441 | "log", 442 | "memchr", 443 | "nix", 444 | "radix_trie", 445 | "scopeguard", 446 | "smallvec", 447 | "unicode-segmentation", 448 | "unicode-width", 449 | "utf8parse", 450 | "winapi", 451 | ] 452 | 453 | [[package]] 454 | name = "scopeguard" 455 | version = "1.1.0" 456 | source = "registry+https://github.com/rust-lang/crates.io-index" 457 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 458 | 459 | [[package]] 460 | name = "serde" 461 | version = "1.0.133" 462 | source = "registry+https://github.com/rust-lang/crates.io-index" 463 | checksum = "97565067517b60e2d1ea8b268e59ce036de907ac523ad83a0475da04e818989a" 464 | 465 | [[package]] 466 | name = "smallvec" 467 | version = "1.8.0" 468 | source = "registry+https://github.com/rust-lang/crates.io-index" 469 | checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" 470 | 471 | [[package]] 472 | name = "str-buf" 473 | version = "1.0.5" 474 | source = "registry+https://github.com/rust-lang/crates.io-index" 475 | checksum = "d44a3643b4ff9caf57abcee9c2c621d6c03d9135e0d8b589bd9afb5992cb176a" 476 | 477 | [[package]] 478 | name = "tinyvec" 479 | version = "1.5.1" 480 | source = "registry+https://github.com/rust-lang/crates.io-index" 481 | checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" 482 | dependencies = [ 483 | "tinyvec_macros", 484 | ] 485 | 486 | [[package]] 487 | name = "tinyvec_macros" 488 | version = "0.1.0" 489 | source = "registry+https://github.com/rust-lang/crates.io-index" 490 | checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" 491 | 492 | [[package]] 493 | name = "toml" 494 | version = "0.5.8" 495 | source = "registry+https://github.com/rust-lang/crates.io-index" 496 | checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" 497 | dependencies = [ 498 | "serde", 499 | ] 500 | 501 | [[package]] 502 | name = "unicode-bidi" 503 | version = "0.3.7" 504 | source = "registry+https://github.com/rust-lang/crates.io-index" 505 | checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" 506 | 507 | [[package]] 508 | name = "unicode-normalization" 509 | version = "0.1.19" 510 | source = "registry+https://github.com/rust-lang/crates.io-index" 511 | checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" 512 | dependencies = [ 513 | "tinyvec", 514 | ] 515 | 516 | [[package]] 517 | name = "unicode-segmentation" 518 | version = "1.8.0" 519 | source = "registry+https://github.com/rust-lang/crates.io-index" 520 | checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" 521 | 522 | [[package]] 523 | name = "unicode-width" 524 | version = "0.1.9" 525 | source = "registry+https://github.com/rust-lang/crates.io-index" 526 | checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" 527 | 528 | [[package]] 529 | name = "url" 530 | version = "2.2.2" 531 | source = "registry+https://github.com/rust-lang/crates.io-index" 532 | checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" 533 | dependencies = [ 534 | "form_urlencoded", 535 | "idna", 536 | "matches", 537 | "percent-encoding", 538 | ] 539 | 540 | [[package]] 541 | name = "utf8parse" 542 | version = "0.2.0" 543 | source = "registry+https://github.com/rust-lang/crates.io-index" 544 | checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372" 545 | 546 | [[package]] 547 | name = "vcpkg" 548 | version = "0.2.15" 549 | source = "registry+https://github.com/rust-lang/crates.io-index" 550 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 551 | 552 | [[package]] 553 | name = "wasi" 554 | version = "0.10.2+wasi-snapshot-preview1" 555 | source = "registry+https://github.com/rust-lang/crates.io-index" 556 | checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" 557 | 558 | [[package]] 559 | name = "winapi" 560 | version = "0.3.9" 561 | source = "registry+https://github.com/rust-lang/crates.io-index" 562 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 563 | dependencies = [ 564 | "winapi-i686-pc-windows-gnu", 565 | "winapi-x86_64-pc-windows-gnu", 566 | ] 567 | 568 | [[package]] 569 | name = "winapi-i686-pc-windows-gnu" 570 | version = "0.4.0" 571 | source = "registry+https://github.com/rust-lang/crates.io-index" 572 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 573 | 574 | [[package]] 575 | name = "winapi-x86_64-pc-windows-gnu" 576 | version = "0.4.0" 577 | source = "registry+https://github.com/rust-lang/crates.io-index" 578 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 579 | 580 | [[package]] 581 | name = "windows-sys" 582 | version = "0.28.0" 583 | source = "registry+https://github.com/rust-lang/crates.io-index" 584 | checksum = "82ca39602d5cbfa692c4b67e3bcbb2751477355141c1ed434c94da4186836ff6" 585 | dependencies = [ 586 | "windows_aarch64_msvc", 587 | "windows_i686_gnu", 588 | "windows_i686_msvc", 589 | "windows_x86_64_gnu", 590 | "windows_x86_64_msvc", 591 | ] 592 | 593 | [[package]] 594 | name = "windows_aarch64_msvc" 595 | version = "0.28.0" 596 | source = "registry+https://github.com/rust-lang/crates.io-index" 597 | checksum = "52695a41e536859d5308cc613b4a022261a274390b25bd29dfff4bf08505f3c2" 598 | 599 | [[package]] 600 | name = "windows_i686_gnu" 601 | version = "0.28.0" 602 | source = "registry+https://github.com/rust-lang/crates.io-index" 603 | checksum = "f54725ac23affef038fecb177de6c9bf065787c2f432f79e3c373da92f3e1d8a" 604 | 605 | [[package]] 606 | name = "windows_i686_msvc" 607 | version = "0.28.0" 608 | source = "registry+https://github.com/rust-lang/crates.io-index" 609 | checksum = "51d5158a43cc43623c0729d1ad6647e62fa384a3d135fd15108d37c683461f64" 610 | 611 | [[package]] 612 | name = "windows_x86_64_gnu" 613 | version = "0.28.0" 614 | source = "registry+https://github.com/rust-lang/crates.io-index" 615 | checksum = "bc31f409f565611535130cfe7ee8e6655d3fa99c1c61013981e491921b5ce954" 616 | 617 | [[package]] 618 | name = "windows_x86_64_msvc" 619 | version = "0.28.0" 620 | source = "registry+https://github.com/rust-lang/crates.io-index" 621 | checksum = "3f2b8c7cbd3bfdddd9ab98769f9746a7fad1bca236554cd032b78d768bc0e89f" 622 | 623 | [[package]] 624 | name = "wu" 625 | version = "0.1.0" 626 | dependencies = [ 627 | "backtrace", 628 | "colored", 629 | "dirs", 630 | "fs_extra", 631 | "git2", 632 | "rustyline", 633 | "toml", 634 | ] 635 | -------------------------------------------------------------------------------- /src/wu/compiler/compiler.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | use std::collections::HashMap; 4 | use std::path::Path; 5 | use std::ffi::OsStr; 6 | 7 | #[derive(Clone, PartialEq)] 8 | pub enum FlagImplicit { 9 | Return, 10 | Global, 11 | Assign(String), 12 | } 13 | 14 | #[derive(Clone, PartialEq)] 15 | pub enum Inside { 16 | Loop, 17 | //Nothing, 18 | Then, 19 | } 20 | 21 | pub struct Generator<'g> { 22 | source: &'g Source, 23 | 24 | flag: Option, 25 | inside: Vec, 26 | 27 | loop_depth: usize, 28 | special_break: bool, 29 | 30 | method_calls: &'g HashMap, 31 | import_map: &'g HashMap, 32 | } 33 | 34 | impl<'g> Generator<'g> { 35 | pub fn new( 36 | source: &'g Source, 37 | method_calls: &'g HashMap, 38 | import_map: &'g HashMap, 39 | ) -> Self { 40 | Generator { 41 | source, 42 | 43 | flag: None, 44 | inside: Vec::new(), 45 | 46 | loop_depth: 0, 47 | special_break: false, 48 | 49 | method_calls, 50 | import_map, 51 | } 52 | } 53 | 54 | fn get_names(statements: &Vec) -> Vec { 55 | use self::StatementNode::*; 56 | 57 | let mut names = Vec::new(); 58 | 59 | for statement in statements { 60 | let mut statement = statement.clone(); 61 | if let ExternBlock(ref s) = statement.node { 62 | if let Variable(..) = s.node { 63 | statement.node = s.node.clone() 64 | } 65 | } 66 | 67 | match statement.node { 68 | Variable(_, ref name, ..) => names.push(name.to_owned()), 69 | Import(ref name, ref imports, _) => { 70 | if imports.len() == 0 { 71 | names.push(name.to_owned()) 72 | } else { 73 | names.append(&mut imports.to_owned()) 74 | } 75 | } 76 | _ => (), 77 | } 78 | } 79 | 80 | names.dedup(); 81 | 82 | names 83 | } 84 | 85 | pub fn generate(&mut self, ast: &'g Vec) -> String { 86 | let mut result = "return (function()\n".to_string(); 87 | let mut output = String::new(); 88 | 89 | for statement in ast.iter() { 90 | let line = self.generate_statement(&statement); 91 | output.push_str(&line); 92 | 93 | if line.trim().len() > 0 { 94 | output.push('\n') 95 | } 96 | } 97 | 98 | self.push_line(&mut result, &output); 99 | 100 | result.push_str(" return {\n"); 101 | 102 | let mut assignments = String::new(); 103 | 104 | for name in Self::get_names(ast) { 105 | assignments.push_str(&format!(" {0} = {0},\n", Self::make_valid(&name))) 106 | } 107 | 108 | self.push_line(&mut result, &assignments); 109 | 110 | result.push_str(" }"); 111 | 112 | result.push_str("\nend)()"); 113 | 114 | result 115 | } 116 | 117 | fn generate_statement(&mut self, statement: &Statement) -> String { 118 | use self::StatementNode::*; 119 | 120 | let result = match statement.node { 121 | Expression(ref expression) => self.generate_expression(expression), 122 | Variable(_, ref left, ref right, _) => self.generate_local(left, right), 123 | Assignment(ref left, ref right) => self.generate_assignment(left, right), 124 | SplatVariable(_, ref splats, ref right, _) => { 125 | let mut left = String::new(); 126 | 127 | for (i, splat) in splats.iter().enumerate() { 128 | left.push_str(&splat); 129 | 130 | if i < splats.len() - 1 { 131 | left.push_str(", ") 132 | } 133 | } 134 | 135 | self.generate_local(left.as_str(), right) 136 | } 137 | 138 | SplatAssignment(ref splats, ref right) => { 139 | let mut left_string = String::new(); 140 | 141 | for (i, splat) in splats.iter().enumerate() { 142 | left_string.push_str(&self.generate_expression(&splat)); 143 | 144 | if i < splats.len() - 1 { 145 | left_string.push_str(", ") 146 | } 147 | } 148 | 149 | let flag_backup = self.flag.clone(); 150 | 151 | self.flag = Some(FlagImplicit::Assign(left_string.clone())); 152 | 153 | let right_string = self.generate_expression(right); 154 | 155 | self.flag = flag_backup; 156 | 157 | let result = format!("{} = {}", left_string, right_string); 158 | 159 | result 160 | } 161 | 162 | ExternBlock(..) => String::new(), 163 | 164 | Return(ref expr) => { 165 | if let Some(ref expr) = *expr { 166 | use self::ExpressionNode::*; 167 | 168 | let flag_backup = self.flag.clone(); 169 | 170 | self.flag = Some(FlagImplicit::Return); 171 | 172 | let line = match expr.node { 173 | Block(..) | If(..) | While(..) => self.generate_expression(expr), 174 | _ => format!("return {}", self.generate_expression(expr)), 175 | }; 176 | 177 | self.flag = flag_backup; 178 | 179 | line 180 | } else { 181 | "return\n".to_string() 182 | } 183 | } 184 | 185 | Import(ref name, ref specifics, _) => { 186 | let mut file_path = if let Some(new_path) = self.import_map.get(&statement.pos) { 187 | format!( 188 | "{}", 189 | new_path 190 | .1 191 | .clone() 192 | .split(&format!("/{}", name)) 193 | .collect::>()[0] 194 | .to_string() 195 | ) 196 | } else { 197 | let my_folder = Path::new(&self.source.file.0).parent().unwrap(); 198 | format!("{}/{}", my_folder.to_str().unwrap(), name) 199 | }; 200 | 201 | if file_path.starts_with("./") { 202 | file_path = file_path[2..].to_string() 203 | } 204 | 205 | let real_path = &Path::new(&file_path) 206 | .iter() 207 | .map(|x: &OsStr| format!("{}", x.to_str().unwrap())) 208 | .collect::>() 209 | .join("."); 210 | 211 | let mut result:String; 212 | 213 | if self.import_map.get(&statement.pos).is_some() { 214 | let path = file_path[..file_path.len() - 1].to_string(); 215 | result = format!( 216 | "package.path = package.path .. ';{0}?.lua;{0}?/init.lua'\n", 217 | path 218 | ); 219 | result.push_str(&format!("local {0} = require('{0}')\n", name)) 220 | } else { 221 | result = format!("local {} = require('{}')\n", name, real_path) 222 | } 223 | 224 | for specific in specifics { 225 | result.push_str(&format!("local {0} = {1}['{0}']\n", specific, name)) 226 | } 227 | 228 | result.push('\n'); 229 | 230 | result 231 | } 232 | 233 | Break => { 234 | if self.special_break { 235 | format!("__brk_{} = true break", self.loop_depth) 236 | } else { 237 | String::from("break") 238 | } 239 | } 240 | 241 | Skip => String::from("break"), 242 | 243 | Implement(ref name, ref body, _) => { 244 | if let ExpressionNode::Block(ref content) = body.node { 245 | let assign = self.generate_expression(name); 246 | 247 | let flag_backup = self.flag.clone(); 248 | 249 | let mut result = String::new(); 250 | 251 | for element in content { 252 | if let Variable(_, ref name, ref right, _) = element.node { 253 | if let ExpressionNode::Extern(_, ref lua) = right.clone().unwrap().node 254 | { 255 | if let Some(ref lua) = lua { 256 | let assign = 257 | format!("{}['{}']", assign, Self::make_valid(name)); 258 | 259 | result.push_str(&format!("{} = {}\n\n", assign, lua)) 260 | } 261 | } else { 262 | let assign = format!("{}['{}']", assign, Self::make_valid(name)); 263 | 264 | self.flag = Some(FlagImplicit::Assign(assign.clone())); 265 | 266 | let right = self.generate_expression(&right.clone().unwrap()); 267 | 268 | result.push_str(&format!("{} = {}\n\n", assign, right)) 269 | } 270 | } 271 | } 272 | 273 | self.flag = flag_backup; 274 | 275 | result 276 | } else { 277 | unreachable!() 278 | } 279 | } 280 | }; 281 | 282 | result 283 | } 284 | 285 | fn generate_expression(&mut self, expression: &Expression) -> String { 286 | use self::ExpressionNode::*; 287 | use std::string; 288 | 289 | let result = match expression.node { 290 | Splat(ref splats) => { 291 | let mut result = String::new(); 292 | 293 | for (i, splat) in splats.iter().enumerate() { 294 | result.push_str(&self.generate_expression(&splat)); 295 | 296 | if i < splats.len() - 1 { 297 | result.push_str(", ") 298 | } 299 | } 300 | 301 | result 302 | } 303 | 304 | Binary(ref left, ref op, ref right) => { 305 | let mut result = string::String::new(); 306 | 307 | match op { 308 | Operator::PipeLeft => { 309 | return format!( 310 | "{}({})", 311 | self.generate_expression(&left), 312 | self.generate_expression(&right) 313 | ) 314 | } 315 | 316 | Operator::PipeRight => { 317 | return format!( 318 | "{}({})", 319 | self.generate_expression(&right), 320 | self.generate_expression(&left) 321 | ) 322 | } 323 | 324 | _ => (), 325 | } 326 | 327 | let folded = Parser::fold_expression(&expression); 328 | 329 | if &folded != expression { 330 | result = self.generate_expression(&folded) 331 | } else { 332 | result.push_str(&format!( 333 | "({} {} {})", 334 | self.generate_expression(&left), 335 | self.generate_operator(&op), 336 | self.generate_expression(&right), 337 | )); 338 | } 339 | 340 | result 341 | } 342 | 343 | Call(ref called, ref args) => { 344 | let flag_backup = self.flag.clone(); 345 | 346 | self.flag = Some(FlagImplicit::Assign("none".to_string())); 347 | let mut caller = self.generate_expression(called); 348 | let mut result = format!("{}(", caller); 349 | 350 | let prefix = self.method_calls.get(&called.pos).is_some(); 351 | 352 | if let Index(ref left, ..) = called.node { 353 | caller = self.generate_expression(left) 354 | } 355 | 356 | if prefix { 357 | result.push_str(&caller); 358 | 359 | if args.len() > 0 { 360 | result.push_str(", ") 361 | } 362 | } 363 | 364 | for (i, arg) in args.iter().enumerate() { 365 | result.push_str(&self.generate_expression(arg)); 366 | 367 | if i < args.len() - 1 { 368 | result.push_str(", ") 369 | } 370 | } 371 | 372 | result.push(')'); 373 | 374 | self.flag = flag_backup; 375 | 376 | result 377 | } 378 | 379 | Module(ref content) => { 380 | if let Block(ref elements) = content.node { 381 | let mut result = "(function()\n".to_string(); 382 | 383 | let mut body = String::new(); 384 | 385 | for element in elements { 386 | body.push_str(&self.generate_statement(&element)) 387 | } 388 | 389 | body.push_str("\nreturn {\n"); 390 | 391 | let mut assignments = String::new(); 392 | 393 | for name in Self::get_names(elements) { 394 | assignments.push_str(&format!("{0} = {0},\n", name)) 395 | } 396 | 397 | self.push_line(&mut body, &assignments); 398 | 399 | body.push('}'); 400 | 401 | self.push_line(&mut result, &body); 402 | 403 | result.push_str("end)()"); 404 | 405 | result 406 | } else { 407 | unreachable!() 408 | } 409 | } 410 | 411 | Block(ref content) => { 412 | let flag_backup = self.flag.clone(); 413 | let flag = self.flag.clone(); 414 | 415 | let mut in_return = false; 416 | 417 | let mut result = if let Some(ref f) = flag { 418 | match *f { 419 | FlagImplicit::Assign(_) => { 420 | self.flag = Some(FlagImplicit::Return); 421 | 422 | "(function()\n" 423 | } 424 | 425 | FlagImplicit::Return => { 426 | in_return = true; 427 | self.flag = None; 428 | 429 | "" 430 | } 431 | 432 | _ => { 433 | if content.len() == 1 && !self.inside.contains(&Inside::Then) { 434 | "do\n" 435 | } else { 436 | "" 437 | } 438 | } 439 | } 440 | } else { 441 | if !self.inside.contains(&Inside::Then) { 442 | "do\n" 443 | } else { 444 | "" 445 | } 446 | } 447 | .to_string(); 448 | 449 | for (i, element) in content.iter().enumerate() { 450 | if i == content.len() - 1 { 451 | if in_return { 452 | self.flag = flag.clone(); 453 | } 454 | 455 | if self.flag.is_some() { 456 | if let StatementNode::Expression(ref expression) = element.node { 457 | match expression.node { 458 | Block(_) => (), 459 | _ => match &self.flag.clone().unwrap() { 460 | &FlagImplicit::Return => { 461 | let line = match expression.node { 462 | Block(..) | If(..) | While(..) => { 463 | self.generate_expression(expression) 464 | } 465 | 466 | ExpressionNode::EOF | ExpressionNode::Empty => { 467 | String::new() 468 | } 469 | 470 | _ => format!( 471 | "return {}", 472 | self.generate_expression(expression) 473 | ), 474 | }; 475 | 476 | result.push_str(&self.make_line(&line)); 477 | 478 | break; 479 | } 480 | 481 | _ => (), 482 | }, 483 | } 484 | } 485 | } 486 | } 487 | 488 | let line = self.generate_statement(&element); 489 | result.push_str(&self.make_line(&line)); 490 | } 491 | 492 | self.flag = flag_backup; 493 | 494 | if let Some(ref f) = flag { 495 | match *f { 496 | FlagImplicit::Assign(_) => { 497 | self.flag = Some(FlagImplicit::Return); 498 | 499 | result.push_str("end)()") 500 | } 501 | 502 | FlagImplicit::Return => (), 503 | 504 | _ => { 505 | if !self.inside.contains(&Inside::Then) { 506 | result.push_str("end\n") 507 | } else { 508 | () 509 | } 510 | } 511 | } 512 | } else { 513 | if !self.inside.contains(&Inside::Then) { 514 | result.push_str("end\n") 515 | } 516 | } 517 | 518 | result 519 | } 520 | 521 | Function(ref params, _, ref body, is_method) => { 522 | let mut result = "function(".to_string(); 523 | 524 | if is_method { 525 | result.push_str("self"); 526 | 527 | if params.len() > 0 { 528 | result.push_str(", ") 529 | } 530 | } 531 | 532 | let mut splat = None; 533 | 534 | for (i, param) in params.iter().enumerate() { 535 | if let TypeMode::Splat(_) = param.1.mode { 536 | result.push_str("..."); 537 | 538 | splat = Some(param.0.clone()) 539 | } else { 540 | result.push_str(¶m.0); 541 | } 542 | 543 | if i < params.len() - 1 { 544 | result.push_str(", ") 545 | } 546 | } 547 | 548 | result.push_str(")\n"); 549 | 550 | if let Some(ref name) = splat { 551 | result.push_str(&format!(" local {} = {{...}}\n", name)) 552 | } 553 | 554 | let flag_backup = self.flag.clone(); 555 | self.flag = Some(FlagImplicit::Return); 556 | 557 | let line = match body.node { 558 | Block(..) | If(..) | While(..) => self.generate_expression(body), 559 | _ => format!("return {}", self.generate_expression(body)), 560 | }; 561 | 562 | self.flag = flag_backup; 563 | 564 | result.push_str(&&line); 565 | result.push_str("end\n"); 566 | 567 | result 568 | } 569 | 570 | Tuple(ref content) => { 571 | let mut result = String::new(); 572 | 573 | for (i, element) in content.iter().enumerate() { 574 | result.push_str( 575 | &self.generate_expression(&element) 576 | ); 577 | 578 | if i != content.len() - 1 { 579 | result.push_str(", ") 580 | } 581 | } 582 | 583 | if self.flag == Some(FlagImplicit::Return) { 584 | result 585 | } else { 586 | format!("{}", result) 587 | } 588 | } 589 | 590 | Array(ref content) => { 591 | let mut result = "{\n".to_string(); 592 | 593 | for (i, arg) in content.iter().enumerate() { 594 | let value = self.generate_expression(arg); 595 | let mut line = format!("[{}] = {}", i + 1, value); 596 | 597 | if i < content.len() - 1 { 598 | line.push(',') 599 | } 600 | 601 | result.push_str(&self.make_line(&line)); 602 | } 603 | 604 | result.push_str("}"); 605 | 606 | result 607 | } 608 | 609 | Index(ref source, ref index, is_braces) => { 610 | let source = self.generate_expression(source); 611 | 612 | let index = if let Identifier(ref name) = index.node { 613 | if is_braces { 614 | format!("{}", Self::make_valid(name)) 615 | } else { 616 | format!("'{}'", Self::make_valid(name)) 617 | } 618 | } else { 619 | self.generate_expression(index) 620 | }; 621 | 622 | format!("{}[{}]", source, index) 623 | } 624 | 625 | If(ref condition, ref body, ref elses) => { 626 | let flag_backup = self.flag.clone(); 627 | 628 | self.inside.push(Inside::Then); 629 | 630 | let mut result = if let Some(FlagImplicit::Assign(_)) = self.flag { 631 | self.flag = Some(FlagImplicit::Return); 632 | 633 | "(function()\n" 634 | } else { 635 | "" 636 | } 637 | .to_string(); 638 | 639 | result.push_str(&format!( 640 | "if {} then\n", 641 | self.generate_expression(condition) 642 | )); 643 | 644 | let mut body_string = self.generate_expression(&body); // doing this to remove redundant 'do' and 'end' 645 | 646 | // if let Block(ref content) = body.node { 647 | // for (i, element) in content.iter().enumerate() { 648 | // if i == content.len() - 1 { 649 | // if self.flag.is_some() { 650 | // if let StatementNode::Expression(ref expression) = element.node { 651 | // match expression.node { 652 | // Block(_) | If(..) | While(..) => (), 653 | // _ => match &self.flag.clone().unwrap() { 654 | // &FlagImplicit::Return => { 655 | // let line = match body.node { 656 | // Block(..) | If(..) | While(..) => self.generate_expression(body), 657 | // _ => format!("return {}", self.generate_expression(body)), 658 | // }; 659 | 660 | // result.push_str(&self.make_line(&line)); 661 | 662 | // break 663 | // }, 664 | 665 | // _ => () 666 | // }, 667 | // } 668 | // } 669 | // } 670 | // } 671 | 672 | // let line = self.generate_statement(&element); 673 | // result.push_str(&self.make_line(&line)); 674 | // } 675 | // } 676 | 677 | result.push_str(&body_string); 678 | 679 | if let &Some(ref elses) = elses { 680 | for branch in elses { 681 | if let Some(ref condition) = branch.0 { 682 | result.push_str(&format!( 683 | "elseif {} then\n", 684 | self.generate_expression(condition) 685 | )); 686 | } else { 687 | result.push_str("else\n") 688 | } 689 | 690 | body_string = self.generate_expression(&branch.1); 691 | 692 | /*if let Block(ref content) = branch.1.node { 693 | for (i, element) in content.iter().enumerate() { 694 | if i == content.len() - 1 { 695 | if self.flag.is_some() { 696 | if let StatementNode::Expression(ref expression) = element.node { 697 | match expression.node { 698 | Block(_) | If(..) | While(..) => (), 699 | _ => match &self.flag.clone().unwrap() { 700 | &FlagImplicit::Return => { 701 | let line = match body.node { 702 | Block(..) | If(..) | While(..) => self.generate_expression(&branch.1), 703 | _ => format!("return {}", self.generate_expression(&branch.1)), 704 | }; 705 | 706 | result.push_str(&self.make_line(&line)); 707 | 708 | continue 709 | }, 710 | 711 | _ => () 712 | }, 713 | } 714 | } 715 | } 716 | } 717 | let line = self.generate_statement(&element); 718 | result.push_str(&self.make_line(&line)); 719 | } 720 | }*/ 721 | 722 | result.push_str(&self.make_line(&body_string)); 723 | } 724 | } 725 | 726 | self.flag = flag_backup; 727 | self.inside.pop(); 728 | 729 | if let Some(FlagImplicit::Assign(_)) = self.flag { 730 | result.push_str("end\nend)()") 731 | } else { 732 | result.push_str("end\n") 733 | } 734 | 735 | result 736 | } 737 | 738 | For(ref iterator, ref body) => { 739 | let flag_backup = self.flag.clone(); 740 | self.inside.push(Inside::Then); 741 | self.special_break = true; 742 | 743 | if self.inside.contains(&Inside::Loop) { 744 | self.loop_depth += 1 745 | } else { 746 | self.loop_depth = 0; 747 | self.inside.push(Inside::Loop) 748 | } 749 | 750 | let mut result = if let Some(FlagImplicit::Assign(_)) = self.flag { 751 | self.flag = Some(FlagImplicit::Return); 752 | 753 | "(function()\n" 754 | } else { 755 | "" 756 | } 757 | .to_string(); 758 | 759 | if self.flag == Some(FlagImplicit::Return) { 760 | self.flag = None 761 | } 762 | 763 | let (expr, iterator) = &*iterator; 764 | 765 | let mut whole = if let Some(ref iterator) = iterator { 766 | let iterator = self.generate_expression(&*iterator); 767 | let expr = self.generate_expression(&*expr); 768 | 769 | format!("for {} in {} do", expr, iterator) 770 | } else { 771 | let iterator = self.generate_expression(&*expr); 772 | 773 | format!("for __iterator_{} = 1, {} do\n", self.loop_depth, iterator) 774 | }; 775 | 776 | let mut body_string = format!("\nlocal __brk_{} = false\n", self.loop_depth); // doing this to remove redundant 'do' and 'end' 777 | 778 | body_string.push_str("repeat\n"); 779 | 780 | if let Block(ref content) = body.node { 781 | for (i, element) in content.iter().enumerate() { 782 | if i == content.len() - 1 { 783 | if StatementNode::Skip == element.node { 784 | break; 785 | } else { 786 | if let StatementNode::Expression(ref expression) = element.node { 787 | if Empty == expression.node { 788 | break; 789 | } 790 | } 791 | } 792 | } 793 | 794 | body_string.push_str(&self.generate_statement(&element)); 795 | body_string.push('\n') 796 | } 797 | } 798 | 799 | // body_string.push_str(&format!("::__while_{}::\n", self.loop_depth)); 800 | body_string.push_str("until true\n"); 801 | body_string.push_str(&format!("if __brk_{} then break end", self.loop_depth)); 802 | 803 | self.push_line(&mut whole, &body_string); 804 | 805 | whole.push_str("end\n"); 806 | 807 | self.special_break = false; 808 | 809 | if let Some(FlagImplicit::Assign(_)) = flag_backup { 810 | self.push_line(&mut result, &whole) 811 | } else { 812 | result.push_str(&whole) 813 | } 814 | 815 | self.flag = flag_backup; 816 | self.inside.pop(); 817 | self.inside.pop(); 818 | 819 | if let Some(FlagImplicit::Assign(_)) = self.flag { 820 | result.push_str("end)()") 821 | } 822 | 823 | result 824 | } 825 | 826 | While(ref condition, ref body) => { 827 | let flag_backup = self.flag.clone(); 828 | self.inside.push(Inside::Then); 829 | 830 | if self.inside.contains(&Inside::Loop) { 831 | self.loop_depth += 1 832 | } else { 833 | self.loop_depth = 0; 834 | self.inside.push(Inside::Loop) 835 | } 836 | 837 | let mut result = if let Some(FlagImplicit::Assign(_)) = self.flag { 838 | self.flag = Some(FlagImplicit::Return); 839 | 840 | "(function()\n" 841 | } else { 842 | "" 843 | } 844 | .to_string(); 845 | 846 | if self.flag == Some(FlagImplicit::Return) { 847 | self.flag = None 848 | } 849 | 850 | let condition = self.generate_expression(condition); 851 | 852 | let mut whole = format!("while {} do\n", condition); 853 | 854 | let mut body_string = "repeat\n".to_string(); // doing this to remove redundant 'do' and 'end' 855 | 856 | if let Block(ref content) = body.node { 857 | for (i, element) in content.iter().enumerate() { 858 | if i == content.len() - 1 { 859 | if StatementNode::Skip == element.node { 860 | break; 861 | } else { 862 | if let StatementNode::Expression(ref expression) = element.node { 863 | if Empty == expression.node { 864 | break; 865 | } 866 | } 867 | } 868 | } 869 | 870 | body_string.push_str(&self.generate_statement(&element)); 871 | body_string.push('\n') 872 | } 873 | } 874 | 875 | // body_string.push_str(&format!("::__while_{}::\n", self.loop_depth)); 876 | body_string.push_str("until true\n"); 877 | 878 | self.push_line(&mut whole, &body_string); 879 | 880 | whole.push_str("end\n"); 881 | 882 | if let Some(FlagImplicit::Assign(_)) = flag_backup { 883 | self.push_line(&mut result, &whole) 884 | } else { 885 | result.push_str(&whole) 886 | } 887 | 888 | self.flag = flag_backup; 889 | self.inside.pop(); 890 | self.inside.pop(); 891 | 892 | if let Some(FlagImplicit::Assign(_)) = self.flag { 893 | result.push_str("end)()") 894 | } 895 | 896 | result 897 | } 898 | 899 | Initialization(ref name, ref body) => { 900 | let mut inner = String::new(); 901 | 902 | for &(ref name, ref expression) in body.iter() { 903 | inner.push_str(&format!( 904 | "{} = {},\n", 905 | name, 906 | self.generate_expression(expression) 907 | )) 908 | } 909 | 910 | format!( 911 | "setmetatable({{\n{}}}, {{__index={}}})", 912 | self.make_line(&inner), 913 | self.generate_expression(name) 914 | ) 915 | } 916 | 917 | Extern(_, ref lua) => { 918 | if let &Some(ref lua) = lua { 919 | lua.to_owned() 920 | } else { 921 | String::new() 922 | } 923 | } 924 | 925 | Int(ref n) => format!("{}", n), 926 | Float(ref n) => format!("{}", n), 927 | Bool(ref n) => format!("{}", n), 928 | Str(ref n) => format!("\"{}\"", n.replace("\\n", "\\\\n").replace('\n', "\\n")), 929 | Char(ref n) => format!("\"{}\"", n), 930 | Identifier(ref n) => Self::make_valid(n), 931 | 932 | Cast(ref a, ref t) => { 933 | use self::TypeNode::*; 934 | 935 | let result = match t.node { 936 | Float => "tonumber(", 937 | Str => "tostring(", 938 | Int => "math.floor(tonumber(", 939 | _ => "(", 940 | }; 941 | 942 | format!( 943 | "{}{}){}", 944 | result, 945 | self.generate_expression(a), 946 | if t.node.strong_cmp(&Int) { ")" } else { "" } 947 | ) 948 | } 949 | UnwrapSplat(ref expression) => { 950 | format!("table.unpack({})", self.generate_expression(expression)) 951 | } 952 | Unwrap(ref expression) => { 953 | self.generate_expression(expression) 954 | } 955 | Neg(ref n) => format!("-{}", self.generate_expression(n)), 956 | Not(ref n) => format!("not {}", self.generate_expression(n)), 957 | 958 | Empty => String::from("nil"), 959 | _ => String::new(), 960 | }; 961 | 962 | result 963 | } 964 | 965 | fn make_valid(n: &String) -> String { 966 | let mut result = String::new(); 967 | 968 | for a in n.chars() { 969 | let new_a = match a { 970 | '?' => "__question_mark__".to_string(), 971 | '!' => "__exclamation_mark__".to_string(), 972 | a => a.to_string(), 973 | }; 974 | 975 | result.push_str(&new_a) 976 | } 977 | 978 | result 979 | } 980 | 981 | fn generate_local(&mut self, name: &str, right: &Option) -> String { 982 | let flag_backup = self.flag.clone(); 983 | 984 | let name = Self::make_valid(&name.to_string()); 985 | 986 | let mut result = { 987 | let output = if self.flag == Some(FlagImplicit::Global) { 988 | name.to_owned() 989 | } else { 990 | format!("local {}", name) 991 | }; 992 | 993 | self.flag = Some(FlagImplicit::Assign(name.to_string())); 994 | 995 | output 996 | }; 997 | 998 | if let &Some(ref right) = right { 999 | if let ExpressionNode::Function(..) = right.node { 1000 | result = self.generate_expression(right); 1001 | result = result.replacen("function", &format!("function {}", name), 1); 1002 | } else { 1003 | let right_str = match right.node { 1004 | ExpressionNode::Struct(..) => "{}".to_string(), 1005 | ExpressionNode::Extern(_, ref lua) if lua.is_none() => return String::new(), 1006 | ExpressionNode::Trait(..) | ExpressionNode::ExternExpression(..) => return String::new(), 1007 | 1008 | _ => self.generate_expression(right), 1009 | }; 1010 | 1011 | result.push_str(&format!(" = {}\n", right_str)) 1012 | } 1013 | } 1014 | 1015 | self.flag = flag_backup; 1016 | 1017 | format!("{}", result) 1018 | } 1019 | 1020 | fn generate_assignment<'b>(&mut self, left: &'b Expression, right: &'b Expression) -> String { 1021 | let left_string = self.generate_expression(left); 1022 | 1023 | let flag_backup = self.flag.clone(); 1024 | 1025 | self.flag = Some(FlagImplicit::Assign(left_string.clone())); 1026 | 1027 | let right_string = self.generate_expression(right); 1028 | 1029 | self.flag = flag_backup; 1030 | 1031 | let result = format!("{} = {}", left_string, right_string); 1032 | 1033 | result 1034 | } 1035 | 1036 | fn generate_operator<'b>(&mut self, op: &'b Operator) -> String { 1037 | use self::Operator::*; 1038 | 1039 | match *op { 1040 | Concat => "..".to_string(), 1041 | NEq => "~=".to_string(), 1042 | _ => format!("{}", op), 1043 | } 1044 | } 1045 | 1046 | fn make_line(&mut self, value: &str) -> String { 1047 | let mut output = String::new(); 1048 | 1049 | for line in value.lines() { 1050 | output.push_str(" "); 1051 | 1052 | output.push_str(&line); 1053 | output.push('\n') 1054 | } 1055 | 1056 | output 1057 | } 1058 | 1059 | fn push_line(&mut self, target: &mut String, value: &str) { 1060 | target.push_str(&self.make_line(&value)) 1061 | } 1062 | } 1063 | -------------------------------------------------------------------------------- /src/wu/parser/parser.rs: -------------------------------------------------------------------------------- 1 | use super::super::error::Response::Wrong; 2 | use super::*; 3 | 4 | use std::rc::Rc; 5 | 6 | pub struct Parser<'p> { 7 | index: usize, 8 | tokens: Vec, 9 | source: &'p Source, 10 | in_sequence: bool, 11 | tmp_sequence: bool, 12 | } 13 | 14 | impl<'p> Parser<'p> { 15 | pub fn new(tokens: Vec, source: &'p Source) -> Self { 16 | Parser { 17 | tokens, 18 | source, 19 | index: 0, 20 | in_sequence: false, 21 | tmp_sequence: false, 22 | } 23 | } 24 | 25 | pub fn parse(&mut self) -> Result, ()> { 26 | let mut ast = Vec::new(); 27 | 28 | while self.remaining() > 0 { 29 | ast.push(self.parse_statement()?) 30 | } 31 | 32 | Ok(ast) 33 | } 34 | 35 | fn parse_statement(&mut self) -> Result { 36 | use self::TokenType::*; 37 | 38 | while self.current_type() == EOL && self.remaining() != 0 { 39 | self.next()? 40 | } 41 | 42 | let position = self.current_position(); 43 | 44 | let statement = match self.current_type() { 45 | Identifier => { 46 | let backup_index = self.index; 47 | let position = self.current_position(); 48 | let name = self.eat_type(&Identifier)?; 49 | 50 | let mut splat_names = vec![name.clone()]; 51 | 52 | while self.current_lexeme() == "," { 53 | self.next()?; 54 | splat_names.push(self.eat_type(&TokenType::Identifier)?) 55 | } 56 | 57 | match self.current_lexeme().as_str() { 58 | ":" => { 59 | self.next()?; 60 | 61 | let position = self.current_position(); 62 | let backup = self.index; 63 | 64 | if splat_names.len() == 1 { 65 | if let Some(right) = self.parse_right_hand(name.clone())? { 66 | let statement = Statement::new( 67 | StatementNode::Variable( 68 | Type::from(TypeNode::Nil), 69 | name, 70 | Some(right), 71 | false 72 | ), 73 | self.span_from(position), 74 | ); 75 | 76 | self.new_line()?; 77 | 78 | return Ok(statement); 79 | } 80 | } 81 | 82 | self.index = backup; 83 | 84 | let kind = if self.current_lexeme() == "=" { 85 | Type::from(TypeNode::Nil) 86 | } else { 87 | self.parse_type()? 88 | }; 89 | 90 | if self.current_lexeme() == "=" { 91 | self.next()?; 92 | 93 | if splat_names.len() > 1 { 94 | Statement::new( 95 | StatementNode::SplatVariable( 96 | kind, 97 | splat_names, 98 | Some(self.parse_expression()?), 99 | false 100 | ), 101 | self.span_from(position), 102 | ) 103 | } else { 104 | Statement::new( 105 | StatementNode::Variable( 106 | kind, 107 | name, 108 | Some(self.parse_expression()?), 109 | false 110 | ), 111 | self.span_from(position), 112 | ) 113 | } 114 | } else { 115 | if splat_names.len() > 1 { 116 | Statement::new( 117 | StatementNode::SplatVariable(kind, splat_names, None, false), 118 | self.span_from(position), 119 | ) 120 | } else { 121 | Statement::new( 122 | StatementNode::Variable(kind, name, None, false), 123 | self.span_from(position), 124 | ) 125 | } 126 | } 127 | } 128 | 129 | "=" => { 130 | self.next()?; 131 | 132 | if splat_names.len() > 1 { 133 | Statement::new( 134 | StatementNode::SplatAssignment( 135 | splat_names 136 | .iter() 137 | .map(|x| { 138 | Expression::new( 139 | ExpressionNode::Identifier(x.clone()), 140 | position.clone(), 141 | ) 142 | }) 143 | .collect::>(), 144 | self.parse_expression()?, 145 | ), 146 | position, 147 | ) 148 | } else { 149 | Statement::new( 150 | StatementNode::Assignment( 151 | Expression::new( 152 | ExpressionNode::Identifier(name), 153 | position.clone(), 154 | ), 155 | self.parse_expression()?, 156 | ), 157 | position, 158 | ) 159 | } 160 | } 161 | 162 | c => { 163 | if splat_names.len() > 1 { 164 | return Err(response!( 165 | Wrong(format!("expected `:` or `=`, found `{}`", c)), 166 | self.source.file, 167 | position 168 | )); 169 | } 170 | 171 | let expression = 172 | Expression::new(ExpressionNode::Identifier(name), position.clone()); 173 | 174 | if let Some(result) = self.try_parse_compound(&expression)? { 175 | result 176 | } else { 177 | self.index = backup_index; 178 | 179 | let expression = self.parse_atom()?; 180 | 181 | if let Some(result) = self.try_parse_compound(&expression)? { 182 | result 183 | } else { 184 | self.index = backup_index; 185 | 186 | let expression = self.parse_expression()?; 187 | let position = expression.pos.clone(); 188 | 189 | if self.current_lexeme() == "=" { 190 | self.next()?; 191 | 192 | Statement::new( 193 | StatementNode::Assignment( 194 | expression, 195 | self.parse_expression()?, 196 | ), 197 | position, 198 | ) 199 | } else { 200 | Statement::new(StatementNode::Expression(expression), position) 201 | } 202 | } 203 | } 204 | } 205 | } 206 | } 207 | 208 | Keyword => match self.current_lexeme().as_str() { 209 | "pub" => { 210 | self.next()?; 211 | 212 | let mut thing = self.parse_statement()?; 213 | 214 | match thing.node { 215 | StatementNode::Variable(.., ref mut public) | 216 | StatementNode::Import(.., ref mut public) | 217 | StatementNode::SplatVariable(.., ref mut public) => { 218 | *public = true 219 | }, 220 | 221 | _ => return Err(response!( 222 | Wrong("expected binding or import"), 223 | self.source.file, 224 | self.current_position() 225 | )) 226 | } 227 | 228 | return Ok(thing) 229 | }, 230 | 231 | "return" => { 232 | self.next()?; 233 | 234 | if ["}", "\n"].contains(&self.current_lexeme().as_str()) { 235 | Statement::new(StatementNode::Return(None), position) 236 | } else { 237 | Statement::new( 238 | StatementNode::Return(Some(Rc::new(self.parse_expression()?))), 239 | self.span_from(position), 240 | ) 241 | } 242 | } 243 | 244 | "break" => { 245 | self.next()?; 246 | 247 | Statement::new(StatementNode::Break, position) 248 | } 249 | 250 | "skip" => { 251 | self.next()?; 252 | 253 | Statement::new(StatementNode::Skip, position) 254 | } 255 | 256 | "import" => { 257 | self.next()?; 258 | 259 | let path = self.eat_type(&Identifier)?; 260 | 261 | let specifics = if self.current_lexeme() == "{" { 262 | self.parse_block_of(("{", "}"), &Self::_parse_name_comma)? 263 | } else { 264 | Vec::new() 265 | }; 266 | 267 | Statement::new( 268 | StatementNode::Import(path, specifics, false), 269 | self.span_from(position), 270 | ) 271 | } 272 | 273 | "implement" => { 274 | let pos = self.span_from(position); 275 | 276 | self.next()?; 277 | self.next_newline()?; 278 | 279 | self.expect_type(TokenType::Identifier)?; 280 | 281 | let start = self.index; 282 | 283 | while self.current_type() == TokenType::Identifier 284 | && self.remaining() > 1 285 | { 286 | self.next()?; 287 | } 288 | 289 | let end = self.index; 290 | 291 | let mut name_parser = 292 | Parser::new(self.tokens[start..end].to_vec(), self.source); 293 | 294 | let name = name_parser.parse_expression()?; 295 | 296 | self.next_newline()?; 297 | 298 | let mut parent = None; 299 | if self.current_lexeme() == ":" { 300 | self.next()?; 301 | 302 | parent = Some(self.parse_expression()?); 303 | 304 | self.next_newline()? 305 | } 306 | 307 | self.expect_lexeme("{")?; 308 | 309 | let body = self.parse_expression()?; 310 | 311 | Statement::new(StatementNode::Implement(name, body, parent), pos) 312 | } 313 | 314 | _ => { 315 | let mut expression = self.parse_expression()?; 316 | expression = self.maybe_splat(expression)?; 317 | 318 | let position = expression.pos.clone(); 319 | 320 | Statement::new(StatementNode::Expression(expression), position) 321 | } 322 | }, 323 | 324 | _ => { 325 | let mut expression = self.parse_expression()?; 326 | expression = self.maybe_splat(expression)?; 327 | 328 | let position = expression.pos.clone(); 329 | 330 | if let Some(result) = self.try_parse_compound(&expression)? { 331 | result 332 | } else { 333 | if self.current_lexeme() == "=" { 334 | self.next()?; 335 | 336 | Statement::new( 337 | StatementNode::Assignment(expression, self.parse_expression()?), 338 | position, 339 | ) 340 | } else { 341 | Statement::new(StatementNode::Expression(expression), position) 342 | } 343 | } 344 | } 345 | }; 346 | 347 | self.new_line()?; 348 | 349 | Ok(statement) 350 | } 351 | 352 | fn maybe_splat(&mut self, expr: Expression) -> Result { 353 | match self.current_lexeme().as_str() { 354 | "," => { 355 | let position = expr.pos.clone(); 356 | let mut splats = vec![expr]; 357 | 358 | self.enter_sequence(); 359 | 360 | while self.current_lexeme() == "," { 361 | self.next()?; 362 | 363 | let expr = self.parse_expression()?; 364 | splats.push(expr) 365 | } 366 | 367 | self.exit_sequence(); 368 | 369 | Ok(Expression::new( 370 | ExpressionNode::Splat(splats), 371 | self.span_from(position), 372 | )) 373 | } 374 | 375 | _ => Ok(expr) 376 | } 377 | } 378 | 379 | fn try_parse_compound(&mut self, left: &Expression) -> Result, ()> { 380 | if self.current_type() != TokenType::Operator { 381 | return Ok(None); 382 | } 383 | 384 | let backup_index = self.index; 385 | 386 | let c = self.eat_type(&TokenType::Operator)?; 387 | 388 | let mut result = None; 389 | 390 | if self::Operator::is_compoundable(&c) { 391 | let op = self::Operator::from_str(&c).unwrap().0; 392 | 393 | let position = self.current_position(); 394 | 395 | if self.current_lexeme() == "=" { 396 | self.next()?; 397 | 398 | let right = self.parse_expression()?; 399 | let ass = Statement::new( 400 | StatementNode::Assignment( 401 | left.clone(), 402 | Expression::new( 403 | ExpressionNode::Binary(Rc::new(left.clone()), op, Rc::new(right)), 404 | self.span_from(position.clone()), 405 | ), 406 | ), 407 | self.span_from(position), 408 | ); 409 | 410 | result = Some(ass) 411 | } else { 412 | self.index = backup_index 413 | } 414 | } 415 | 416 | Ok(result) 417 | } 418 | 419 | fn parse_right_hand(&mut self, name: String) -> Result, ()> { 420 | let declaration = match self.current_lexeme().as_str() { 421 | "extern" => { 422 | let position = self.current_position(); 423 | self.next()?; 424 | 425 | if self.current_lexeme() == "module" { 426 | if self.current_lexeme() == "extern" { 427 | return Err(response!( 428 | Wrong("expected literally any other expression"), 429 | self.source.file, 430 | self.current_position() 431 | )); 432 | } 433 | 434 | let expr = self.parse_right_hand(name)?; 435 | 436 | if let Some(expr) = expr { 437 | Some( 438 | Expression::new(ExpressionNode::ExternExpression(Rc::new(expr)), self.span_from(position)) 439 | ) 440 | } else { 441 | return Err(response!( 442 | Wrong("expected right-hand expression in extern"), 443 | self.source.file, 444 | self.current_position() 445 | )); 446 | } 447 | } else { 448 | let kind = self.parse_type()?; 449 | 450 | let lua = if self.current_lexeme() == "=" { 451 | self.next()?; 452 | 453 | Some(self.eat_type(&TokenType::Str)?) 454 | } else { 455 | None 456 | }; 457 | 458 | Some(Expression::new( 459 | ExpressionNode::Extern(kind, lua), 460 | self.span_from(position), 461 | )) 462 | } 463 | }, 464 | 465 | "fun" => Some(self.parse_function()?), 466 | 467 | "struct" => { 468 | let mut position = self.current_position(); 469 | 470 | self.next()?; 471 | self.next_newline()?; 472 | 473 | position = self.span_from(position); 474 | 475 | self.expect_lexeme("{")?; 476 | 477 | let params = self.parse_block_of(("{", "}"), &Self::_parse_struct_param_comma)?; 478 | 479 | Some(Expression::new( 480 | ExpressionNode::Struct( 481 | name, 482 | params, 483 | format!("{}{}", self.source.file, position), 484 | ), 485 | position, 486 | )) 487 | }, 488 | 489 | "trait" => { 490 | let position = self.current_position(); 491 | 492 | self.next()?; 493 | 494 | let body = self.parse_block_of(("{", "}"), &Self::_parse_param_comma)?; 495 | 496 | Some(Expression::new(ExpressionNode::Trait(name, body), position)) 497 | }, 498 | 499 | "module" => { 500 | let position = self.current_position(); 501 | 502 | self.next()?; 503 | self.next_newline()?; 504 | 505 | self.next_newline()?; 506 | 507 | self.expect_lexeme("{")?; 508 | 509 | Some(Expression::new( 510 | ExpressionNode::Module(Rc::new(self.parse_expression()?)), 511 | position, 512 | )) 513 | }, 514 | 515 | _ => None, 516 | }; 517 | 518 | Ok(declaration) 519 | } 520 | 521 | fn parse_function(&mut self) -> Result { 522 | let mut position = self.current_position(); 523 | 524 | self.next()?; 525 | self.next_newline()?; 526 | 527 | let mut params = if self.current_lexeme() == "(" { 528 | self.parse_block_of(("(", ")"), &Self::_parse_param_comma)? 529 | } else { 530 | Vec::new() 531 | }; 532 | 533 | let mut is_method = false; 534 | 535 | if params.len() > 0 { 536 | if params[0].1.node.strong_cmp(&TypeNode::This) { 537 | params.remove(0); 538 | 539 | is_method = true 540 | } 541 | } 542 | 543 | let retty = if self.current_lexeme() == "->" { 544 | self.next()?; 545 | 546 | self.parse_type()? 547 | } else { 548 | Type::from(TypeNode::Nil) 549 | }; 550 | 551 | position = self.span_from(position); 552 | 553 | self.next_newline()?; 554 | 555 | self.expect_lexeme("{")?; 556 | 557 | Ok(Expression::new( 558 | ExpressionNode::Function(params, retty, Rc::new(self.parse_expression()?), is_method), 559 | position, 560 | )) 561 | } 562 | 563 | fn parse_expression(&mut self) -> Result { 564 | let atom = self.parse_atom()?; 565 | 566 | if self.current_type() == TokenType::Operator { 567 | self.parse_binary(atom, 0) 568 | } else { 569 | Ok(atom) 570 | } 571 | } 572 | 573 | fn parse_atom(&mut self) -> Result { 574 | use self::TokenType::*; 575 | 576 | if self.remaining() == 0 { 577 | Ok(Expression::new( 578 | ExpressionNode::EOF, 579 | self.current_position(), 580 | )) 581 | } else { 582 | let token_type = self.current_type().clone(); 583 | let position = self.current_position(); 584 | 585 | let expression = match token_type { 586 | Int => Expression::new( 587 | ExpressionNode::Int(self.eat()?.parse::().unwrap()), 588 | position, 589 | ), 590 | 591 | Float => Expression::new( 592 | ExpressionNode::Float(self.eat()?.parse::().unwrap()), 593 | position, 594 | ), 595 | 596 | Char => Expression::new( 597 | ExpressionNode::Char(self.eat()?.chars().last().unwrap()), 598 | position, 599 | ), 600 | 601 | Str => Expression::new(ExpressionNode::Str(self.eat()?), position), 602 | 603 | Identifier => Expression::new(ExpressionNode::Identifier(self.eat()?), position), 604 | 605 | Bool => Expression::new(ExpressionNode::Bool(self.eat()? == "true"), position), 606 | 607 | Operator => match self.current_lexeme().as_str() { 608 | "*" => { 609 | self.next()?; 610 | 611 | Expression::new( 612 | ExpressionNode::UnwrapSplat(Rc::new(self.parse_expression()?)), 613 | self.span_from(position), 614 | ) 615 | } 616 | 617 | "-" => { 618 | self.next()?; 619 | 620 | Expression::new( 621 | ExpressionNode::Neg(Rc::new(self.parse_expression()?)), 622 | self.span_from(position), 623 | ) 624 | } 625 | 626 | "not" => { 627 | self.next()?; 628 | 629 | Expression::new( 630 | ExpressionNode::Not(Rc::new(self.parse_expression()?)), 631 | self.span_from(position), 632 | ) 633 | } 634 | 635 | ref symbol => { 636 | return Err(response!( 637 | Wrong(format!("unexpected operator `{}`", symbol)), 638 | self.source.file, 639 | self.current_position() 640 | )) 641 | } 642 | }, 643 | 644 | Symbol => match self.current_lexeme().as_str() { 645 | "{" => Expression::new( 646 | ExpressionNode::Block( 647 | self.parse_block_of(("{", "}"), &Self::_parse_statement)?, 648 | ), 649 | position, 650 | ), 651 | 652 | "[" => { 653 | self.enter_sequence(); 654 | 655 | let expr = Expression::new( 656 | ExpressionNode::Array( 657 | self.parse_block_of(("[", "]"), &Self::_parse_expression_comma)?, 658 | ), 659 | self.span_from(position), 660 | ); 661 | 662 | self.exit_sequence(); 663 | 664 | expr 665 | } 666 | 667 | "(" => { 668 | let backup_index = self.index; 669 | 670 | self.enter_sequence(); 671 | 672 | let possible_content = self.parse_block_of(("(", ")"), &Self::_parse_expression_comma)?; 673 | 674 | self.exit_sequence(); 675 | 676 | if possible_content.len() > 1 { 677 | self.enter_sequence(); 678 | 679 | let expr = Expression::new( 680 | ExpressionNode::Tuple( 681 | possible_content 682 | ), 683 | self.span_from(position), 684 | ); 685 | 686 | self.exit_sequence(); 687 | 688 | expr 689 | } else { 690 | self.index = backup_index; 691 | 692 | self.next()?; 693 | self.next_newline()?; 694 | 695 | if self.current_lexeme() == ")" && self.current_type() == TokenType::Symbol 696 | { 697 | self.next()?; 698 | 699 | Expression::new(ExpressionNode::Empty, self.span_from(position)) 700 | } else { 701 | let expression = self.parse_expression()?; 702 | 703 | self.eat_lexeme(")")?; 704 | 705 | expression 706 | } 707 | } 708 | } 709 | 710 | ref symbol => { 711 | return Err(response!( 712 | Wrong(format!("unexpected symbol `{}`", symbol)), 713 | self.source.file, 714 | self.current_position() 715 | )) 716 | } 717 | }, 718 | 719 | Keyword => { 720 | match self.current_lexeme().as_str() { 721 | "fun" => self.parse_function()?, 722 | "nil" => { 723 | let a = Expression::new(ExpressionNode::Empty, self.current_position()); 724 | 725 | self.next()?; 726 | 727 | a 728 | } 729 | 730 | "switch" => { 731 | self.next()?; 732 | 733 | let right_hand = self.parse_expression()?; 734 | let position = right_hand.pos.clone(); 735 | 736 | let mut block_scope = Vec::new(); // switch is actually a block with a declaration + if statement :)) #funfacts 737 | 738 | let name = format!("__switch_tmp_{}", self.remaining()); 739 | 740 | let decl = Statement::new( 741 | StatementNode::Variable( 742 | Type::from(TypeNode::Nil), 743 | name.clone(), 744 | Some(right_hand), 745 | false 746 | ), 747 | position.clone(), 748 | ); 749 | 750 | let right_template = 751 | Expression::new(ExpressionNode::Identifier(name), position.clone()); 752 | 753 | self.next_newline()?; 754 | 755 | self.eat_lexeme("{")?; 756 | 757 | self.next_newline()?; 758 | 759 | let mut branches = Vec::new(); 760 | 761 | loop { 762 | let mut branch_position = self.current_position(); 763 | 764 | let left = self.parse_expression()?; 765 | 766 | let condition = Expression::new( 767 | ExpressionNode::Binary( 768 | Rc::new(left), 769 | super::Operator::Eq, 770 | Rc::new(right_template.clone()), 771 | ), 772 | branch_position.clone(), 773 | ); 774 | 775 | self.eat_lexeme("=>")?; 776 | 777 | self.next_newline()?; 778 | 779 | branch_position = self.span_from(branch_position); 780 | 781 | let body = self.parse_expression()?; 782 | 783 | branches.push((Some(condition), body, branch_position)); 784 | 785 | self.next_newline()?; 786 | 787 | if self.current_lexeme() == "}" || self.remaining() == 0 { 788 | break; 789 | } 790 | } 791 | 792 | self.eat_lexeme("}")?; 793 | 794 | let primary = branches.remove(0); 795 | 796 | let if_pattern = Expression::new( 797 | ExpressionNode::If( 798 | Rc::new(primary.0.unwrap()), 799 | Rc::new(primary.1), 800 | Some(branches), 801 | ), 802 | primary.2.clone(), 803 | ); 804 | 805 | let if_pattern_stmt = 806 | Statement::new(StatementNode::Expression(if_pattern), primary.2); 807 | 808 | block_scope.push(decl); 809 | block_scope.push(if_pattern_stmt); 810 | 811 | Expression::new(ExpressionNode::Block(block_scope), position) 812 | } 813 | 814 | "for" => { 815 | self.next()?; 816 | self.next_newline()?; 817 | 818 | let expr = Rc::new(self.parse_expression()?); 819 | let mut iterator = None; 820 | 821 | self.next_newline()?; 822 | 823 | if self.current_lexeme() == "in" { 824 | self.next()?; 825 | self.next_newline()?; 826 | 827 | iterator = Some(Rc::new(self.parse_expression()?)) 828 | } 829 | 830 | let for_position = self.span_from(position.clone()); 831 | 832 | let body = Rc::new(Expression::new( 833 | ExpressionNode::Block( 834 | self.parse_block_of(("{", "}"), &Self::_parse_statement)?, 835 | ), 836 | position, 837 | )); 838 | 839 | Expression::new( 840 | ExpressionNode::For((expr, iterator), body), 841 | for_position, 842 | ) 843 | } 844 | 845 | "if" => { 846 | self.next()?; 847 | self.next_newline()?; 848 | 849 | let condition = Rc::new(self.parse_expression()?); 850 | let if_position = self.span_from(position.clone()); 851 | 852 | let body = Rc::new(Expression::new( 853 | ExpressionNode::Block( 854 | self.parse_block_of(("{", "}"), &Self::_parse_statement)?, 855 | ), 856 | position, 857 | )); 858 | 859 | let mut elses = Vec::new(); 860 | 861 | loop { 862 | let branch_position = self.current_position(); 863 | 864 | match self.current_lexeme().as_str() { 865 | "elif" => { 866 | self.next()?; 867 | 868 | let condition = self.parse_expression()?; 869 | let position = self.current_position(); 870 | let body = Expression::new( 871 | ExpressionNode::Block(self.parse_block_of( 872 | ("{", "}"), 873 | &Self::_parse_statement, 874 | )?), 875 | position, 876 | ); 877 | 878 | elses.push((Some(condition), body, branch_position)) 879 | } 880 | 881 | "else" => { 882 | self.next()?; 883 | 884 | let position = self.current_position(); 885 | let body = Expression::new( 886 | ExpressionNode::Block(self.parse_block_of( 887 | ("{", "}"), 888 | &Self::_parse_statement, 889 | )?), 890 | position, 891 | ); 892 | 893 | elses.push((None, body, branch_position)) 894 | } 895 | 896 | _ => break, 897 | } 898 | } 899 | 900 | Expression::new( 901 | ExpressionNode::If( 902 | condition, 903 | body, 904 | if elses.len() > 0 { Some(elses) } else { None }, 905 | ), 906 | if_position, 907 | ) 908 | } 909 | 910 | "while" => { 911 | self.next()?; 912 | 913 | self.next_newline()?; 914 | 915 | let condition = self.parse_expression()?; 916 | 917 | self.next_newline()?; 918 | 919 | self.expect_lexeme("{")?; 920 | 921 | let position = self.span_from(position); 922 | 923 | Expression::new( 924 | ExpressionNode::While( 925 | Rc::new(condition), 926 | Rc::new(self.parse_expression()?), 927 | ), 928 | position, 929 | ) 930 | } 931 | 932 | "new" => { 933 | self.next()?; 934 | self.next_newline()?; 935 | 936 | let expression = self.parse_expression()?; 937 | 938 | let position = self.span_from(position); 939 | 940 | self.next_newline()?; 941 | 942 | let args = 943 | self.parse_block_of(("{", "}"), &Self::_parse_definition_comma)?; 944 | 945 | Expression::new( 946 | ExpressionNode::Initialization(Rc::new(expression), args), 947 | position, 948 | ) 949 | } 950 | 951 | ref symbol => { 952 | return Err(response!( 953 | Wrong(format!("unexpected keyword `{}`", symbol)), 954 | self.source.file, 955 | self.current_position() 956 | )) 957 | } 958 | } 959 | } 960 | 961 | ref token_type => { 962 | return Err(response!( 963 | Wrong(format!("unexpected token `{}`", token_type)), 964 | self.source.file, 965 | self.current_position() 966 | )) 967 | } 968 | }; 969 | 970 | if self.remaining() > 0 { 971 | self.parse_postfix(expression) 972 | } else { 973 | Ok(expression) 974 | } 975 | } 976 | } 977 | 978 | fn parse_postfix(&mut self, expression: Expression) -> Result { 979 | if self.remaining() == 0 { 980 | return Ok(expression); 981 | } 982 | 983 | match self.current_type() { 984 | TokenType::Symbol => match self.current_lexeme().as_str() { 985 | "(" => { 986 | self.enter_sequence(); 987 | 988 | let args = self.parse_block_of(("(", ")"), &Self::_parse_expression_comma)?; 989 | 990 | let position = expression.pos.clone(); 991 | 992 | let call = Expression::new( 993 | ExpressionNode::Call(Rc::new(expression), args), 994 | self.span_from(position), 995 | ); 996 | 997 | self.exit_sequence(); 998 | 999 | self.parse_postfix(call) 1000 | } 1001 | 1002 | "[" => { 1003 | self.enter_sequence(); 1004 | 1005 | self.next()?; 1006 | 1007 | let expr = self.parse_expression()?; 1008 | 1009 | self.eat_lexeme("]")?; 1010 | 1011 | let position = expression.pos.clone(); 1012 | 1013 | let index = Expression::new( 1014 | ExpressionNode::Index(Rc::new(expression), Rc::new(expr), true), 1015 | self.span_from(position), 1016 | ); 1017 | 1018 | self.exit_sequence(); 1019 | 1020 | self.parse_postfix(index) 1021 | } 1022 | 1023 | "," => { 1024 | if !self.in_sequence { 1025 | let position = expression.pos.clone(); 1026 | let mut splats = vec![expression]; 1027 | 1028 | self.enter_sequence(); 1029 | 1030 | while self.current_lexeme() == "," { 1031 | self.next()?; 1032 | 1033 | let expr = self.parse_expression()?; 1034 | splats.push(expr) 1035 | } 1036 | 1037 | self.exit_sequence(); 1038 | 1039 | Ok(Expression::new( 1040 | ExpressionNode::Splat(splats), 1041 | self.span_from(position), 1042 | )) 1043 | } else { 1044 | Ok(expression) 1045 | } 1046 | } 1047 | 1048 | "!" => { 1049 | self.next()?; 1050 | 1051 | let position = expression.pos.clone(); 1052 | 1053 | let question = Expression::new( 1054 | ExpressionNode::Unwrap(Rc::new(expression)), 1055 | self.span_from(position), 1056 | ); 1057 | 1058 | self.parse_postfix(question) 1059 | } 1060 | 1061 | _ => Ok(expression), 1062 | }, 1063 | 1064 | TokenType::Keyword => match self.current_lexeme().as_str() { 1065 | "as" => { 1066 | self.next()?; 1067 | 1068 | let t = self.parse_type()?; 1069 | let position = expression.pos.clone(); 1070 | 1071 | self.parse_postfix(Expression::new( 1072 | ExpressionNode::Cast(Rc::new(expression), t), 1073 | position, 1074 | )) 1075 | } 1076 | 1077 | _ => Ok(expression), 1078 | }, 1079 | 1080 | TokenType::Identifier => { 1081 | let position = self.current_position(); 1082 | 1083 | let id = Expression::new(ExpressionNode::Identifier(self.eat()?), position); 1084 | 1085 | let position = expression.pos.clone(); 1086 | 1087 | let index = Expression::new( 1088 | ExpressionNode::Index(Rc::new(expression), Rc::new(id), false), 1089 | self.span_from(position), 1090 | ); 1091 | 1092 | self.parse_postfix(index) 1093 | } 1094 | 1095 | _ => Ok(expression), 1096 | } 1097 | } 1098 | 1099 | fn parse_binary(&mut self, left: Expression, min_prec: usize) -> Result { 1100 | let mut left = left; 1101 | let left_position = left.pos.clone(); 1102 | 1103 | while self.current_type() == TokenType::Operator { 1104 | let index_backup = self.index; 1105 | let operator = Operator::from_str(self.eat()?.as_str()).unwrap(); 1106 | 1107 | if operator.1 < min_prec as u8 { 1108 | self.index = index_backup; 1109 | break; 1110 | } 1111 | 1112 | let prec = if !operator.0.is_right_ass() { 1113 | operator.1 + 1 1114 | } else { 1115 | operator.1 1116 | }; 1117 | 1118 | let mut right = self.parse_atom()?; 1119 | right = self.parse_binary(right, prec as usize)?; 1120 | 1121 | left = Expression::new( 1122 | ExpressionNode::Binary(Rc::new(left), operator.0, Rc::new(right.clone())), 1123 | self.span_from(left_position.clone()), 1124 | ); 1125 | } 1126 | 1127 | Ok(left) 1128 | } 1129 | 1130 | fn parse_type(&mut self) -> Result { 1131 | use self::TokenType::*; 1132 | 1133 | let mut t = match self.current_type() { 1134 | Identifier => match self.eat()?.as_str() { 1135 | "str" => Type::from(TypeNode::Str), 1136 | "char" => Type::from(TypeNode::Char), 1137 | "int" => Type::from(TypeNode::Int), 1138 | "float" => Type::from(TypeNode::Float), 1139 | "any" => Type::from(TypeNode::Any), 1140 | "bool" => Type::from(TypeNode::Bool), 1141 | "self" => Type::from(TypeNode::This), 1142 | 1143 | _ => { 1144 | self.index -= 1; // lol 1145 | self.enter_sequence(); 1146 | 1147 | let a = Type::id(Rc::new(self.parse_expression()?)); 1148 | 1149 | self.exit_sequence(); 1150 | 1151 | a 1152 | } 1153 | }, 1154 | 1155 | Keyword => match self.current_lexeme().as_str() { 1156 | "nil" => { 1157 | self.next()?; 1158 | Type::from(TypeNode::Nil) 1159 | } 1160 | "fun" => { 1161 | self.next()?; 1162 | 1163 | let mut params = if self.current_lexeme() == "(" { 1164 | self.parse_block_of(("(", ")"), &Self::_parse_type_comma)? 1165 | } else { 1166 | Vec::new() 1167 | }; 1168 | 1169 | let mut is_method = false; 1170 | 1171 | if params.len() > 0 { 1172 | if params[0].node.strong_cmp(&TypeNode::This) { 1173 | params.remove(0); 1174 | 1175 | is_method = true 1176 | } 1177 | } 1178 | 1179 | let return_type = if self.current_lexeme() == "->" { 1180 | self.next()?; 1181 | 1182 | self.parse_type()? 1183 | } else { 1184 | Type::from(TypeNode::Nil) 1185 | }; 1186 | 1187 | Type::from(TypeNode::Func( 1188 | params, 1189 | Rc::new(return_type), 1190 | None, 1191 | is_method, 1192 | )) 1193 | } 1194 | 1195 | _ => { 1196 | return Err(response!( 1197 | Wrong(format!( 1198 | "unexpected keyword `{}` in type", 1199 | self.current_lexeme() 1200 | )), 1201 | self.source.file, 1202 | self.current_position() 1203 | )) 1204 | } 1205 | }, 1206 | 1207 | Symbol => match self.current_lexeme().as_str() { 1208 | "(" => { 1209 | self.next()?; 1210 | self.next_newline()?; 1211 | 1212 | let mut content = Vec::new(); 1213 | 1214 | content.push( 1215 | self.parse_type()? 1216 | ); 1217 | 1218 | self.next_newline()?; 1219 | 1220 | while self.current_lexeme() == "," { 1221 | self.eat()?; 1222 | 1223 | content.push(self.parse_type()?); 1224 | 1225 | self.next_newline()?; 1226 | } 1227 | 1228 | self.eat_lexeme(")")?; 1229 | 1230 | Type::tuple(content) 1231 | }, 1232 | 1233 | "[" => { 1234 | self.next()?; 1235 | self.next_newline()?; 1236 | 1237 | let t = self.parse_type()?; 1238 | 1239 | self.next_newline()?; 1240 | 1241 | let mut len = None; 1242 | 1243 | if self.current_lexeme() == ";" { 1244 | self.eat_lexeme(";")?; 1245 | 1246 | self.next_newline()?; 1247 | 1248 | let expression = self.parse_expression()?; 1249 | 1250 | len = if let ExpressionNode::Int(ref len) = 1251 | Self::fold_expression(&expression).node 1252 | { 1253 | Some(*len as usize) 1254 | } else { 1255 | return Err(response!( 1256 | Wrong(format!("length of array can be nothing but int")), 1257 | self.source.file, 1258 | expression.pos 1259 | )); 1260 | }; 1261 | } 1262 | 1263 | self.eat_lexeme("]")?; 1264 | 1265 | Type::array(t, len) 1266 | } 1267 | 1268 | "..." => { 1269 | self.next()?; 1270 | 1271 | let splatted = if ([")", "=", "?", "{"] 1272 | .contains(&self.current_lexeme().as_str()) 1273 | && self.current_type() == TokenType::Symbol) 1274 | || self.remaining() == 0 1275 | || self.current_lexeme() == "\n" 1276 | { 1277 | Type::from(TypeNode::Any) 1278 | } else { 1279 | self.parse_type()? 1280 | }; 1281 | 1282 | let result = Type::new(splatted.node, TypeMode::Splat(None)); 1283 | 1284 | if self.remaining() == 0 { 1285 | return Ok(result); 1286 | } else { 1287 | result 1288 | } 1289 | } 1290 | 1291 | _ => { 1292 | return Err(response!( 1293 | Wrong(format!( 1294 | "unexpected symbol `{}` in type", 1295 | self.current_lexeme() 1296 | )), 1297 | self.source.file, 1298 | self.current_position() 1299 | )) 1300 | } 1301 | }, 1302 | 1303 | _ => { 1304 | return Err(response!( 1305 | Wrong(format!("expected type found `{}`", self.current_lexeme())), 1306 | self.source.file, 1307 | self.current_position() 1308 | )) 1309 | } 1310 | }; 1311 | 1312 | if self.current_lexeme() == "?" { 1313 | self.next()?; 1314 | 1315 | let inner = t.node.clone(); 1316 | 1317 | t.node = TypeNode::Optional(Rc::new(inner)); 1318 | } 1319 | 1320 | Ok(t) 1321 | } 1322 | 1323 | fn new_line(&mut self) -> Result<(), ()> { 1324 | if self.remaining() > 0 { 1325 | match self.current_lexeme().as_str() { 1326 | "\n" => self.next(), 1327 | _ => Err(response!( 1328 | 1329 | Wrong(format!( 1330 | "expected new line found: `{}`", 1331 | self.current_lexeme() 1332 | )), 1333 | self.source.file, 1334 | self.current_position() 1335 | )), 1336 | } 1337 | } else { 1338 | Ok(()) 1339 | } 1340 | } 1341 | 1342 | fn next_newline(&mut self) -> Result<(), ()> { 1343 | while self.current_lexeme() == "\n" && self.remaining() > 0 { 1344 | self.next()? 1345 | } 1346 | 1347 | Ok(()) 1348 | } 1349 | 1350 | fn next(&mut self) -> Result<(), ()> { 1351 | if self.index <= self.tokens.len() { 1352 | self.index += 1; 1353 | Ok(()) 1354 | } else { 1355 | Err(response!( 1356 | Wrong("moving outside token stack"), 1357 | self.source.file, 1358 | self.current_position() 1359 | )) 1360 | } 1361 | } 1362 | 1363 | fn remaining(&self) -> usize { 1364 | self.tokens.len().saturating_sub(self.index) 1365 | } 1366 | 1367 | fn current_position(&self) -> Pos { 1368 | let current = self.current(); 1369 | 1370 | Pos(current.line.clone(), current.slice) 1371 | } 1372 | 1373 | fn span_from(&self, left_position: Pos) -> Pos { 1374 | let Pos(ref line, ref slice) = left_position; 1375 | let Pos(_, ref slice2) = self.current_position(); 1376 | 1377 | Pos( 1378 | line.clone(), 1379 | ( 1380 | slice.0, 1381 | if slice2.1 < line.1.len() { 1382 | slice2.1 1383 | } else { 1384 | line.1.len() 1385 | }, 1386 | ), 1387 | ) 1388 | } 1389 | 1390 | fn current(&self) -> Token { 1391 | if self.index > self.tokens.len() - 1 { 1392 | self.tokens[self.tokens.len() - 1].clone() 1393 | } else { 1394 | self.tokens[self.index].clone() 1395 | } 1396 | } 1397 | 1398 | fn eat(&mut self) -> Result { 1399 | let lexeme = self.current().lexeme; 1400 | self.next()?; 1401 | 1402 | Ok(lexeme) 1403 | } 1404 | 1405 | fn eat_lexeme(&mut self, lexeme: &str) -> Result { 1406 | if self.current_lexeme() == lexeme { 1407 | let lexeme = self.current().lexeme; 1408 | self.next()?; 1409 | 1410 | Ok(lexeme) 1411 | } else { 1412 | Err(response!( 1413 | Wrong(format!( 1414 | "expected `{}`, found `{}`", 1415 | lexeme, 1416 | self.current_lexeme() 1417 | )), 1418 | self.source.file, 1419 | self.current_position() 1420 | )) 1421 | } 1422 | } 1423 | 1424 | fn eat_type(&mut self, token_type: &TokenType) -> Result { 1425 | if self.current_type() == *token_type { 1426 | let lexeme = self.current().lexeme.clone(); 1427 | self.next()?; 1428 | 1429 | Ok(lexeme) 1430 | } else { 1431 | Err(response!( 1432 | Wrong(format!( 1433 | "expected `{}`, found `{}`", 1434 | token_type, 1435 | self.current_type() 1436 | )), 1437 | self.source.file, 1438 | self.current_position() 1439 | )) 1440 | } 1441 | } 1442 | 1443 | fn current_lexeme(&self) -> String { 1444 | self.current().lexeme.clone() 1445 | } 1446 | 1447 | fn current_type(&self) -> TokenType { 1448 | self.current().token_type 1449 | } 1450 | 1451 | fn expect_type(&self, token_type: TokenType) -> Result<(), ()> { 1452 | if self.current_type() == token_type { 1453 | Ok(()) 1454 | } else { 1455 | Err(response!( 1456 | Wrong(format!( 1457 | "expected `{}`, found `{}`", 1458 | token_type, 1459 | self.current_type() 1460 | )), 1461 | self.source.file, 1462 | self.current_position() 1463 | )) 1464 | } 1465 | } 1466 | 1467 | fn expect_lexeme(&self, lexeme: &str) -> Result<(), ()> { 1468 | if self.current_lexeme() == lexeme { 1469 | Ok(()) 1470 | } else { 1471 | Err(response!( 1472 | Wrong(format!( 1473 | "expected `{}`, found `{}`", 1474 | lexeme, 1475 | self.current_lexeme() 1476 | )), 1477 | self.source.file, 1478 | self.current_position() 1479 | )) 1480 | } 1481 | } 1482 | 1483 | // A helper method for parsing sequences defined by provided static methods, 1484 | // for as long as given static method returns Some(B) 1485 | fn parse_block_of( 1486 | &mut self, 1487 | delimeters: (&str, &str), 1488 | parse_with: &dyn Fn(&mut Self) -> Result, ()>, 1489 | ) -> Result, ()> { 1490 | self.enter_sequence(); 1491 | self.eat_lexeme(delimeters.0)?; 1492 | 1493 | if self.current_lexeme() == delimeters.1 { 1494 | self.next()?; 1495 | 1496 | return Ok(Vec::new()); 1497 | } 1498 | 1499 | let mut block_tokens = Vec::new(); 1500 | let mut nest_count = 1; 1501 | 1502 | while nest_count > 0 { 1503 | if self.current_lexeme() == delimeters.1 && self.current_type() == TokenType::Symbol { 1504 | nest_count -= 1 1505 | } else if self.current_lexeme() == delimeters.0 1506 | && self.current_type() == TokenType::Symbol 1507 | { 1508 | nest_count += 1 1509 | } 1510 | 1511 | if nest_count == 0 { 1512 | break; 1513 | } else { 1514 | block_tokens.push(self.current()); 1515 | 1516 | self.next()?; 1517 | } 1518 | } 1519 | 1520 | self.eat_lexeme(delimeters.1)?; 1521 | 1522 | 1523 | if !block_tokens.is_empty() { 1524 | let mut parser = Parser::new(block_tokens, self.source); 1525 | parser.in_sequence = self.in_sequence; 1526 | let mut block = Vec::new(); 1527 | 1528 | while let Some(element) = parse_with(&mut parser)? { 1529 | block.push(element) 1530 | } 1531 | 1532 | self.exit_sequence(); 1533 | 1534 | Ok(block) 1535 | } else { 1536 | self.exit_sequence(); 1537 | 1538 | Ok(Vec::new()) 1539 | } 1540 | } 1541 | 1542 | fn _parse_statement(self: &mut Self) -> Result, ()> { 1543 | if self.remaining() > 0 { 1544 | Ok(Some(self.parse_statement()?)) 1545 | } else { 1546 | Ok(None) 1547 | } 1548 | } 1549 | 1550 | fn _parse_expression(self: &mut Self) -> Result, ()> { 1551 | let expression = self.parse_expression()?; 1552 | 1553 | match expression.node { 1554 | ExpressionNode::EOF => Ok(None), 1555 | _ => Ok(Some(expression)), 1556 | } 1557 | } 1558 | 1559 | fn _parse_name_comma(self: &mut Self) -> Result, ()> { 1560 | if self.remaining() == 0 { 1561 | Ok(None) 1562 | } else { 1563 | if self.remaining() > 0 && self.current_lexeme() == "\n" { 1564 | self.next()? 1565 | } 1566 | 1567 | let t = self.eat_type(&TokenType::Identifier)?; 1568 | 1569 | if self.remaining() > 0 { 1570 | if ![",", "\n"].contains(&self.current_lexeme().as_str()) { 1571 | return Err(response!( 1572 | Wrong(format!( 1573 | "expected `,` or newline, found `{}`", 1574 | self.current_lexeme() 1575 | )), 1576 | self.source.file, 1577 | self.current_position() 1578 | )); 1579 | } else { 1580 | self.next()?; 1581 | } 1582 | 1583 | if self.remaining() > 0 && self.current_lexeme() == "\n" { 1584 | self.next()? 1585 | } 1586 | } 1587 | 1588 | Ok(Some(t)) 1589 | } 1590 | } 1591 | 1592 | // Static method for parsing sequence `expr* ,* \n*` - for things like [1, 2, 3, 4,] 1593 | fn _parse_expression_comma(self: &mut Self) -> Result, ()> { 1594 | if self.remaining() > 0 && self.current_lexeme() == "\n" { 1595 | self.next()?; 1596 | self.next_newline()? 1597 | } 1598 | 1599 | let expression = Self::_parse_expression(self); 1600 | 1601 | if self.remaining() > 0 && self.current_lexeme() == "\n" { 1602 | self.next()?; 1603 | self.next_newline()? 1604 | } 1605 | 1606 | if self.remaining() > 0 { 1607 | self.eat_lexeme(",")?; 1608 | 1609 | if self.remaining() > 0 && self.current_lexeme() == "\n" { 1610 | self.next()?; 1611 | self.next_newline()? 1612 | } 1613 | } 1614 | 1615 | expression 1616 | } 1617 | 1618 | fn _parse_param_comma(self: &mut Self) -> Result, ()> { 1619 | if self.remaining() > 0 && self.current_lexeme() == "\n" { 1620 | self.next()? 1621 | } 1622 | 1623 | if self.remaining() == 0 { 1624 | return Ok(None); 1625 | } 1626 | 1627 | let mut splat = false; 1628 | let mut optional = false; 1629 | let position = self.current_position(); 1630 | 1631 | if self.current_lexeme() == "..." { 1632 | splat = true; 1633 | 1634 | self.next()?; 1635 | self.next_newline()?; 1636 | } 1637 | 1638 | if self.current_lexeme() == "?" { 1639 | optional = false; 1640 | 1641 | self.next()?; 1642 | self.next_newline()?; 1643 | } 1644 | 1645 | self.next_newline()?; 1646 | 1647 | let name = self.eat_type(&TokenType::Identifier)?; 1648 | 1649 | let mut kind = if name == "self" { 1650 | if splat { 1651 | return Err(response!( 1652 | Wrong("can't splat `self`"), 1653 | self.source.file, 1654 | position 1655 | )); 1656 | } 1657 | 1658 | Type::new(TypeNode::This, TypeMode::Regular) 1659 | } else { 1660 | let mut kind = Type::from(TypeNode::Any); 1661 | 1662 | if self.current_lexeme() == ":" { 1663 | self.eat_lexeme(":")?; 1664 | 1665 | kind = self.parse_type()?; 1666 | 1667 | if splat { 1668 | kind.mode = TypeMode::Splat(None) 1669 | } 1670 | } 1671 | 1672 | kind 1673 | }; 1674 | 1675 | if optional { 1676 | let inner = kind.node.clone(); 1677 | 1678 | kind.node = TypeNode::Optional(Rc::new(inner)); 1679 | } 1680 | 1681 | let param = Some((name, kind)); 1682 | 1683 | self.next_newline()?; 1684 | 1685 | if self.remaining() > 0 { 1686 | if ![",", "\n"].contains(&self.current_lexeme().as_str()) { 1687 | return Err(response!( 1688 | Wrong(format!( 1689 | "expected `,` or newline, found `{}`", 1690 | self.current_lexeme() 1691 | )), 1692 | self.source.file, 1693 | self.current_position() 1694 | )); 1695 | } else { 1696 | self.next()?; 1697 | } 1698 | 1699 | if self.remaining() > 0 && self.current_lexeme() == "\n" { 1700 | self.next()? 1701 | } 1702 | } 1703 | 1704 | Ok(param) 1705 | } 1706 | 1707 | fn _parse_definition_comma(self: &mut Self) -> Result, ()> { 1708 | if self.remaining() > 0 && self.current_lexeme() == "\n" { 1709 | self.next()? 1710 | } 1711 | 1712 | if self.remaining() == 0 { 1713 | return Ok(None); 1714 | } 1715 | 1716 | let position = self.current_position(); 1717 | 1718 | let name = self.eat_type(&TokenType::Identifier)?; 1719 | 1720 | self.eat_lexeme(":")?; 1721 | 1722 | let mut value = self.parse_expression()?; 1723 | 1724 | value.pos = position; 1725 | 1726 | let param = Some((name, value)); 1727 | 1728 | if self.remaining() > 0 { 1729 | if ![",", "\n"].contains(&self.current_lexeme().as_str()) { 1730 | return Err(response!( 1731 | Wrong(format!( 1732 | "expected `,` or newline, found `{}`", 1733 | self.current_lexeme() 1734 | )), 1735 | self.source.file, 1736 | self.current_position() 1737 | )); 1738 | } else { 1739 | self.next()?; 1740 | } 1741 | 1742 | if self.remaining() > 0 && self.current_lexeme() == "\n" { 1743 | self.next()? 1744 | } 1745 | } 1746 | 1747 | Ok(param) 1748 | } 1749 | 1750 | fn _parse_struct_param_comma(self: &mut Self) -> Result, ()> { 1751 | if self.remaining() > 0 && self.current_lexeme() == "\n" { 1752 | self.next()?; 1753 | self.next_newline()?; 1754 | } 1755 | 1756 | if self.remaining() == 0 { 1757 | return Ok(None); 1758 | } 1759 | 1760 | let name = self.eat_type(&TokenType::Identifier)?; 1761 | 1762 | self.eat_lexeme(":")?; 1763 | 1764 | let value = self.parse_type()?; 1765 | let param = Some((name, value)); 1766 | 1767 | if self.remaining() > 0 { 1768 | if ![",", "\n"].contains(&self.current_lexeme().as_str()) { 1769 | return Err(response!( 1770 | Wrong(format!( 1771 | "expected `,` or newline, found `{}`", 1772 | self.current_lexeme() 1773 | )), 1774 | self.source.file, 1775 | self.current_position() 1776 | )); 1777 | } else { 1778 | self.next()?; 1779 | } 1780 | 1781 | if self.remaining() > 0 && self.current_lexeme() == "\n" { 1782 | self.next()? 1783 | } 1784 | } 1785 | 1786 | Ok(param) 1787 | } 1788 | 1789 | fn _parse_type_comma(self: &mut Self) -> Result, ()> { 1790 | if self.remaining() == 0 { 1791 | Ok(None) 1792 | } else { 1793 | let t = self.parse_type()?; 1794 | 1795 | if self.remaining() > 0 { 1796 | self.eat_lexeme(",")?; 1797 | 1798 | if self.remaining() > 0 && self.current_lexeme() == "\n" { 1799 | self.next()? 1800 | } 1801 | } 1802 | 1803 | Ok(Some(t)) 1804 | } 1805 | } 1806 | 1807 | pub fn fold_expression(expression: &Expression) -> Expression { 1808 | use self::ExpressionNode::*; 1809 | use self::Operator::*; 1810 | 1811 | let node = match expression.node { 1812 | Binary(ref left, ref op, ref right) => { 1813 | let node = match ( 1814 | &Self::fold_expression(&*left).node, 1815 | op, 1816 | &Self::fold_expression(&*right).node, 1817 | ) { 1818 | (&Int(ref a), &Add, &Int(ref b)) => Int(a + b), 1819 | (&Float(ref a), &Add, &Float(ref b)) => Float(a + b), 1820 | (&Int(ref a), &Sub, &Int(ref b)) => Int(a - b), 1821 | (&Float(ref a), &Sub, &Float(ref b)) => Float(a - b), 1822 | (&Int(ref a), &Mul, &Int(ref b)) => Int(a * b), 1823 | (&Float(ref a), &Mul, &Float(ref b)) => Float(a * b), 1824 | (&Int(ref a), &Div, &Int(ref b)) => Int(a / b), 1825 | (&Float(ref a), &Div, &Float(ref b)) => Float(a / b), 1826 | 1827 | _ => expression.node.clone(), 1828 | }; 1829 | 1830 | Expression::new(node, expression.pos.clone()) 1831 | } 1832 | 1833 | _ => expression.clone(), 1834 | }; 1835 | 1836 | node 1837 | } 1838 | 1839 | fn enter_sequence(&mut self) { 1840 | self.tmp_sequence = self.in_sequence; 1841 | self.in_sequence = true; 1842 | } 1843 | 1844 | fn exit_sequence(&mut self) { 1845 | self.in_sequence = self.tmp_sequence; 1846 | } 1847 | } 1848 | --------------------------------------------------------------------------------