Working full parser

This commit is contained in:
2026-04-13 14:30:22 +02:00
parent 6b908754e3
commit 3758305a23
4 changed files with 248 additions and 34 deletions
+7
View File
@@ -112,6 +112,7 @@ pub enum Expression {
Call(Box<CallExpr>), Call(Box<CallExpr>),
FieldAccess(Box<FieldAccess>), FieldAccess(Box<FieldAccess>),
StructInit(Box<StructInit>), StructInit(Box<StructInit>),
ArrayLiteral(Box<ArrayLiteral>),
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@@ -178,3 +179,9 @@ pub enum TypeExpr {
Array(Box<TypeExpr>), Array(Box<TypeExpr>),
Optional(Box<TypeExpr>), Optional(Box<TypeExpr>),
} }
#[derive(Debug, Clone)]
pub struct ArrayLiteral {
pub elements: Vec<Expression>,
pub span: Span,
}
+37 -8
View File
@@ -23,21 +23,50 @@ param = { identifier ~ ":" ~ type_expr }
// statements // statements
block = { "{" ~ statement* ~ "}" } block = { "{" ~ statement* ~ "}" }
statement = _{ let_stmt | return_stmt | if_stmt | for_stmt | expression } statement = _{ let_stmt | return_stmt | if_stmt | for_stmt | assign_stmt | expression }
assign_stmt = { identifier ~ "=" ~ expression }
let_stmt = { "let" ~ identifier ~ (":" ~ type_expr)? ~ "=" ~ expression } let_stmt = { "let" ~ identifier ~ (":" ~ type_expr)? ~ "=" ~ expression }
return_stmt = { "return" ~ expression? } return_stmt = { "return" ~ expression? }
if_stmt = { "if" ~ expression ~ block ~ ("else" ~ block)? } if_stmt = { "if" ~ expression ~ block ~ ("else" ~ block)? }
for_stmt = { "for" ~ identifier ~ "in" ~ expression ~ block } for_stmt = { "for" ~ identifier ~ "in" ~ expression ~ block }
// expressions — broken into precedence layers, no cycles
expression = { primary ~ (access_chain)* }
access_chain = _{ field_access | call_suffix }
field_access = { "." ~ identifier }
call_suffix = { "(" ~ (expression ~ ("," ~ expression)*)? ~ ")" }
primary = _{ float | integer | string_lit | boolean | identifier }
// types — optional is a suffix, not a recursive wrapper // types — optional is a suffix, not a recursive wrapper
type_expr = { base_type ~ "?"? } type_expr = { base_type ~ "?"? }
base_type = _{ array_type | identifier } base_type = _{ array_type | identifier }
array_type = { "[" ~ type_expr ~ "]" } array_type = { "[" ~ type_expr ~ "]" }
// expressions
expression = { term ~ (bin_op ~ term)* }
bin_op = _{ add | sub | mul | div | eq | neq | lte | gte | lt | gt | and | or }
add = { "+" }
sub = { "-" }
mul = { "*" }
div = { "/" }
eq = { "==" }
neq = { "!=" }
lte = { "<=" }
gte = { ">=" }
lt = { "<" }
gt = { ">" }
and = { "&&" }
or = { "||" }
struct_literal = {
identifier ~ "{" ~ (struct_init_field ~ ("," ~ struct_init_field)*)? ~ "}"
}
struct_init_field = {
identifier ~ ":" ~ expression
}
array_literal = {
"[" ~ (expression ~ ("," ~ expression)*)? ~ "]"
}
term = { primary ~ (field_access | call_suffix)* }
field_access = { "." ~ identifier }
call_suffix = { "(" ~ (expression ~ ("," ~ expression)*)? ~ ")" }
primary = _{ struct_literal | array_literal | float | integer | string_lit | boolean | self_kw | null_kw | identifier }
self_kw = { "self" }
null_kw = { "null" }
+87 -25
View File
@@ -219,52 +219,114 @@ fn parse_for(pair: Pair<Rule>) -> ForStatement {
} }
fn parse_expression(pair: Pair<Rule>) -> Expression { fn parse_expression(pair: Pair<Rule>) -> Expression {
// let span = span_of(&pair);
match pair.as_rule() { match pair.as_rule() {
Rule::expression => { Rule::expression => {
let mut inner = pair.into_inner(); let mut inner = pair.into_inner();
let mut expr = parse_primary(inner.next().unwrap()); let mut expr = parse_term(inner.next().unwrap());
// chain field accesses and calls as left-to-right suffixes // consume pairs of (bin_op, term)
for part in inner { while let Some(op_pair) = inner.next() {
let span = span_of(&part); let right = parse_term(inner.next().unwrap());
match part.as_rule() { let span = span_of(&op_pair);
Rule::field_access => { let op = match op_pair.as_rule() {
let field = part.into_inner().next().unwrap().as_str().to_string(); Rule::add => BinOperator::Add,
expr = Expression::FieldAccess(Box::new(FieldAccess { Rule::sub => BinOperator::Sub,
object: expr, Rule::mul => BinOperator::Mul,
field, Rule::div => BinOperator::Div,
span, Rule::eq => BinOperator::Eq,
})); Rule::neq => BinOperator::NotEq,
} Rule::lt => BinOperator::Lt,
Rule::call_suffix => { Rule::gt => BinOperator::Gt,
let args = part.into_inner().map(|p| parse_expression(p)).collect(); Rule::lte => BinOperator::LtEq,
expr = Expression::Call(Box::new(CallExpr { Rule::gte => BinOperator::GtEq,
callee: expr, Rule::and => BinOperator::And,
args, Rule::or => BinOperator::Or,
span, _ => unreachable!(),
})); };
} expr = Expression::BinaryOp(Box::new(BinaryOp {
_ => {} left: expr,
} op,
right,
span,
}));
} }
expr expr
} }
_ => parse_primary(pair), _ => 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 { fn parse_primary(pair: Pair<Rule>) -> Expression {
let span = span_of(&pair); let span = span_of(&pair);
match pair.as_rule() { match pair.as_rule() {
Rule::struct_literal => {
let mut inner = pair.into_inner();
let name = inner.next().unwrap().as_str().to_string();
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::integer => Expression::Integer(pair.as_str().parse().unwrap(), span),
Rule::float => Expression::Float(pair.as_str().parse().unwrap(), span), Rule::float => Expression::Float(pair.as_str().parse().unwrap(), span),
Rule::string_lit => { Rule::string_lit => {
Expression::StringLit(pair.into_inner().next().unwrap().as_str().to_string(), span) Expression::StringLit(pair.into_inner().next().unwrap().as_str().to_string(), span)
} }
Rule::boolean => Expression::Bool(pair.as_str() == "true", 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::identifier => Expression::Identifier(pair.as_str().to_string(), span),
Rule::term => parse_term(pair),
_ => unreachable!("unexpected primary rule: {:?}", pair.as_rule()), _ => unreachable!("unexpected primary rule: {:?}", pair.as_rule()),
} }
} }
+117 -1
View File
@@ -1,4 +1,120 @@
import "fmt"
import "strings"
// structs are plain data
struct Point {
x: float
y: float
}
// classes have fields and methods
class Animal {
name: string
age: int
fn speak() -> string {
return "..."
}
fn describe() -> string {
return "I am " + self.name
}
}
class Dog {
name: string
age: int
fn speak() -> string {
return "Woof!"
}
fn fetch(item: string) -> string {
return self.name + " fetched the " + item
}
}
// basic function
fn add(a: int, b: int) -> int {
return a + b
}
// optional return type
fn find(name: string) -> string? {
if name == "mist" {
return name
}
return null
}
// array types
fn sum(numbers: [int]) -> int {
let total: int = 0
for n in numbers {
total = total + n
}
return total
}
// multiple params, no return
fn greet(first: string, last: string) {
let full: string = first + " " + last
print(full)
}
// structs initialized with fields
fn make_point(x: float, y: float) -> Point {
return Point {
x: x,
y: y
}
}
// if / else
fn classify(n: int) -> string {
if n < 0 {
return "negative"
} else {
return "positive"
}
}
// entry point
fn main() { fn main() {
let message: string = "Hello, World!" // variables
let x: int = 10
let y: int = 20
let result: int = add(x, y)
// inferred (no type annotation)
let message = "Hello from Mist!"
print(message) print(message)
// struct usage
let p: Point = make_point(1.5, 2.5)
print(p.x)
// class usage
let dog: Dog = Dog {
name: "Rex",
age: 3
}
print(dog.speak())
print(dog.fetch("ball"))
// arrays
let nums: [int] = [1, 2, 3, 4, 5]
let total: int = sum(nums)
print(total)
// for loop
for n in nums {
print(n)
}
// optional
let found: string? = find("mist")
if found {
print(found)
}
} }