/
ast_explorer.rs
149 lines (138 loc) · 3.82 KB
/
ast_explorer.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#![allow(dead_code)]
use std::{fs, path::PathBuf};
use argh::FromArgs;
use enum_variants_strings::EnumVariantsStrings;
use parser::{ASTNode, Expression, Module, SourceId, ToStringSettings};
use crate::{error_handling::emit_parser_error, utilities::print_to_cli};
/// Repl for testing out AST
#[derive(FromArgs, Debug)]
#[argh(subcommand, name = "ast-explorer")]
pub(crate) struct ExplorerArguments {
#[argh(subcommand)]
nested: ExplorerSubCommand,
/// path to input file
#[argh(option)]
file: Option<PathBuf>,
}
impl ExplorerArguments {
pub(crate) fn run<T: crate::FSResolver, U: crate::CLIInputResolver>(
&mut self,
fs_resolver: T,
cli_input_resolver: U,
) {
if let Some(ref file) = self.file {
let file = fs_resolver(file).unwrap();
self.nested.run(file.0);
} else {
print_to_cli(format_args!("ezno ast-explorer\nUse #exit to leave. Also #switch-mode *mode name* and #load-file *path*"));
loop {
let mut input = cli_input_resolver(self.nested.to_str()).unwrap_or_default();
if input.len() == 0 {
continue;
} else if input.trim() == "#exit" {
break;
} else if let Some(new_mode) = input.strip_prefix("#switch-mode ") {
self.nested = match ExplorerSubCommand::from_str(new_mode.trim()) {
Ok(mode) => mode,
Err(expected) => {
print_to_cli(format_args!(
"Unexpected mode, options are {:?}",
expected
));
continue;
}
};
continue;
} else if let Some(path) = input.strip_prefix("#load-file ") {
input = match fs::read_to_string(path.trim()) {
Ok(string) => string,
Err(err) => {
print_to_cli(format_args!("{:?}", err));
continue;
}
};
};
self.nested.run(input);
}
}
}
}
#[derive(FromArgs, Debug, EnumVariantsStrings)]
#[argh(subcommand)]
#[enum_variants_strings_transform(transform = "kebab_case")]
pub(crate) enum ExplorerSubCommand {
AST(ASTArgs),
FullAST(FullASTArgs),
Prettifier(PrettyArgs),
Uglifier(UglifierArgs),
}
/// Prints AST for given expression
#[derive(FromArgs, Debug, Default)]
#[argh(subcommand, name = "ast")]
pub(crate) struct ASTArgs {}
/// Prints AST for given module
#[derive(FromArgs, Debug, Default)]
#[argh(subcommand, name = "full-ast")]
pub(crate) struct FullASTArgs {}
/// Prettifies source code (full whitespace)
#[derive(FromArgs, Debug, Default)]
#[argh(subcommand, name = "prettifier")]
pub(crate) struct PrettyArgs {}
/// Removes whitespace from input
#[derive(FromArgs, Debug, Default)]
#[argh(subcommand, name = "uglifier")]
pub(crate) struct UglifierArgs {}
impl ExplorerSubCommand {
pub fn run(&self, input: String) {
match self {
ExplorerSubCommand::AST(_) => {
let res = <Expression as parser::ASTNode>::from_string(
input.clone(),
Default::default(),
SourceId::NULL,
None,
Vec::new(),
);
match res {
Ok(res) => {
print_to_cli(format_args!("{:#?}", res));
}
Err(err) => emit_parser_error(input, err).unwrap(),
}
}
ExplorerSubCommand::FullAST(_) => {
let res = Module::from_string(
input.clone(),
Default::default(),
SourceId::NULL,
None,
Vec::new(),
);
match res {
Ok(res) => print_to_cli(format_args!("{:#?}", res)),
Err(err) => emit_parser_error(input, err).unwrap(),
}
}
ExplorerSubCommand::Prettifier(_) | ExplorerSubCommand::Uglifier(_) => {
let res = Module::from_string(
input.clone(),
Default::default(),
SourceId::NULL,
None,
Vec::new(),
);
match res {
Ok(module) => {
let settings = if matches!(self, ExplorerSubCommand::Prettifier(_)) {
ToStringSettings::default()
} else {
ToStringSettings::minified()
};
print_to_cli(format_args!("{}", module.to_string(&settings)));
}
Err(err) => emit_parser_error(input, err).unwrap(),
}
}
}
}
}