Merge pull request #4 from mist-go/rewritten-parser

Rewritten parser
This commit is contained in:
2026-04-14 10:41:49 +02:00
committed by GitHub
8 changed files with 808 additions and 861 deletions
+1
View File
@@ -26,3 +26,4 @@ target
/target /target
/test/build /test/build
/test/output.json
+3 -2
View File
@@ -41,7 +41,7 @@ pub fn build() {
let ast = match parser::parse(&source) { let ast = match parser::parse(&source) {
Ok(ast) => { Ok(ast) => {
println!(" ✓ parsed {} items", ast.statements.len()); println!(" ✓ parsed {} items", ast.len());
ast ast
} }
Err(e) => { Err(e) => {
@@ -52,7 +52,8 @@ pub fn build() {
println!(" → generating Go code..."); println!(" → generating Go code...");
let output = gogen::generate(&ast); // let output = gogen::generate(&ast);
let output = String::from("// TODO: implement code generation\n");
// 4. ensure build dir // 4. ensure build dir
if let Err(e) = fs::create_dir_all(&out_dir) { if let Err(e) = fs::create_dir_all(&out_dir) {
+229 -229
View File
@@ -1,283 +1,283 @@
use crate::parser::ast::{ // use crate::parser::ast::{
BinOperator, Class, Expression, Function, Program, Statement, Struct, TopLevel, TypeExpr, // BinOperator, Class, Expression, Function, Statement, Struct, TopLevel, TopLevel, TypeExpr,
}; // };
pub fn generate(program: &Program) -> String { // pub fn generate(program: &TopLevel) -> String {
let mut out = String::new(); // let mut out = String::new();
out.push_str("package main\n\n"); // out.push_str("package main\n\n");
// imports // // imports
let mut imports = vec![]; // let mut imports = vec![];
for item in &program.statements { // for item in &program.statements {
if let TopLevel::Import(i) = item { // if let TopLevel::Import(i) = item {
imports.push(i.path.clone()); // imports.push(i.path.clone());
} // }
} // }
if !imports.is_empty() { // if !imports.is_empty() {
out.push_str("import (\n"); // out.push_str("import (\n");
for imp in imports { // for imp in imports {
out.push_str(&format!(" {}\n", imp)); // out.push_str(&format!(" {}\n", imp));
} // }
out.push_str(")\n\n"); // out.push_str(")\n\n");
} // }
// rest // // rest
for item in &program.statements { // for item in &program.statements {
match item { // match item {
TopLevel::Function(f) => out.push_str(&gen_function(f)), // TopLevel::Function(f) => out.push_str(&gen_function(f)),
TopLevel::Struct(s) => out.push_str(&gen_struct(s)), // TopLevel::Struct(s) => out.push_str(&gen_struct(s)),
TopLevel::Class(c) => out.push_str(&gen_class(c)), // TopLevel::Class(c) => out.push_str(&gen_class(c)),
TopLevel::Import(_) => {} // TopLevel::Import(_) => {}
} // }
out.push('\n'); // out.push('\n');
} // }
out // out
} // }
fn gen_struct(s: &Struct) -> String { // fn gen_struct(s: &Struct) -> String {
let mut out = format!("type {} struct {{\n", s.name); // let mut out = format!("type {} struct {{\n", s.name);
for field in &s.fields { // for field in &s.fields {
out.push_str(&format!( // out.push_str(&format!(
" {} {}\n", // " {} {}\n",
capitalize(&field.name), // capitalize(&field.name),
gen_type(&field.type_expr) // gen_type(&field.type_expr)
)); // ));
} // }
out.push_str("}\n"); // out.push_str("}\n");
out // out
} // }
fn gen_class(c: &Class) -> String { // fn gen_class(c: &Class) -> String {
let mut out = String::new(); // let mut out = String::new();
// struct // // struct
out.push_str(&format!("type {} struct {{\n", c.name)); // out.push_str(&format!("type {} struct {{\n", c.name));
for field in &c.fields { // for field in &c.fields {
out.push_str(&format!( // out.push_str(&format!(
" {} {}\n", // " {} {}\n",
capitalize(&field.name), // capitalize(&field.name),
gen_type(&field.type_expr) // gen_type(&field.type_expr)
)); // ));
} // }
out.push_str("}\n\n"); // out.push_str("}\n\n");
// methods // // methods
for method in &c.methods { // for method in &c.methods {
out.push_str(&gen_method(c, method)); // out.push_str(&gen_method(c, method));
out.push('\n'); // out.push('\n');
} // }
out // out
} // }
fn gen_function(f: &Function) -> String { // fn gen_function(f: &Function) -> String {
let mut out = format!("func {}(", f.name); // let mut out = format!("func {}(", f.name);
// params // // params
for (i, p) in f.params.iter().enumerate() { // for (i, p) in f.params.iter().enumerate() {
if i > 0 { // if i > 0 {
out.push_str(", "); // out.push_str(", ");
} // }
out.push_str(&format!("{} {}", p.name, gen_type(&p.type_expr))); // out.push_str(&format!("{} {}", p.name, gen_type(&p.type_expr)));
} // }
out.push(')'); // out.push(')');
// return // // return
if let Some(ret) = &f.return_type { // if let Some(ret) = &f.return_type {
out.push_str(&format!(" {}", gen_type(ret))); // out.push_str(&format!(" {}", gen_type(ret)));
} // }
out.push_str(" {\n"); // out.push_str(" {\n");
for stmt in &f.body { // for stmt in &f.body {
out.push_str(&gen_statement(stmt)); // out.push_str(&gen_statement(stmt));
} // }
out.push_str("}\n"); // out.push_str("}\n");
out // out
} // }
fn gen_method(class: &Class, f: &Function) -> String { // fn gen_method(class: &Class, f: &Function) -> String {
let mut out = format!("func (self *{}) {}(", class.name, f.name); // let mut out = format!("func (self *{}) {}(", class.name, f.name);
for (i, p) in f.params.iter().enumerate() { // for (i, p) in f.params.iter().enumerate() {
if i > 0 { // if i > 0 {
out.push_str(", "); // out.push_str(", ");
} // }
out.push_str(&format!("{} {}", p.name, gen_type(&p.type_expr))); // out.push_str(&format!("{} {}", p.name, gen_type(&p.type_expr)));
} // }
out.push(')'); // out.push(')');
if let Some(ret) = &f.return_type { // if let Some(ret) = &f.return_type {
out.push_str(&format!(" {}", gen_type(ret))); // out.push_str(&format!(" {}", gen_type(ret)));
} // }
out.push_str(" {\n"); // out.push_str(" {\n");
for stmt in &f.body { // for stmt in &f.body {
out.push_str(&gen_statement(stmt)); // out.push_str(&gen_statement(stmt));
} // }
out.push_str("}\n"); // out.push_str("}\n");
out // out
} // }
fn gen_statement(stmt: &Statement) -> String { // fn gen_statement(stmt: &Statement) -> String {
match stmt { // match stmt {
Statement::Let(s) => { // Statement::Let(s) => {
let mut out = format!(" {} := {}", s.name, gen_expr(&s.value)); // let mut out = format!(" {} := {}", s.name, gen_expr(&s.value));
out.push_str(";\n"); // out.push_str(";\n");
out // out
} // }
Statement::Return(r) => match &r.value { // Statement::Return(r) => match &r.value {
Some(v) => format!(" return {};\n", gen_expr(v)), // Some(v) => format!(" return {};\n", gen_expr(v)),
None => " return;\n".to_string(), // None => " return;\n".to_string(),
}, // },
Statement::Expression(e) => { // Statement::Expression(e) => {
format!(" {};\n", gen_expr(e)) // format!(" {};\n", gen_expr(e))
} // }
Statement::If(i) => { // Statement::If(i) => {
let mut out = format!(" if {} {{\n", gen_expr(&i.condition)); // let mut out = format!(" if {} {{\n", gen_expr(&i.condition));
for stmt in &i.body { // for stmt in &i.body {
out.push_str(&gen_statement(stmt)); // out.push_str(&gen_statement(stmt));
} // }
out.push_str(" }"); // out.push_str(" }");
if let Some(else_body) = &i.else_body { // if let Some(else_body) = &i.else_body {
out.push_str(" else {\n"); // out.push_str(" else {\n");
for stmt in else_body { // for stmt in else_body {
out.push_str(&gen_statement(stmt)); // out.push_str(&gen_statement(stmt));
} // }
out.push_str(" }"); // out.push_str(" }");
} // }
out.push('\n'); // out.push('\n');
out // out
} // }
Statement::For(f) => { // Statement::For(f) => {
let mut out = format!( // let mut out = format!(
" for _, {} := range {} {{\n", // " for _, {} := range {} {{\n",
f.var, // f.var,
gen_expr(&f.iterator) // gen_expr(&f.iterator)
); // );
for stmt in &f.body { // for stmt in &f.body {
out.push_str(&gen_statement(stmt)); // out.push_str(&gen_statement(stmt));
} // }
out.push_str(" }\n"); // out.push_str(" }\n");
out // out
} // }
} // }
} // }
fn gen_expr(expr: &Expression) -> String { // fn gen_expr(expr: &Expression) -> String {
match expr { // match expr {
Expression::Identifier(name, _) => name.clone(), // Expression::Identifier(name, _) => name.clone(),
Expression::Integer(v, _) => v.to_string(), // Expression::Integer(v, _) => v.to_string(),
Expression::Float(v, _) => v.to_string(), // Expression::Float(v, _) => v.to_string(),
Expression::StringLit(s, _) => format!("\"{}\"", s), // Expression::StringLit(s, _) => format!("\"{}\"", s),
Expression::Bool(b, _) => b.to_string(), // Expression::Bool(b, _) => b.to_string(),
Expression::BinaryOp(b) => format!( // Expression::BinaryOp(b) => format!(
"{} {} {}", // "{} {} {}",
gen_expr(&b.left), // gen_expr(&b.left),
op_to_str(&b.op), // op_to_str(&b.op),
gen_expr(&b.right) // gen_expr(&b.right)
), // ),
Expression::Call(c) => { // Expression::Call(c) => {
let args = c.args.iter().map(gen_expr).collect::<Vec<_>>().join(", "); // let args = c.args.iter().map(gen_expr).collect::<Vec<_>>().join(", ");
format!("{}({})", gen_expr(&c.callee), args) // format!("{}({})", gen_expr(&c.callee), args)
} // }
Expression::FieldAccess(f) => { // Expression::FieldAccess(f) => {
format!("{}.{}", gen_expr(&f.object), capitalize(&f.field)) // format!("{}.{}", gen_expr(&f.object), capitalize(&f.field))
} // }
Expression::StructInit(s) => { // Expression::StructInit(s) => {
let mut out = format!("{}{{", s.name); // let mut out = format!("{}{{", s.name);
for (i, (name, val)) in s.fields.iter().enumerate() { // for (i, (name, val)) in s.fields.iter().enumerate() {
if i > 0 { // if i > 0 {
out.push_str(", "); // out.push_str(", ");
} // }
out.push_str(&format!("{}: {}", capitalize(name), gen_expr(val))); // out.push_str(&format!("{}: {}", capitalize(name), gen_expr(val)));
} // }
out.push('}'); // out.push('}');
out // out
} // }
Expression::ArrayLiteral(arr) => { // Expression::ArrayLiteral(arr) => {
let elems = arr // let elems = arr
.elements // .elements
.iter() // .iter()
.map(gen_expr) // .map(gen_expr)
.collect::<Vec<_>>() // .collect::<Vec<_>>()
.join(", "); // .join(", ");
format!("[]any{{{}}}", elems) // simple version // format!("[]any{{{}}}", elems) // simple version
} // }
_ => todo!(), // _ => todo!(),
} // }
} // }
fn gen_type(t: &TypeExpr) -> String { // fn gen_type(t: &TypeExpr) -> String {
match t { // match t {
TypeExpr::Named(n) => match n.as_str() { // TypeExpr::Named(n) => match n.as_str() {
"int" => "int".into(), // "int" => "int".into(),
"float" => "float64".into(), // "float" => "float64".into(),
"string" => "string".into(), // "string" => "string".into(),
_ => n.clone(), // _ => n.clone(),
}, // },
TypeExpr::Array(inner) => { // TypeExpr::Array(inner) => {
format!("[]{}", gen_type(inner)) // format!("[]{}", gen_type(inner))
} // }
TypeExpr::Optional(inner) => { // TypeExpr::Optional(inner) => {
format!("*{}", gen_type(inner)) // pointer for optional // format!("*{}", gen_type(inner)) // pointer for optional
} // }
} // }
} // }
fn capitalize(s: &str) -> String { // fn capitalize(s: &str) -> String {
let mut chars = s.chars(); // let mut chars = s.chars();
match chars.next() { // match chars.next() {
Some(c) => c.to_uppercase().collect::<String>() + chars.as_str(), // Some(c) => c.to_uppercase().collect::<String>() + chars.as_str(),
None => String::new(), // None => String::new(),
} // }
} // }
fn op_to_str(op: &BinOperator) -> &'static str { // fn op_to_str(op: &BinOperator) -> &'static str {
match op { // match op {
BinOperator::Add => "+", // BinOperator::Add => "+",
BinOperator::Sub => "-", // BinOperator::Sub => "-",
BinOperator::Mul => "*", // BinOperator::Mul => "*",
BinOperator::Div => "/", // BinOperator::Div => "/",
BinOperator::Eq => "==", // BinOperator::Eq => "==",
BinOperator::NotEq => "!=", // BinOperator::NotEq => "!=",
BinOperator::Lt => "<", // BinOperator::Lt => "<",
BinOperator::Gt => ">", // BinOperator::Gt => ">",
BinOperator::LtEq => "<=", // BinOperator::LtEq => "<=",
BinOperator::GtEq => ">=", // BinOperator::GtEq => ">=",
BinOperator::And => "&&", // BinOperator::And => "&&",
BinOperator::Or => "||", // BinOperator::Or => "||",
} // }
} // }
+27
View File
@@ -30,6 +30,13 @@ fn main() {
} }
cmd_check(&args[2]); cmd_check(&args[2]);
} }
"parse" => {
if args.len() < 3 {
eprintln!("error: expected a file path\n usage: mist check <file.ms>");
process::exit(1);
}
cmd_parse(&args[2]);
}
"version" | "--version" | "-v" => { "version" | "--version" | "-v" => {
println!("mist {}", env!("CARGO_PKG_VERSION")); println!("mist {}", env!("CARGO_PKG_VERSION"));
} }
@@ -61,6 +68,26 @@ fn cmd_check(path: &str) {
} }
} }
fn cmd_parse(path: &str) {
let source = read_ms_file(path);
match parser::parse(&source) {
Ok(output) => {
fs::write(
"output.json",
serde_json::to_string_pretty(&output).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 { fn read_ms_file(path: &str) -> String {
let pb = PathBuf::from(path); let pb = PathBuf::from(path);
+118 -180
View File
@@ -1,187 +1,125 @@
#[derive(Debug, Clone)] use serde::Serialize;
pub struct Span {
pub start: usize,
pub end: usize,
}
#[derive(Debug, Clone)] #[derive(Debug, Clone, Serialize)]
pub struct Program { pub struct ParamList(pub Vec<(String, TypeExpr)>);
pub statements: Vec<TopLevel>,
}
#[derive(Debug, Clone)] #[derive(Debug, Clone, Serialize)]
pub enum TopLevel { pub struct Block(pub Vec<Statement>);
Function(Function),
Struct(Struct),
Class(Class),
Import(Import),
}
#[derive(Debug, Clone)] #[derive(Debug, Clone, Serialize)]
pub struct Function { #[serde(tag = "type", content = "value")]
pub name: String,
pub params: Vec<Param>,
pub return_type: Option<TypeExpr>,
pub body: Vec<Statement>,
pub span: Span,
}
#[derive(Debug, Clone)]
pub struct Param {
pub name: String,
pub type_expr: TypeExpr,
pub span: Span,
}
#[derive(Debug, Clone)]
pub struct Struct {
pub name: String,
pub fields: Vec<StructField>,
pub span: Span,
}
#[derive(Debug, Clone)]
pub struct StructField {
pub name: String,
pub type_expr: TypeExpr,
pub span: Span,
}
#[derive(Debug, Clone)]
pub struct Class {
pub name: String,
pub fields: Vec<StructField>,
pub methods: Vec<Function>,
pub span: Span,
}
#[derive(Debug, Clone)]
pub struct Import {
pub path: String,
pub span: Span,
}
#[derive(Debug, Clone)]
pub enum Statement {
Let(LetStatement),
Return(ReturnStatement),
Expression(Expression),
If(IfStatement),
For(ForStatement),
}
#[derive(Debug, Clone)]
pub struct LetStatement {
pub name: String,
pub type_expr: Option<TypeExpr>,
pub value: Expression,
pub span: Span,
}
#[derive(Debug, Clone)]
pub struct ReturnStatement {
pub value: Option<Expression>,
pub span: Span,
}
#[derive(Debug, Clone)]
pub struct IfStatement {
pub condition: Expression,
pub body: Vec<Statement>,
pub else_body: Option<Vec<Statement>>,
pub span: Span,
}
#[derive(Debug, Clone)]
pub struct ForStatement {
pub var: String,
pub iterator: Expression,
pub body: Vec<Statement>,
pub span: Span,
}
#[derive(Debug, Clone)]
pub enum Expression {
Identifier(String, Span),
Integer(i64, Span),
Float(f64, Span),
StringLit(String, Span),
Bool(bool, Span),
BinaryOp(Box<BinaryOp>),
UnaryOp(Box<UnaryOp>),
Call(Box<CallExpr>),
FieldAccess(Box<FieldAccess>),
StructInit(Box<StructInit>),
ArrayLiteral(Box<ArrayLiteral>),
}
#[derive(Debug, Clone)]
pub struct BinaryOp {
pub left: Expression,
pub op: BinOperator,
pub right: Expression,
pub span: Span,
}
#[derive(Debug, Clone)]
pub enum BinOperator {
Add,
Sub,
Mul,
Div,
Eq,
NotEq,
Lt,
Gt,
LtEq,
GtEq,
And,
Or,
}
#[derive(Debug, Clone)]
pub struct UnaryOp {
pub op: UnaryOperator,
pub expr: Expression,
pub span: Span,
}
#[derive(Debug, Clone)]
pub enum UnaryOperator {
Neg,
Not,
}
#[derive(Debug, Clone)]
pub struct CallExpr {
pub callee: Expression,
pub args: Vec<Expression>,
pub span: Span,
}
#[derive(Debug, Clone)]
pub struct FieldAccess {
pub object: Expression,
pub field: String,
pub span: Span,
}
#[derive(Debug, Clone)]
pub struct StructInit {
pub name: String,
pub fields: Vec<(String, Expression)>,
pub span: Span,
}
#[derive(Debug, Clone)]
pub enum TypeExpr { pub enum TypeExpr {
Named(String), Identifier(String),
Array(Box<TypeExpr>),
Optional(Box<TypeExpr>),
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone, Serialize)]
pub struct ArrayLiteral { pub enum BinaryOp {
pub elements: Vec<Expression>, Plus,
pub span: Span, Minus,
Multiply,
Divide,
Modulo,
Equal,
NotEqual,
LessThan,
GreaterThan,
LessThanOrEqual,
GreaterThanOrEqual,
}
#[derive(Debug, Clone, Serialize)]
#[serde(tag = "type", content = "value")]
pub enum TopLevel {
Import(String),
StructDecl {
export: bool,
name: String,
fields: ParamList,
},
FunctionDecl {
export: bool,
name: String,
params: ParamList,
return_type: Option<TypeExpr>,
body: Block,
},
}
#[derive(Debug, Clone, Serialize)]
#[serde(tag = "type", content = "value")]
pub enum Postfix {
FieldAccess(String),
Call(Vec<Expression>),
Index(Expression),
Binary(BinaryOp, Expression),
}
#[derive(Debug, Clone, Serialize)]
#[serde(tag = "type", content = "value")]
pub enum Statement {
// expr;
Expression(Expression),
// { ... }
Block(Block),
// let/const/var x = ...
VarDecl {
kind: VarKind,
name: String,
init: Option<Expression>,
},
VarAssign {
target: Expression,
value: Expression,
},
// if (...) stmt else stmt
If {
condition: Expression,
then_branch: Box<Statement>,
else_branch: Option<Box<Statement>>,
},
// while (...) stmt
While {
condition: Expression,
body: Box<Statement>,
},
// for (...) stmt
For {
init: (VarKind, String, Option<Expression>),
condition: Option<Expression>,
update: Option<Box<Statement>>,
body: Box<Statement>,
},
// return expr?;
Return(Option<Expression>),
Break,
Continue,
}
#[derive(Debug, Clone, Serialize)]
#[serde(tag = "type", content = "value")]
pub enum Expression {
Identifier(String),
IntLiteral(i64),
FloatLiteral(f64),
BoolLiteral(bool),
StringLiteral(String),
Postfix {
initial: Box<Expression>,
postfixes: Vec<Postfix>,
},
}
#[derive(Debug, Clone, Serialize)]
pub enum VarKind {
Let,
Const,
Var,
} }
+72 -117
View File
@@ -1,8 +1,7 @@
WHITESPACE = _{ " " | "\t" | "\r" | "\n" } WHITESPACE = _{ " " | "\t" | "\r" | "\n" }
COMMENT = _{ "//" ~ (!"\n" ~ ANY)* } COMMENT = _{ "//" ~ (!"\n" ~ ANY)* }
program = { SOI ~ item* ~ EOI } program = { SOI ~ top_level* ~ EOI }
item = _{ import_decl | function_decl | struct_decl | class_decl }
// primitives // primitives
identifier = @{ (ASCII_ALPHA | "_") ~ (ASCII_ALPHANUMERIC | "_")* } identifier = @{ (ASCII_ALPHA | "_") ~ (ASCII_ALPHANUMERIC | "_")* }
@@ -12,152 +11,108 @@ boolean = { "true" | "false" }
string_lit = { "\"" ~ inner_str ~ "\"" } string_lit = { "\"" ~ inner_str ~ "\"" }
inner_str = @{ (!"\"" ~ ANY)* } inner_str = @{ (!"\"" ~ ANY)* }
// ================= TYPE SCRIPT STYLE CHANGES ================= // ================= TOP LEVEL =================
// import becomes TS-like (still identical structure) top_level = _{ import | function_decl | struct_decl }
import_decl = { "import" ~ string_lit ~ ";" }
// struct stays, but feels like TS "type object shape" export = { "export" }
struct_decl = {
"struct" ~ identifier ~ "{" ~ struct_field* ~ "}"
}
// class already TS-like — just improved consistency import = { "import" ~ string_lit ~ ";" }
class_decl = {
"class" ~ identifier ~ "{" ~ class_member* ~ "}"
}
class_member = _{ struct_field | function_decl }
// function keyword changed feel: fn → function
function_decl = {
"function" ~ identifier ~ "(" ~ param_list? ~ ")" ~ ("->" ~ type_expr)? ~ block
}
// struct fields: TS-style semicolon consistency (already good)
struct_field = { identifier ~ ":" ~ type_expr ~ ";" }
// params: TS optional typing style feel (unchanged structure)
param_list = { param ~ ("," ~ param)* ~ ","? } param_list = { param ~ ("," ~ param)* ~ ","? }
param = { identifier ~ ":" ~ type_expr } param = { identifier ~ ":" ~ type_expr }
struct_decl = {
export? ~ "struct" ~ identifier ~ "{" ~ param_list? ~ "}"
}
function_decl = {
export? ~ "function" ~ identifier ~ "(" ~ param_list? ~ ")" ~ (":" ~ type_expr)? ~ block
}
// ================= STATEMENTS ================= // ================= STATEMENTS =================
block = { "{" ~ statement* ~ "}" } block = { "{" ~ statement_list ~ "}" }
statement_list = { statement* }
statement = _{ statement = _{
let_stmt expr_stmt
| return_stmt | var_decl
| var_assign
| if_stmt | if_stmt
| while_stmt
| for_stmt | for_stmt
| assign_stmt | return_stmt
| expression_stmt | break_stmt
| continue_stmt
| block
} }
// expression statements: TS allows no semicolon in real life, // --- basic statements ---
// but we keep your structure
expression_stmt = { expression ~ ";" }
// assignment unchanged (JS/TS feel already) expr_stmt = { expr ~ ";" }
assign_stmt = { identifier ~ "=" ~ expression ~ ";" }
// let → const/let feel (still your rule, just TS naming) return_stmt = { "return" ~ expr? ~ ";" }
let_stmt = {
"const" ~ identifier ~ (":" ~ type_expr)? ~ "=" ~ expression ~ ";" break_stmt = { "break" ~ ";" }
continue_stmt = { "continue" ~ ";" }
// --- variable declarations ---
var_decl_kind = { "let" | "const" | "var" }
var_decl = {
var_decl_kind ~ identifier ~ ("=" ~ expr)? ~ ";"
} }
// return: TS-like (no change except feel consistency) var_assign = {
return_stmt = { "return" ~ expression? ~ ";" } expr ~ "=" ~ expr ~ ";"
}
// --- control flow ---
// if: add TS-style parentheses (MAJOR feel upgrade, same structure)
if_stmt = { if_stmt = {
"if" ~ "(" ~ expression ~ ")" ~ block ~ ("else" ~ block)? "if" ~ "(" ~ expr ~ ")" ~ statement ~ ("else" ~ statement)?
}
while_stmt = {
"while" ~ "(" ~ expr ~ ")" ~ statement
} }
// for: TS-like "of"
for_stmt = { for_stmt = {
"for" ~ identifier ~ "of" ~ expression ~ block "for" ~ "(" ~ var_decl ~ expr ~ ";" ~ var_assign_no_semicolon ~ ")" ~ statement
} }
// ================= TYPES (KEEP STRUCTURE, TS FEEL) ================= var_assign_no_semicolon = {
expr ~ "=" ~ expr
type_expr = { base_type ~ "?"? } }
base_type = _{ array_type | identifier }
array_type = { "[" ~ type_expr ~ "]" }
// ================= EXPRESSIONS ================= // ================= EXPRESSIONS =================
type_expr = { identifier }
expression = { term ~ (bin_op ~ term)* } primary = {
integer
bin_op = _{
eq
| neq
| lte
| gte
| lt
| gt
| and
| or
| add
| sub
| mul
| div
}
add = { "+" }
sub = { "-" }
mul = { "*" }
div = { "/" }
eq = { "==" }
neq = { "!=" }
lte = { "<=" }
gte = { ">=" }
lt = { "<" }
gt = { ">" }
and = { "&&" }
or = { "||" }
// ================= LITERALS =================
struct_literal = {
identifier ~ "{" ~ struct_init_list? ~ "}"
}
struct_init_list = {
struct_init_field ~ ("," ~ struct_init_field)* ~ ","?
}
struct_init_field = {
identifier ~ ":" ~ expression
}
array_literal = {
"[" ~ (expression ~ ("," ~ expression)*)? ~ ","? ~ "]"
}
// ================= CHAINING =================
term = { primary ~ (field_access | call_suffix)* }
field_access = { "." ~ identifier }
call_suffix = {
"(" ~ (expression ~ ("," ~ expression)*)? ~ ","? ~ ")"
}
// ================= PRIMARY =================
primary = _{
struct_literal
| array_literal
| float | float
| integer
| string_lit
| boolean | boolean
| self_kw | string_lit
| null_kw
| identifier | identifier
} }
self_kw = { "this" } postfix = {
null_kw = { "null" } field_px
| call_px
| index_px
| binary_px
}
field_px = { "." ~ identifier }
call_px = { "(" ~ (expr ~ ("," ~ expr)*)? ~ ")" }
index_px = { "[" ~ expr ~ "]" }
binary_px = { bin_op ~ expr }
bin_op = { "+" | "-" | "*" | "/" | "%" | "==" | "!=" | "<" | ">" | "<=" | ">=" }
expr = {
primary ~ postfix*
}
+318 -301
View File
@@ -1,5 +1,4 @@
use pest::Parser; use pest::Parser;
use pest::iterators::Pair;
use pest_derive::Parser; use pest_derive::Parser;
pub mod ast; pub mod ast;
@@ -12,352 +11,370 @@ pub struct MistParser;
// convenience alias for pest errors // convenience alias for pest errors
pub type ParseError = pest::error::Error<Rule>; pub type ParseError = pest::error::Error<Rule>;
pub fn parse(source: &str) -> Result<Program, ParseError> { pub fn parse(source: &str) -> Result<Vec<TopLevel>, ParseError> {
let pairs = MistParser::parse(Rule::program, source)?; let mut pairs = MistParser::parse(Rule::program, source)?;
let mut statements = vec![]; let mut statements = vec![];
// pairs is an iterator over the top-level program pair for pair in pairs.next().unwrap().into_inner() {
// we need to get its inner children if let Some(stmt) = TopLevel::from_pair(pair) {
for pair in pairs { statements.push(stmt);
}
}
Ok(statements)
}
impl TypeExpr {
pub fn from_pair(pair: pest::iterators::Pair<Rule>) -> Self {
match pair.as_rule() { match pair.as_rule() {
Rule::program => { Rule::type_expr => {
for inner in pair.into_inner() { let inner = pair.into_inner().next().unwrap();
match inner.as_rule() { 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(pair: pest::iterators::Pair<Rule>) -> Self {
let params = pair
.into_inner()
.map(|p| {
let mut param_inner = p.into_inner();
let param_name = param_inner.next().unwrap().as_str().to_string();
let param_type = TypeExpr::from_pair(param_inner.next().unwrap());
(param_name, param_type)
})
.collect();
ParamList(params)
}
}
impl TopLevel {
pub fn from_pair(pair: pest::iterators::Pair<Rule>) -> Option<Self> {
match pair.as_rule() {
Rule::import => {
let path = pair.into_inner().next().unwrap().as_str().to_string();
Some(TopLevel::Import(path))
}
Rule::function_decl => { Rule::function_decl => {
statements.push(TopLevel::Function(parse_function(inner)))
}
Rule::struct_decl => statements.push(TopLevel::Struct(parse_struct(inner))),
Rule::class_decl => statements.push(TopLevel::Class(parse_class(inner))),
Rule::import_decl => statements.push(TopLevel::Import(parse_import(inner))),
Rule::EOI => {}
_ => {}
}
}
}
Rule::EOI => {}
_ => {}
}
}
Ok(Program { statements })
}
fn span_of(pair: &Pair<Rule>) -> Span {
let s = pair.as_span();
Span {
start: s.start(),
end: s.end(),
}
}
fn parse_function(pair: Pair<Rule>) -> Function {
let span = span_of(&pair);
let mut inner = pair.into_inner(); 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 name = inner.next().unwrap().as_str().to_string();
let params_pair = inner.next().unwrap();
let mut params = vec![]; let params = if params_pair.as_rule() == Rule::param_list {
let mut return_type = None; ParamList::from_pair(params_pair)
let mut body = vec![]; } else {
ParamList(vec![])
for part in inner { };
match part.as_rule() { let return_type = if let Some(next) = inner.peek() {
Rule::param_list => params = parse_param_list(part), if next.as_rule() == Rule::type_expr {
Rule::type_expr => return_type = Some(parse_type_expr(part)), Some(TypeExpr::from_pair(inner.next().unwrap()))
Rule::block => body = parse_block(part), } else {
_ => {} None
}
} }
} else {
None
};
Function { let body = Block::from_pair(inner.next().unwrap());
Some(TopLevel::FunctionDecl {
export,
name, name,
params, params,
return_type, return_type,
body, body,
span,
}
}
fn parse_param_list(pair: Pair<Rule>) -> Vec<Param> {
pair.into_inner()
.map(|p| {
let span = span_of(&p);
let mut inner = p.into_inner();
let name = inner.next().unwrap().as_str().to_string();
let type_expr = parse_type_expr(inner.next().unwrap());
Param {
name,
type_expr,
span,
}
}) })
.collect()
} }
fn parse_struct(pair: Pair<Rule>) -> Struct { Rule::struct_decl => {
let span = span_of(&pair);
let mut inner = pair.into_inner(); 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 name = inner.next().unwrap().as_str().to_string();
let fields = inner.map(|f| parse_struct_field(f)).collect(); let fields_pair = inner.next().unwrap();
Struct { name, fields, span } let fields = ParamList::from_pair(fields_pair);
}
fn parse_struct_field(pair: Pair<Rule>) -> StructField { Some(TopLevel::StructDecl {
let span = span_of(&pair); export,
let mut inner = pair.into_inner();
let name = inner.next().unwrap().as_str().to_string();
let type_expr = parse_type_expr(inner.next().unwrap());
StructField {
name,
type_expr,
span,
}
}
fn parse_class(pair: Pair<Rule>) -> Class {
let span = span_of(&pair);
let mut inner = pair.into_inner();
let name = inner.next().unwrap().as_str().to_string();
let mut fields = vec![];
let mut methods = vec![];
for part in inner {
match part.as_rule() {
Rule::struct_field => fields.push(parse_struct_field(part)),
Rule::function_decl => methods.push(parse_function(part)),
_ => {}
}
}
Class {
name, name,
fields, fields,
methods, })
span, }
Rule::EOI => None,
_ => unimplemented!("TopLevel parsing not implemented yet {:?}", pair.as_rule()),
}
} }
} }
fn parse_import(pair: Pair<Rule>) -> Import { impl Block {
let span = span_of(&pair); pub fn from_pair(pair: pest::iterators::Pair<Rule>) -> Self {
let path = pair.into_inner().next().unwrap().as_str().to_string(); let statements = pair
Import { path, span } .into_inner()
} .flat_map(|pair| {
if pair.as_rule() == Rule::statement_list {
fn parse_block(pair: Pair<Rule>) -> Vec<Statement> { pair.into_inner().map(Statement::from_pair).collect()
pair.into_inner()
.filter_map(|p| parse_statement(p))
.collect()
}
fn parse_statement(pair: Pair<Rule>) -> Option<Statement> {
match pair.as_rule() {
Rule::let_stmt => Some(Statement::Let(parse_let(pair))),
Rule::return_stmt => Some(Statement::Return(parse_return(pair))),
Rule::if_stmt => Some(Statement::If(parse_if(pair))),
Rule::for_stmt => Some(Statement::For(parse_for(pair))),
Rule::expression_stmt => {
let expr = pair.into_inner().next().unwrap();
Some(Statement::Expression(parse_expression(expr)))
}
Rule::expression => Some(Statement::Expression(parse_expression(pair))),
_ => None,
}
}
fn parse_let(pair: Pair<Rule>) -> LetStatement {
let span = span_of(&pair);
let mut inner = pair.into_inner();
let name = inner.next().unwrap().as_str().to_string();
// peek ahead — next is either a type or an expression
let next = inner.next().unwrap();
let (type_expr, value) = if next.as_rule() == Rule::type_expr {
(
Some(parse_type_expr(next)),
parse_expression(inner.next().unwrap()),
)
} else { } else {
(None, parse_expression(next)) vec![Statement::from_pair(pair)]
}
})
.collect();
Block(statements)
}
}
impl Statement {
pub fn from_pair(pair: pest::iterators::Pair<Rule>) -> 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(|expr_pair| {
// expects "=" expr
Expression::from_pair(expr_pair.into_inner().next().unwrap())
});
let kind = match kind_pair.as_str() {
"let" => VarKind::Let,
"const" => VarKind::Const,
"var" => VarKind::Var,
_ => unreachable!(),
}; };
LetStatement { Statement::VarDecl {
name, kind,
type_expr, name: name_pair.as_str().to_string(),
value, init,
span,
} }
} }
fn parse_return(pair: Pair<Rule>) -> ReturnStatement { Rule::return_stmt => {
let span = span_of(&pair);
let value = pair.into_inner().next().map(|p| parse_expression(p));
ReturnStatement { value, span }
}
fn parse_if(pair: Pair<Rule>) -> IfStatement {
let span = span_of(&pair);
let mut inner = pair.into_inner(); let mut inner = pair.into_inner();
let condition = parse_expression(inner.next().unwrap());
let body = parse_block(inner.next().unwrap()); let expr = inner.next().map(Expression::from_pair);
let else_body = inner.next().map(|p| parse_block(p));
IfStatement { 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, condition,
body, then_branch: Box::new(then_branch),
else_body, else_branch: else_branch.map(Box::new),
span,
} }
} }
fn parse_for(pair: Pair<Rule>) -> ForStatement { Rule::while_stmt => {
let span = span_of(&pair);
let mut inner = pair.into_inner(); let mut inner = pair.into_inner();
let var = inner.next().unwrap().as_str().to_string();
let iterator = parse_expression(inner.next().unwrap()); let condition = Expression::from_pair(inner.next().unwrap());
let body = parse_block(inner.next().unwrap()); let body = Statement::from_pair(inner.next().unwrap());
ForStatement {
var, Statement::While {
iterator, condition,
body, body: Box::new(body),
span,
} }
} }
fn parse_expression(pair: Pair<Rule>) -> Expression { Rule::for_stmt => {
match pair.as_rule() {
Rule::expression => {
let mut inner = pair.into_inner(); let mut inner = pair.into_inner();
let mut expr = parse_term(inner.next().unwrap());
// consume pairs of (bin_op, term) let init = inner
while let Some(op_pair) = inner.next() { .next()
let right = parse_term(inner.next().unwrap()); .map(|p| match p.as_rule() {
let span = span_of(&op_pair); Rule::var_decl => {
let op = match op_pair.as_rule() { let mut it = p.into_inner();
Rule::add => BinOperator::Add,
Rule::sub => BinOperator::Sub,
Rule::mul => BinOperator::Mul,
Rule::div => BinOperator::Div,
Rule::eq => BinOperator::Eq,
Rule::neq => BinOperator::NotEq,
Rule::lt => BinOperator::Lt,
Rule::gt => BinOperator::Gt,
Rule::lte => BinOperator::LtEq,
Rule::gte => BinOperator::GtEq,
Rule::and => BinOperator::And,
Rule::or => BinOperator::Or,
_ => unreachable!(),
};
expr = Expression::BinaryOp(Box::new(BinaryOp {
left: expr,
op,
right,
span,
}));
}
expr let kind = match it.next().unwrap().as_str() {
} "let" => VarKind::Let,
_ => parse_term(pair), "const" => VarKind::Const,
} "var" => VarKind::Var,
}
fn parse_term(pair: Pair<Rule>) -> Expression {
let mut inner = pair.into_inner();
let mut expr = parse_primary(inner.next().unwrap());
for part in inner {
let span = span_of(&part);
match part.as_rule() {
Rule::field_access => {
let field = part.into_inner().next().unwrap().as_str().to_string();
expr = Expression::FieldAccess(Box::new(FieldAccess {
object: expr,
field,
span,
}));
}
Rule::call_suffix => {
let args = part.into_inner().map(|p| parse_expression(p)).collect();
expr = Expression::Call(Box::new(CallExpr {
callee: expr,
args,
span,
}));
}
_ => {}
}
}
expr
}
fn parse_primary(pair: Pair<Rule>) -> Expression {
let span = span_of(&pair);
match pair.as_rule() {
Rule::struct_literal => {
let mut inner = pair.into_inner();
let name = inner.next().unwrap().as_str().to_string();
inner = inner.next().unwrap().into_inner();
// println!("{inner:#?}");
let mut fields = vec![];
for field in inner {
let mut f_inner = field.into_inner();
let field_name = f_inner.next().unwrap().as_str().to_string();
let value = parse_expression(f_inner.next().unwrap());
fields.push((field_name, value));
}
Expression::StructInit(Box::new(StructInit { name, fields, span }))
}
Rule::array_literal => {
let elements = pair.into_inner().map(|p| parse_expression(p)).collect();
Expression::ArrayLiteral(Box::new(ArrayLiteral { elements, span }))
}
Rule::integer => Expression::Integer(pair.as_str().parse().unwrap(), span),
Rule::float => Expression::Float(pair.as_str().parse().unwrap(), span),
Rule::string_lit => {
Expression::StringLit(pair.into_inner().next().unwrap().as_str().to_string(), span)
}
Rule::boolean => Expression::Bool(pair.as_str() == "true", span),
Rule::self_kw => Expression::Identifier("self".to_string(), span),
Rule::null_kw => Expression::Identifier("null".to_string(), span),
Rule::identifier => Expression::Identifier(pair.as_str().to_string(), span),
Rule::term => parse_term(pair),
_ => unreachable!("unexpected primary rule: {:?}", pair.as_rule()),
}
}
fn parse_type_expr(pair: Pair<Rule>) -> TypeExpr {
let mut inner = pair.into_inner();
let base = inner.next().unwrap();
let base_type = match base.as_rule() {
Rule::array_type => {
let inner_type = parse_type_expr(base.into_inner().next().unwrap());
TypeExpr::Array(Box::new(inner_type))
}
Rule::identifier => TypeExpr::Named(base.as_str().to_string()),
_ => unreachable!(), _ => unreachable!(),
}; };
// if a "?" suffix was present, wrap in Optional let name = it.next().unwrap().as_str().to_string();
if inner.next().is_some() { let init_expr = it
TypeExpr::Optional(Box::new(base_type)) .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<Rule>) -> 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 { } else {
base_type 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::<i64>().unwrap();
Expression::IntLiteral(value)
}
Rule::float => {
let value = pair.as_str().parse::<f64>().unwrap();
Expression::FloatLiteral(value)
}
Rule::boolean => {
let value = pair.as_str().parse::<bool>().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<Rule>) -> 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<Rule>) -> 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 }
}
+13 -5
View File
@@ -1,9 +1,17 @@
import "fmt"; function add(a: int, b: int): int {
let sum = 0;
function add(a: int, b: int) -> int { for (let i = 0; i < 10; i = i + 1) {
return a + b; if (i == 5) {
continue;
} }
function main() { sum = sum + i;
fmt.Println(add(10, 10) / 2); }
if (sum > 20) {
return sum;
} else {
return 0;
}
} }