feat(language): new continue keyword
parent
252c23e889
commit
3f053015f6
File diff suppressed because it is too large
Load Diff
16
Cargo.toml
16
Cargo.toml
|
@ -7,11 +7,11 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
lazy_static = "1.4.0"
|
||||
pest = "2.0"
|
||||
pest_derive = "2.0"
|
||||
pest = "2.7.5"
|
||||
pest_derive = "2.7.5"
|
||||
# web
|
||||
egui = "0.20.0"
|
||||
eframe = { version = "0.20.0", default-features = false, features = [
|
||||
egui = "0.24.0"
|
||||
eframe = { version = "0.24.0", default-features = false, features = [
|
||||
"default_fonts", # Embed the default egui fonts.
|
||||
"glow", # Use the glow rendering backend. Alternative: "wgpu".
|
||||
] }
|
||||
|
@ -34,13 +34,13 @@ path = "src/web/main.rs"
|
|||
|
||||
# native:
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
tracing-subscriber = "0.3"
|
||||
tracing-subscriber = "0.3.18"
|
||||
|
||||
# web:
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
console_error_panic_hook = "0.1.6"
|
||||
tracing-wasm = "0.2"
|
||||
wasm-bindgen-futures = "0.4"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
tracing-wasm = "0.2.1"
|
||||
wasm-bindgen-futures = "0.4.39"
|
||||
|
||||
[profile.release]
|
||||
opt-level = 's'
|
||||
|
|
|
@ -13,6 +13,7 @@ Written in Rust with pest PEG parser.
|
|||
<br>
|
||||
|
||||
### TODO playground
|
||||
- compile time reading of the example file
|
||||
- syntax color
|
||||
- line numbers
|
||||
- better panel title
|
||||
|
@ -65,11 +66,11 @@ var: z => val: 8
|
|||
- read / write
|
||||
- program arguments
|
||||
- structs
|
||||
- iterator, for, continue keyword
|
||||
- iterator, for keyword
|
||||
- list
|
||||
- import from other files
|
||||
### tools
|
||||
- live interpreter
|
||||
- repl
|
||||
- LLVM IR translation
|
||||
- JIT
|
||||
- compilation
|
|
@ -8,10 +8,12 @@ if (x) {
|
|||
y = 5;
|
||||
while (x) {
|
||||
if (!y && z % 2) {
|
||||
z = 8;
|
||||
break;
|
||||
} else if (y == 3) {
|
||||
} else if (y == 3) { // never reached because of continue
|
||||
z = 5;
|
||||
} else if (y == 4) {
|
||||
y = y - 2;
|
||||
continue;
|
||||
}
|
||||
y = y - 1;
|
||||
}
|
||||
|
|
Binary file not shown.
|
@ -4,6 +4,7 @@ use std::{env, fs::File, io::Read};
|
|||
|
||||
pub fn main() {
|
||||
for arg in env::args().skip(1) {
|
||||
// if arg match --debug flag
|
||||
let mut f = File::open(&arg).unwrap_or_else(|_| panic!("file {} not found", arg));
|
||||
let mut content = String::new();
|
||||
f.read_to_string(&mut content)
|
||||
|
|
|
@ -38,6 +38,6 @@ impl Display for Environment {
|
|||
.iter()
|
||||
.map(|(key, val)| format!("var: {0} => val: {1}", key, val))
|
||||
.collect();
|
||||
write!(f, "{}", vars.join("\n"))
|
||||
writeln!(f, "{}", vars.join("\n"))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ pub trait Execution {
|
|||
|
||||
impl Execution for Stat {
|
||||
fn execute(&self, environment: &mut Environment) -> Result<ControlFlow, String> {
|
||||
println!("statement: {}", &self);
|
||||
match *self {
|
||||
Stat::Condition(ref condition, ref consequence, ref alternative) => {
|
||||
if condition.evaluate(environment)?.truth() {
|
||||
|
@ -43,9 +44,11 @@ impl Execution for Stat {
|
|||
Stat::Assignment(ref name, ref expr) => {
|
||||
let value = expr.evaluate(environment)?;
|
||||
environment.add(name, value);
|
||||
println!("environment:\n{}", environment);
|
||||
Ok(ControlFlow::Next)
|
||||
}
|
||||
Stat::Break => Ok(ControlFlow::Break),
|
||||
Stat::Continue => Ok(ControlFlow::Next),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -144,6 +144,12 @@ fn build_stat(pair: Pair<Rule>, in_loop: bool) -> Result<Box<Stat>, String> {
|
|||
}
|
||||
Err(parsing_error(pair, "break keyword while not in loop"))
|
||||
}
|
||||
Rule::stat_continue => {
|
||||
if in_loop {
|
||||
return Ok(Stat::continue_keyword());
|
||||
}
|
||||
Err(parsing_error(pair, "continue keyword while not in loop"))
|
||||
}
|
||||
rule => Err(format!(
|
||||
"statement expected assign, if, while or break, found {:?}",
|
||||
rule
|
||||
|
|
|
@ -50,6 +50,7 @@ value = _{ boolean | number | variable | "(" ~ expr ~ ")" }
|
|||
term = { op_unary* ~ value }
|
||||
expr = { term ~ (op_binary ~ term)* }
|
||||
|
||||
stat_continue = { "continue" ~ ";" }
|
||||
stat_break = { "break" ~ ";" }
|
||||
stat_assign = { variable ~ "=" ~ expr ~ ";" }
|
||||
stat_while = { "while" ~ "(" ~ expr ~ ")" ~ "{" ~ stats ~ "}" }
|
||||
|
@ -58,7 +59,7 @@ stat_elif = { ("else if" ~ "(" ~ expr ~ ")" ~ "{" ~ stats ~ "}" ~ "else" ~ "{" ~
|
|||
stat_if = { ("if" ~ "(" ~ expr ~ ")" ~ "{" ~ stats ~ "}" ~ "else" ~ "{" ~ stats ~ "}" ) |
|
||||
("if" ~ "(" ~ expr ~ ")" ~ "{" ~ stats ~ "}" ~ (stat_elif)?) }
|
||||
|
||||
stat = _{ ( stat_if | stat_while | stat_assign | stat_break ) }
|
||||
stat = _{ ( stat_if | stat_while | stat_assign | stat_break | stat_continue ) }
|
||||
|
||||
stats = { (stat)* }
|
||||
|
||||
|
|
|
@ -137,10 +137,9 @@ pub enum Stat {
|
|||
Loop(Box<Expr>, Vec<Stat>),
|
||||
Assignment(String, Box<Expr>),
|
||||
Break,
|
||||
// continue
|
||||
// declare
|
||||
// call
|
||||
// return
|
||||
Continue, // declare
|
||||
// call
|
||||
// return
|
||||
}
|
||||
|
||||
impl Stat {
|
||||
|
@ -150,6 +149,9 @@ impl Stat {
|
|||
pub fn break_keyword() -> Box<Stat> {
|
||||
Box::new(Stat::Break)
|
||||
}
|
||||
pub fn continue_keyword() -> Box<Stat> {
|
||||
Box::new(Stat::Continue)
|
||||
}
|
||||
pub fn while_loop(condition: Box<Expr>, body: Vec<Stat>) -> Box<Stat> {
|
||||
Box::new(Stat::Loop(condition, body))
|
||||
}
|
||||
|
@ -168,7 +170,7 @@ impl Display for Stat {
|
|||
Stat::Condition(condition, body, else_body) => {
|
||||
write!(f, "if {} {{", condition)?;
|
||||
for statement in body {
|
||||
write!(f, "{}", statement)?;
|
||||
write!(f, " {} ", statement)?;
|
||||
}
|
||||
write!(f, "}}")?;
|
||||
if let Some(else_body) = else_body {
|
||||
|
@ -189,6 +191,7 @@ impl Display for Stat {
|
|||
}
|
||||
Stat::Assignment(name, expr) => write!(f, "{} = {};", name, expr),
|
||||
Stat::Break => write!(f, "break;"),
|
||||
Stat::Continue => write!(f, "continue;"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,21 @@
|
|||
use ducklang::{interpreter::machine::Machine, parser::ast::build_ast};
|
||||
|
||||
const EXAMPLE_CODE: &str = r#"// example code
|
||||
const EXAMPLE_CODE: &str = r#"/*
|
||||
An example of program with most of
|
||||
the supported features
|
||||
*/
|
||||
x = true;
|
||||
z = 3 + 4 * (2 + 1); // good order of op
|
||||
if (x) {
|
||||
y = 5;
|
||||
while (x) {
|
||||
if (!y && z % 2) {
|
||||
z = 8;
|
||||
break;
|
||||
} else if (y == 3) {
|
||||
} else if (y == 3) { // never reached because of continue
|
||||
z = 5;
|
||||
} else if (y == 4) {
|
||||
y = y - 2;
|
||||
continue;
|
||||
}
|
||||
y = y - 1;
|
||||
}
|
||||
|
@ -72,7 +77,7 @@ impl MyEguiApp {
|
|||
// calculate desired rows based on the height of the window
|
||||
let font_selection = egui::FontSelection::default();
|
||||
let font_id = font_selection.resolve(ui.style());
|
||||
let row_height = ui.fonts().row_height(&font_id);
|
||||
let row_height = ui.fonts(|fonts| fonts.row_height(&font_id));
|
||||
let rows = (ui.available_size().y / row_height) as usize;
|
||||
ui.add(
|
||||
egui::TextEdit::multiline(&mut self.code)
|
||||
|
@ -164,11 +169,12 @@ fn main() {
|
|||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn main() {
|
||||
let options = eframe::NativeOptions {
|
||||
initial_window_size: Some(egui::vec2(1280.0, 720.0)),
|
||||
resizable: true,
|
||||
viewport: egui::ViewportBuilder::default()
|
||||
.with_inner_size([1280.0, 720.0])
|
||||
.with_resizable(true),
|
||||
..Default::default()
|
||||
};
|
||||
eframe::run_native(
|
||||
let _run_native = eframe::run_native(
|
||||
"Duckscript Playground",
|
||||
options,
|
||||
Box::new(|cc| Box::new(MyEguiApp::new(cc))),
|
||||
|
|
Loading…
Reference in New Issue