Re writing

This commit is contained in:
2026-04-14 02:12:46 +02:00
parent 63ac823caa
commit a9c9c03fd3
5 changed files with 264 additions and 866 deletions
+19 -174
View File
@@ -1,187 +1,32 @@
#[derive(Debug, Clone)]
pub struct Span {
pub start: usize,
pub end: usize,
}
#[derive(Debug, Clone)]
pub struct Program {
pub statements: Vec<TopLevel>,
pub enum TypeExpr {
Identifier(String),
}
#[derive(Debug, Clone)]
pub enum TopLevel {
Function(Function),
Struct(Struct),
Class(Class),
Import(Import),
}
#[derive(Debug, Clone)]
pub struct Function {
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,
Import(String),
StructDecl {
name: String,
fields: Vec<(String, TypeExpr)>,
},
FunctionDecl {
name: String,
params: Vec<(String, TypeExpr)>,
return_type: Option<TypeExpr>,
body: Vec<Statement>,
},
}
#[derive(Debug, Clone)]
pub enum Statement {
Let(LetStatement),
Return(ReturnStatement),
Expression(Expression),
If(IfStatement),
For(ForStatement),
Expression(String),
}
#[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 {
Named(String),
Array(Box<TypeExpr>),
Optional(Box<TypeExpr>),
}
#[derive(Debug, Clone)]
pub struct ArrayLiteral {
pub elements: Vec<Expression>,
pub span: Span,
Identifier(String),
IntLiteral(i64),
FloatLiteral(f64),
BoolLiteral(bool),
StringLiteral(String),
}
+8 -134
View File
@@ -2,7 +2,7 @@ WHITESPACE = _{ " " | "\t" | "\r" | "\n" }
COMMENT = _{ "//" ~ (!"\n" ~ ANY)* }
program = { SOI ~ item* ~ EOI }
item = _{ import_decl | function_decl | struct_decl | class_decl }
item = _{ import_decl | function_decl | struct_decl }
// primitives
identifier = @{ (ASCII_ALPHA | "_") ~ (ASCII_ALPHANUMERIC | "_")* }
@@ -12,152 +12,26 @@ boolean = { "true" | "false" }
string_lit = { "\"" ~ inner_str ~ "\"" }
inner_str = @{ (!"\"" ~ ANY)* }
// ================= TYPE SCRIPT STYLE CHANGES =================
// ================= TOP LEVEL =================
// import becomes TS-like (still identical structure)
import_decl = { "import" ~ string_lit ~ ";" }
// struct stays, but feels like TS "type object shape"
struct_decl = {
struct_field = { identifier ~ ":" ~ type_expr ~ ";" }
struct_decl = {
"struct" ~ identifier ~ "{" ~ struct_field* ~ "}"
}
// class already TS-like — just improved consistency
class_decl = {
"class" ~ identifier ~ "{" ~ class_member* ~ "}"
}
class_member = _{ struct_field | function_decl }
// function keyword changed feel: fn → function
param_list = { param ~ ("," ~ param)* ~ ","? }
param = { identifier ~ ":" ~ type_expr }
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 = { identifier ~ ":" ~ type_expr }
// ================= STATEMENTS =================
block = { "{" ~ statement* ~ "}" }
statement = _{
let_stmt
| return_stmt
| if_stmt
| for_stmt
| assign_stmt
| expression_stmt
}
// expression statements: TS allows no semicolon in real life,
// but we keep your structure
expression_stmt = { expression ~ ";" }
// assignment unchanged (JS/TS feel already)
assign_stmt = { identifier ~ "=" ~ expression ~ ";" }
// let → const/let feel (still your rule, just TS naming)
let_stmt = {
"const" ~ identifier ~ (":" ~ type_expr)? ~ "=" ~ expression ~ ";"
}
// return: TS-like (no change except feel consistency)
return_stmt = { "return" ~ expression? ~ ";" }
// if: add TS-style parentheses (MAJOR feel upgrade, same structure)
if_stmt = {
"if" ~ "(" ~ expression ~ ")" ~ block ~ ("else" ~ block)?
}
// for: TS-like "of"
for_stmt = {
"for" ~ identifier ~ "of" ~ expression ~ block
}
// ================= TYPES (KEEP STRUCTURE, TS FEEL) =================
type_expr = { base_type ~ "?"? }
base_type = _{ array_type | identifier }
array_type = { "[" ~ type_expr ~ "]" }
statement = _{ "idk" }
// ================= EXPRESSIONS =================
expression = { term ~ (bin_op ~ term)* }
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
| integer
| string_lit
| boolean
| self_kw
| null_kw
| identifier
}
self_kw = { "this" }
null_kw = { "null" }
type_expr = _{ identifier }
+5 -327
View File
@@ -1,5 +1,4 @@
use pest::Parser;
use pest::iterators::Pair;
use pest_derive::Parser;
pub mod ast;
@@ -12,7 +11,7 @@ pub struct MistParser;
// convenience alias for pest errors
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 statements = vec![];
@@ -24,12 +23,10 @@ pub fn parse(source: &str) -> Result<Program, ParseError> {
Rule::program => {
for inner in pair.into_inner() {
match inner.as_rule() {
Rule::function_decl => {
statements.push(TopLevel::Function(parse_function(inner)))
Rule::import_decl => {
let path = inner.into_inner().next().unwrap().as_str().to_string();
statements.push(TopLevel::Import(path));
}
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 => {}
_ => {}
}
@@ -40,324 +37,5 @@ pub fn parse(source: &str) -> Result<Program, ParseError> {
}
}
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 name = inner.next().unwrap().as_str().to_string();
let mut params = vec![];
let mut return_type = None;
let mut body = vec![];
for part in inner {
match part.as_rule() {
Rule::param_list => params = parse_param_list(part),
Rule::type_expr => return_type = Some(parse_type_expr(part)),
Rule::block => body = parse_block(part),
_ => {}
}
}
Function {
name,
params,
return_type,
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 {
let span = span_of(&pair);
let mut inner = pair.into_inner();
let name = inner.next().unwrap().as_str().to_string();
let fields = inner.map(|f| parse_struct_field(f)).collect();
Struct { name, fields, span }
}
fn parse_struct_field(pair: Pair<Rule>) -> StructField {
let span = span_of(&pair);
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,
fields,
methods,
span,
}
}
fn parse_import(pair: Pair<Rule>) -> Import {
let span = span_of(&pair);
let path = pair.into_inner().next().unwrap().as_str().to_string();
Import { path, span }
}
fn parse_block(pair: Pair<Rule>) -> Vec<Statement> {
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 {
(None, parse_expression(next))
};
LetStatement {
name,
type_expr,
value,
span,
}
}
fn parse_return(pair: Pair<Rule>) -> ReturnStatement {
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 condition = parse_expression(inner.next().unwrap());
let body = parse_block(inner.next().unwrap());
let else_body = inner.next().map(|p| parse_block(p));
IfStatement {
condition,
body,
else_body,
span,
}
}
fn parse_for(pair: Pair<Rule>) -> ForStatement {
let span = span_of(&pair);
let mut inner = pair.into_inner();
let var = inner.next().unwrap().as_str().to_string();
let iterator = parse_expression(inner.next().unwrap());
let body = parse_block(inner.next().unwrap());
ForStatement {
var,
iterator,
body,
span,
}
}
fn parse_expression(pair: Pair<Rule>) -> Expression {
match pair.as_rule() {
Rule::expression => {
let mut inner = pair.into_inner();
let mut expr = parse_term(inner.next().unwrap());
// consume pairs of (bin_op, term)
while let Some(op_pair) = inner.next() {
let right = parse_term(inner.next().unwrap());
let span = span_of(&op_pair);
let op = match op_pair.as_rule() {
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
}
_ => parse_term(pair),
}
}
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!(),
};
// if a "?" suffix was present, wrap in Optional
if inner.next().is_some() {
TypeExpr::Optional(Box::new(base_type))
} else {
base_type
}
Ok(statements)
}