feat(language): new continue keyword

flavien 2023-11-27 21:52:06 +01:00
parent 252c23e889
commit 3f053015f6
No known key found for this signature in database
13 changed files with 563 additions and 475 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

963
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -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'

View File

@ -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

View File

@ -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;
}

BIN
src/.DS_Store vendored Normal file

Binary file not shown.

View File

@ -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)

View File

@ -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"))
}
}

View File

@ -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),
}
}
}

View File

@ -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

View File

@ -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)* }

View File

@ -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;"),
}
}
}

View File

@ -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))),