From 27a772dad8b4bff0a5e91c9d25bc948ae8e3d11c Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Wed, 22 Apr 2026 15:03:34 +0200 Subject: [PATCH] Mist Script --- parser/src/lib.rs | 389 +----------------- .../src/{grammar.pest => script_grammar.pest} | 0 parser/src/script_parser.rs | 388 +++++++++++++++++ src/compiler.rs | 9 +- src/main.rs | 76 +--- test/mist.json | 3 +- 6 files changed, 400 insertions(+), 465 deletions(-) rename parser/src/{grammar.pest => script_grammar.pest} (100%) create mode 100644 parser/src/script_parser.rs diff --git a/parser/src/lib.rs b/parser/src/lib.rs index 2dbe131..c9fb5fe 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -1,389 +1,2 @@ -use std::collections::HashMap; - -use pest::Parser; -use pest_derive::Parser; - pub mod ast; -use ast::*; - -#[derive(Parser)] -#[grammar = "./src/grammar.pest"] -pub struct MistParser; - -// convenience alias for pest errors -pub type ParseError = pest::error::Error; - -pub fn parse(source: &str) -> Result, ParseError> { - let mut pairs = MistParser::parse(Rule::program, source)?; - - let mut statements = vec![]; - - for pair in pairs.next().unwrap().into_inner() { - if let Some(stmt) = TopLevel::from_pair(pair) { - statements.push(stmt); - } - } - - Ok(statements) -} - -impl TypeExpr { - pub fn from_pair(pair: pest::iterators::Pair) -> Self { - match pair.as_rule() { - Rule::type_expr => { - let inner = pair.into_inner().next().unwrap(); - TypeExpr::from_pair(inner) - } - Rule::identifier => TypeExpr::Identifier(pair.as_str().to_string()), - _ => unimplemented!("TypeExpr parsing not implemented yet"), - } - } -} - -impl ParamList { - pub fn from_pair(export_allowed: bool, pair: pest::iterators::Pair) -> Self { - let params = pair - .into_inner() - .map(|p| { - let mut param_inner = p.into_inner(); - let export = - if export_allowed && param_inner.peek().unwrap().as_rule() == Rule::export { - param_inner.next().unwrap(); - true - } else { - false - }; - let param_name = param_inner.next().unwrap().as_str().to_string(); - let param_type = TypeExpr::from_pair(param_inner.next().unwrap()); - (param_name, (export, param_type)) - }) - .collect(); - - ParamList(params) - } -} - -impl TopLevel { - pub fn from_pair(pair: pest::iterators::Pair) -> Option { - match pair.as_rule() { - Rule::import => { - let path = pair.into_inner().next().unwrap().as_str().to_string(); - Some(TopLevel::Import(path)) - } - Rule::package => { - let name = pair.into_inner().next().unwrap().as_str().to_string(); - Some(TopLevel::Package(name)) - } - Rule::function_decl => { - let mut inner = pair.into_inner(); - - let export = if let Some(first) = inner.peek() { - if first.as_rule() == Rule::export { - inner.next(); - true - } else { - false - } - } else { - false - }; - let name = inner.next().unwrap().as_str().to_string(); - let params = if inner.peek().unwrap().as_rule() == Rule::param_list { - ParamList::from_pair(false, inner.next().unwrap()) - } else { - ParamList(HashMap::new()) - }; - let return_type = if let Some(next) = inner.peek() { - if next.as_rule() == Rule::type_expr { - Some(TypeExpr::from_pair(inner.next().unwrap())) - } else { - None - } - } else { - None - }; - - let body = Block::from_pair(inner.next().unwrap()); - - Some(TopLevel::FunctionDecl { - export, - name, - params, - return_type, - body, - }) - } - - Rule::struct_decl => { - let mut inner = pair.into_inner(); - let export = if let Some(first) = inner.peek() { - if first.as_rule() == Rule::export { - inner.next(); - true - } else { - false - } - } else { - false - }; - let name = inner.next().unwrap().as_str().to_string(); - let fields_pair = inner.next().unwrap(); - let fields = ParamList::from_pair(true, fields_pair); - - Some(TopLevel::StructDecl { - export, - name, - fields, - }) - } - - Rule::EOI => None, - _ => unimplemented!("TopLevel parsing not implemented yet {:?}", pair.as_rule()), - } - } -} - -impl Block { - pub fn from_pair(pair: pest::iterators::Pair) -> Self { - let statements = pair - .into_inner() - .flat_map(|pair| { - if pair.as_rule() == Rule::statement_list { - pair.into_inner().map(Statement::from_pair).collect() - } else { - vec![Statement::from_pair(pair)] - } - }) - .collect(); - Block(statements) - } -} - -impl Statement { - pub fn from_pair(pair: pest::iterators::Pair) -> Self { - match pair.as_rule() { - Rule::statement => { - let inner = pair.into_inner().next().unwrap(); - Statement::from_pair(inner) - } - - Rule::expr_stmt => { - let expr_pair = pair.into_inner().next().unwrap(); - Statement::Expression(Expression::from_pair(expr_pair)) - } - - Rule::block => Statement::Block(Block::from_pair(pair.into_inner().next().unwrap())), - - Rule::var_decl => { - let mut inner = pair.into_inner(); - - let kind_pair = inner.next().unwrap(); // let/const/var - let name_pair = inner.next().unwrap(); // identifier - - let init = inner.next().map(Expression::from_pair); - - let kind = match kind_pair.as_str() { - "let" => VarKind::Let, - "const" => VarKind::Const, - "var" => VarKind::Var, - _ => unreachable!(), - }; - - Statement::VarDecl { - kind, - name: name_pair.as_str().to_string(), - init, - } - } - - Rule::return_stmt => { - let mut inner = pair.into_inner(); - - let expr = inner.next().map(Expression::from_pair); - - Statement::Return(expr) - } - - Rule::break_stmt => Statement::Break, - - Rule::continue_stmt => Statement::Continue, - - Rule::if_stmt => { - let mut inner = pair.into_inner(); - - let condition = Expression::from_pair(inner.next().unwrap()); - let then_branch = Statement::from_pair(inner.next().unwrap()); - - let else_branch = inner.next().map(Statement::from_pair); - - Statement::If { - condition, - then_branch: Box::new(then_branch), - else_branch: else_branch.map(Box::new), - } - } - - Rule::while_stmt => { - let mut inner = pair.into_inner(); - - let condition = Expression::from_pair(inner.next().unwrap()); - let body = Statement::from_pair(inner.next().unwrap()); - - Statement::While { - condition, - body: Box::new(body), - } - } - - Rule::for_stmt => { - let mut inner = pair.into_inner(); - - let init = inner - .next() - .map(|p| match p.as_rule() { - Rule::var_decl => { - let mut it = p.into_inner(); - - let kind = match it.next().unwrap().as_str() { - "let" => VarKind::Let, - "const" => VarKind::Const, - "var" => VarKind::Var, - _ => unreachable!(), - }; - - let name = it.next().unwrap().as_str().to_string(); - let init_expr = it - .next() - .map(|e| Expression::from_pair(e.into_inner().next().unwrap())); - - (kind, name, init_expr) - } - _ => unimplemented!( - "For loop init parsing not implemented yet: {:?}", - p.as_rule() - ), - }) - .unwrap(); - - let condition = inner.next().map(Expression::from_pair); - let update = inner.next().map(parse_var_assign_no_semicolon); - let body = Statement::from_pair(inner.next().unwrap()); - - Statement::For { - init, - condition, - update: update.map(Box::new), - body: Box::new(body), - } - } - - Rule::var_assign => { - let mut inner = pair.into_inner(); - let target = Expression::from_pair(inner.next().unwrap()); - let value = Expression::from_pair(inner.next().unwrap()); - - Statement::VarAssign { target, value } - } - - _ => unimplemented!( - "Statement parsing not implemented yet: {:?}", - pair.as_rule() - ), - } - } -} - -impl Expression { - pub fn from_pair(pair: pest::iterators::Pair) -> Self { - match pair.as_rule() { - Rule::expr => { - let mut inner = pair.into_inner(); - let exp = Expression::from_pair(inner.next().unwrap()); - - if inner.len() > 0 { - Expression::Postfix { - initial: Box::new(exp), - postfixes: inner.map(|p| Postfix::from_pair(p)).collect(), - } - } else { - exp - } - } - Rule::primary => Expression::from_pair(pair.into_inner().next().unwrap()), - Rule::identifier => Expression::Identifier(pair.as_str().to_string()), - Rule::integer => { - let value = pair.as_str().parse::().unwrap(); - Expression::IntLiteral(value) - } - Rule::float => { - let value = pair.as_str().parse::().unwrap(); - Expression::FloatLiteral(value) - } - Rule::boolean => { - let value = pair.as_str().parse::().unwrap(); - Expression::BoolLiteral(value) - } - Rule::string_lit => { - let inner_str = pair.into_inner().next().unwrap().as_str(); - Expression::StringLiteral(inner_str.to_string()) - } - - _ => unimplemented!( - "Expression parsing not implemented yet {:?}", - pair.as_rule() - ), - } - } -} - -impl Postfix { - pub fn from_pair(pair: pest::iterators::Pair) -> Self { - match pair.as_rule() { - Rule::postfix => Postfix::from_pair(pair.into_inner().next().unwrap()), - - Rule::field_px => { - let field_name = pair.into_inner().next().unwrap().as_str().to_string(); - Postfix::FieldAccess(field_name) - } - - Rule::call_px => Postfix::Call(pair.into_inner().map(Expression::from_pair).collect()), - - Rule::index_px => { - Postfix::Index(Expression::from_pair(pair.into_inner().next().unwrap())) - } - - Rule::binary_px => { - let mut inner = pair.into_inner(); - let op_pair = inner.next().unwrap(); - let op = match op_pair.as_str() { - "+" => BinaryOp::Plus, - "-" => BinaryOp::Minus, - "*" => BinaryOp::Multiply, - "/" => BinaryOp::Divide, - "%" => BinaryOp::Modulo, - "==" => BinaryOp::Equal, - "!=" => BinaryOp::NotEqual, - "<" => BinaryOp::LessThan, - ">" => BinaryOp::GreaterThan, - "<=" => BinaryOp::LessThanOrEqual, - ">=" => BinaryOp::GreaterThanOrEqual, - - _ => { - unimplemented!("Binary operator not implemented yet: {}", op_pair.as_str()) - } - }; - Postfix::Binary(op, Expression::from_pair(inner.next().unwrap())) - } - - _ => unimplemented!("Postfix parsing not implemented yet {:?}", pair.as_rule()), - } - } -} - -fn parse_var_assign_no_semicolon(pair: pest::iterators::Pair) -> Statement { - let mut inner = pair.into_inner(); - let target = Expression::from_pair(inner.next().unwrap()); - let value = Expression::from_pair(inner.next().unwrap()); - - Statement::VarAssign { target, value } -} +pub mod script_parser; diff --git a/parser/src/grammar.pest b/parser/src/script_grammar.pest similarity index 100% rename from parser/src/grammar.pest rename to parser/src/script_grammar.pest diff --git a/parser/src/script_parser.rs b/parser/src/script_parser.rs new file mode 100644 index 0000000..f580d4b --- /dev/null +++ b/parser/src/script_parser.rs @@ -0,0 +1,388 @@ +use std::collections::HashMap; + +use pest::Parser; +use pest_derive::Parser; + +use crate::ast::*; + +#[derive(Parser)] +#[grammar = "./src/script_grammar.pest"] +pub struct MistParser; + +// convenience alias for pest errors +pub type ParseError = pest::error::Error; + +pub fn parse(source: &str) -> Result, ParseError> { + let mut pairs = MistParser::parse(Rule::program, source)?; + + let mut statements = vec![]; + + for pair in pairs.next().unwrap().into_inner() { + if let Some(stmt) = TopLevel::from_pair(pair) { + statements.push(stmt); + } + } + + Ok(statements) +} + +impl TypeExpr { + pub fn from_pair(pair: pest::iterators::Pair) -> Self { + match pair.as_rule() { + Rule::type_expr => { + let inner = pair.into_inner().next().unwrap(); + TypeExpr::from_pair(inner) + } + Rule::identifier => TypeExpr::Identifier(pair.as_str().to_string()), + _ => unimplemented!("TypeExpr parsing not implemented yet"), + } + } +} + +impl ParamList { + pub fn from_pair(export_allowed: bool, pair: pest::iterators::Pair) -> Self { + let params = pair + .into_inner() + .map(|p| { + let mut param_inner = p.into_inner(); + let export = + if export_allowed && param_inner.peek().unwrap().as_rule() == Rule::export { + param_inner.next().unwrap(); + true + } else { + false + }; + let param_name = param_inner.next().unwrap().as_str().to_string(); + let param_type = TypeExpr::from_pair(param_inner.next().unwrap()); + (param_name, (export, param_type)) + }) + .collect(); + + ParamList(params) + } +} + +impl TopLevel { + pub fn from_pair(pair: pest::iterators::Pair) -> Option { + match pair.as_rule() { + Rule::import => { + let path = pair.into_inner().next().unwrap().as_str().to_string(); + Some(TopLevel::Import(path)) + } + Rule::package => { + let name = pair.into_inner().next().unwrap().as_str().to_string(); + Some(TopLevel::Package(name)) + } + Rule::function_decl => { + let mut inner = pair.into_inner(); + + let export = if let Some(first) = inner.peek() { + if first.as_rule() == Rule::export { + inner.next(); + true + } else { + false + } + } else { + false + }; + let name = inner.next().unwrap().as_str().to_string(); + let params = if inner.peek().unwrap().as_rule() == Rule::param_list { + ParamList::from_pair(false, inner.next().unwrap()) + } else { + ParamList(HashMap::new()) + }; + let return_type = if let Some(next) = inner.peek() { + if next.as_rule() == Rule::type_expr { + Some(TypeExpr::from_pair(inner.next().unwrap())) + } else { + None + } + } else { + None + }; + + let body = Block::from_pair(inner.next().unwrap()); + + Some(TopLevel::FunctionDecl { + export, + name, + params, + return_type, + body, + }) + } + + Rule::struct_decl => { + let mut inner = pair.into_inner(); + let export = if let Some(first) = inner.peek() { + if first.as_rule() == Rule::export { + inner.next(); + true + } else { + false + } + } else { + false + }; + let name = inner.next().unwrap().as_str().to_string(); + let fields_pair = inner.next().unwrap(); + let fields = ParamList::from_pair(true, fields_pair); + + Some(TopLevel::StructDecl { + export, + name, + fields, + }) + } + + Rule::EOI => None, + _ => unimplemented!("TopLevel parsing not implemented yet {:?}", pair.as_rule()), + } + } +} + +impl Block { + pub fn from_pair(pair: pest::iterators::Pair) -> Self { + let statements = pair + .into_inner() + .flat_map(|pair| { + if pair.as_rule() == Rule::statement_list { + pair.into_inner().map(Statement::from_pair).collect() + } else { + vec![Statement::from_pair(pair)] + } + }) + .collect(); + Block(statements) + } +} + +impl Statement { + pub fn from_pair(pair: pest::iterators::Pair) -> Self { + match pair.as_rule() { + Rule::statement => { + let inner = pair.into_inner().next().unwrap(); + Statement::from_pair(inner) + } + + Rule::expr_stmt => { + let expr_pair = pair.into_inner().next().unwrap(); + Statement::Expression(Expression::from_pair(expr_pair)) + } + + Rule::block => Statement::Block(Block::from_pair(pair.into_inner().next().unwrap())), + + Rule::var_decl => { + let mut inner = pair.into_inner(); + + let kind_pair = inner.next().unwrap(); // let/const/var + let name_pair = inner.next().unwrap(); // identifier + + let init = inner.next().map(Expression::from_pair); + + let kind = match kind_pair.as_str() { + "let" => VarKind::Let, + "const" => VarKind::Const, + "var" => VarKind::Var, + _ => unreachable!(), + }; + + Statement::VarDecl { + kind, + name: name_pair.as_str().to_string(), + init, + } + } + + Rule::return_stmt => { + let mut inner = pair.into_inner(); + + let expr = inner.next().map(Expression::from_pair); + + Statement::Return(expr) + } + + Rule::break_stmt => Statement::Break, + + Rule::continue_stmt => Statement::Continue, + + Rule::if_stmt => { + let mut inner = pair.into_inner(); + + let condition = Expression::from_pair(inner.next().unwrap()); + let then_branch = Statement::from_pair(inner.next().unwrap()); + + let else_branch = inner.next().map(Statement::from_pair); + + Statement::If { + condition, + then_branch: Box::new(then_branch), + else_branch: else_branch.map(Box::new), + } + } + + Rule::while_stmt => { + let mut inner = pair.into_inner(); + + let condition = Expression::from_pair(inner.next().unwrap()); + let body = Statement::from_pair(inner.next().unwrap()); + + Statement::While { + condition, + body: Box::new(body), + } + } + + Rule::for_stmt => { + let mut inner = pair.into_inner(); + + let init = inner + .next() + .map(|p| match p.as_rule() { + Rule::var_decl => { + let mut it = p.into_inner(); + + let kind = match it.next().unwrap().as_str() { + "let" => VarKind::Let, + "const" => VarKind::Const, + "var" => VarKind::Var, + _ => unreachable!(), + }; + + let name = it.next().unwrap().as_str().to_string(); + let init_expr = it + .next() + .map(|e| Expression::from_pair(e.into_inner().next().unwrap())); + + (kind, name, init_expr) + } + _ => unimplemented!( + "For loop init parsing not implemented yet: {:?}", + p.as_rule() + ), + }) + .unwrap(); + + let condition = inner.next().map(Expression::from_pair); + let update = inner.next().map(parse_var_assign_no_semicolon); + let body = Statement::from_pair(inner.next().unwrap()); + + Statement::For { + init, + condition, + update: update.map(Box::new), + body: Box::new(body), + } + } + + Rule::var_assign => { + let mut inner = pair.into_inner(); + let target = Expression::from_pair(inner.next().unwrap()); + let value = Expression::from_pair(inner.next().unwrap()); + + Statement::VarAssign { target, value } + } + + _ => unimplemented!( + "Statement parsing not implemented yet: {:?}", + pair.as_rule() + ), + } + } +} + +impl Expression { + pub fn from_pair(pair: pest::iterators::Pair) -> Self { + match pair.as_rule() { + Rule::expr => { + let mut inner = pair.into_inner(); + let exp = Expression::from_pair(inner.next().unwrap()); + + if inner.len() > 0 { + Expression::Postfix { + initial: Box::new(exp), + postfixes: inner.map(|p| Postfix::from_pair(p)).collect(), + } + } else { + exp + } + } + Rule::primary => Expression::from_pair(pair.into_inner().next().unwrap()), + Rule::identifier => Expression::Identifier(pair.as_str().to_string()), + Rule::integer => { + let value = pair.as_str().parse::().unwrap(); + Expression::IntLiteral(value) + } + Rule::float => { + let value = pair.as_str().parse::().unwrap(); + Expression::FloatLiteral(value) + } + Rule::boolean => { + let value = pair.as_str().parse::().unwrap(); + Expression::BoolLiteral(value) + } + Rule::string_lit => { + let inner_str = pair.into_inner().next().unwrap().as_str(); + Expression::StringLiteral(inner_str.to_string()) + } + + _ => unimplemented!( + "Expression parsing not implemented yet {:?}", + pair.as_rule() + ), + } + } +} + +impl Postfix { + pub fn from_pair(pair: pest::iterators::Pair) -> Self { + match pair.as_rule() { + Rule::postfix => Postfix::from_pair(pair.into_inner().next().unwrap()), + + Rule::field_px => { + let field_name = pair.into_inner().next().unwrap().as_str().to_string(); + Postfix::FieldAccess(field_name) + } + + Rule::call_px => Postfix::Call(pair.into_inner().map(Expression::from_pair).collect()), + + Rule::index_px => { + Postfix::Index(Expression::from_pair(pair.into_inner().next().unwrap())) + } + + Rule::binary_px => { + let mut inner = pair.into_inner(); + let op_pair = inner.next().unwrap(); + let op = match op_pair.as_str() { + "+" => BinaryOp::Plus, + "-" => BinaryOp::Minus, + "*" => BinaryOp::Multiply, + "/" => BinaryOp::Divide, + "%" => BinaryOp::Modulo, + "==" => BinaryOp::Equal, + "!=" => BinaryOp::NotEqual, + "<" => BinaryOp::LessThan, + ">" => BinaryOp::GreaterThan, + "<=" => BinaryOp::LessThanOrEqual, + ">=" => BinaryOp::GreaterThanOrEqual, + + _ => { + unimplemented!("Binary operator not implemented yet: {}", op_pair.as_str()) + } + }; + Postfix::Binary(op, Expression::from_pair(inner.next().unwrap())) + } + + _ => unimplemented!("Postfix parsing not implemented yet {:?}", pair.as_rule()), + } + } +} + +fn parse_var_assign_no_semicolon(pair: pest::iterators::Pair) -> Statement { + let mut inner = pair.into_inner(); + let target = Expression::from_pair(inner.next().unwrap()); + let value = Expression::from_pair(inner.next().unwrap()); + + Statement::VarAssign { target, value } +} diff --git a/src/compiler.rs b/src/compiler.rs index c7cbbe9..fb5621f 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -6,6 +6,7 @@ use serde::Deserialize; struct Config { entry: String, out_dir: String, + script: bool, } pub fn build() { @@ -37,7 +38,13 @@ pub fn build() { println!(" → parsing..."); - let mut ast = match parser::parse(&source) { + let parser_result = if config.script { + parser::script_parser::parse(&source) + } else { + parser::script_parser::parse(&source) + }; + + let mut ast = match parser_result { Ok(ast) => ast, Err(e) => { eprintln!("error: parse failed\n{}", e); diff --git a/src/main.rs b/src/main.rs index 6331f9c..2632a49 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,6 @@ -pub mod compiler; - -use std::fs; -use std::path::PathBuf; use std::process; -use semantic::walk_ast; +pub mod compiler; fn main() { let args: Vec = std::env::args().collect(); @@ -22,20 +18,6 @@ fn main() { } compiler::build(); } - "check" => { - if args.len() < 3 { - eprintln!("error: expected a file path\n usage: mist check "); - process::exit(1); - } - cmd_check(&args[2]); - } - "parse" => { - if args.len() < 3 { - eprintln!("error: expected a file path\n usage: mist check "); - process::exit(1); - } - cmd_parse(&args[2]); - } "version" | "--version" | "-v" => { println!("mist {}", env!("CARGO_PKG_VERSION")); } @@ -50,62 +32,6 @@ fn main() { } } -fn cmd_check(path: &str) { - let source = read_ms_file(path); - match parser::parse(&source) { - Ok(mut ast) => { - println!("parse: ok"); - - // walk_ast(semantic::scope::Scope::from_top(&ast), &mut ast); - - println!("{:#?}", ast) - } - Err(e) => { - eprintln!("parse error:\n{}", e); - process::exit(1); - } - } -} - -fn cmd_parse(path: &str) { - let source = read_ms_file(path); - match parser::parse(&source) { - Ok(mut ast) => { - // walk_ast(semantic::scope::Scope::from_top(&ast), &mut ast); - - fs::write("output.json", serde_json::to_string_pretty(&ast).unwrap()).unwrap_or_else( - |e| { - eprintln!("error: could not write output.json: {}", e); - process::exit(1); - }, - ); - } - Err(e) => { - eprintln!("parse error:\n{}", e); - process::exit(1); - } - } -} - -fn read_ms_file(path: &str) -> String { - let pb = PathBuf::from(path); - - if !pb.exists() { - eprintln!("error: file '{}' not found", path); - process::exit(1); - } - - if pb.extension().and_then(|e| e.to_str()) != Some("ms") { - eprintln!("error: expected a .ms file, got '{}'", path); - process::exit(1); - } - - fs::read_to_string(&pb).unwrap_or_else(|e| { - eprintln!("error: could not read '{}': {}", path, e); - process::exit(1); - }) -} - fn print_usage() { println!("mist - the mist compiler"); println!(); diff --git a/test/mist.json b/test/mist.json index c639516..6a2d242 100644 --- a/test/mist.json +++ b/test/mist.json @@ -1,4 +1,5 @@ { "entry": "src/main.ms", - "out_dir": "build" + "out_dir": "build", + "script": true } \ No newline at end of file