From 7ac0070589d0eef049ddf84808c40b227c6f9460 Mon Sep 17 00:00:00 2001 From: Lil-Ran Date: Sat, 4 Oct 2025 14:30:33 +0800 Subject: [PATCH] wip: struct, enum --- src/parser/ast.mbt | 113 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 107 insertions(+), 6 deletions(-) diff --git a/src/parser/ast.mbt b/src/parser/ast.mbt index 3deb5c1..3777bc7 100644 --- a/src/parser/ast.mbt +++ b/src/parser/ast.mbt @@ -63,8 +63,16 @@ enum Expr { enum TopLevel { TopLetDecl(id~ : String, type_~ : Type?, expr~ : Expr) TopFn(Function) - Struct(Struct) - Enum(Enum) + Struct( + id~ : String, + user_defined_type~ : Type?, + fields~ : Array[(String, Type)] + ) + Enum( + id~ : String, + user_defined_type~ : Type?, + variants~ : Array[(String, Array[Type])] + ) } ///| @@ -118,6 +126,91 @@ fn parse_type( } } +///| +fn parse_struct( + tokens : ArrayView[Token], +) -> (TopLevel, ArrayView[Token]) raise ParseError { + guard tokens is [Struct, UpperIdentifier(id), .. rest] else { + raise ParseError("Expected 'struct' followed by struct name") + } + let (user_defined_type, rest) = if rest + is [LBracket, UpperIdentifier(type_), RBracket, .. r] { + (Some(UserDefined(type_)), r) + } else { + (None, rest) + } + guard rest is [LCurlyBracket, .. rest] else { + raise ParseError("Expected '{' after struct name") + } + let fields = [] + loop rest { + [RCurlyBracket, .. r] => (Struct(id~, user_defined_type~, fields~), r) + [UpperIdentifier(field_name) | LowerIdentifier(field_name), Colon, .. r] => { + let (field_type, r) = parse_type(r) + fields.push((field_name, field_type)) + match r { + [Semicolon, .. r] => continue r + [RCurlyBracket, ..] => continue r + _ => raise ParseError("Expected ';' or '}' after struct field") + } + } + _ => raise ParseError("Unexpected token in struct field list") + } +} + +///| +fn parse_enum( + tokens : ArrayView[Token], +) -> (TopLevel, ArrayView[Token]) raise ParseError { + guard tokens is [Enum, UpperIdentifier(id), .. rest] else { + raise ParseError("Expected 'enum' followed by enum name") + } + let (user_defined_type, rest) = if rest + is [LBracket, UpperIdentifier(type_), RBracket, .. r] { + (Some(UserDefined(type_)), r) + } else { + (None, rest) + } + guard rest is [LCurlyBracket, .. rest] else { + raise ParseError("Expected '{' after enum name") + } + let variants = [] + loop rest { + [RCurlyBracket, .. r] => (Enum(id~, user_defined_type~, variants~), r) + [UpperIdentifier(variant_name), .. r] => { + let variant_types = [] + if r is [LParen, .. r] { + loop r { + [RParen, ..] => break + r => { + let (variant_type, r) = parse_type(r) + variant_types.push(variant_type) + match r { + [Comma, RParen, ..] => + raise ParseError( + "Trailing comma in enum variant type list is not allowed", + ) + [Comma, .. r] => continue r + [RParen, ..] => break + _ => + raise ParseError( + "Expected ',' or ')' in enum variant type list", + ) + } + } + } + } + variants.push((variant_name, variant_types)) + match r { + [Semicolon, .. r] => continue r + [RCurlyBracket, ..] => continue r + _ => raise ParseError("Expected ';' or '}' after enum variant") + } + } + _ => raise ParseError("Unexpected token in enum variant list") + } +} + ///| pub fn parse_program(tokens : Array[Token]) -> Program raise ParseError { let program = [] @@ -131,18 +224,26 @@ pub fn parse_program(tokens : Array[Token]) -> Program raise ParseError { ) } let (expr, rest) = parse_expr(rest) - program.push(TopLetDecl(id, type_, expr)) + program.push(TopLetDecl(id~, type_=Some(type_), expr~)) continue rest } [Let, LowerIdentifier(id) | UpperIdentifier(id), Assign, .. rest] => { let (expr, rest) = parse_expr(rest) - program.push(TopLetDecl(id, None, expr)) + program.push(TopLetDecl(id~, type_=None, expr~)) continue rest } [Fn, LowerIdentifier("main"), ..] => ... [Fn, ..] => ... - [Struct, ..] => ... - [Enum, ..] => ... + [Struct, ..] as tokens => { + let (struct_, rest) = parse_struct(tokens) + program.push(struct_) + continue rest + } + [Enum, ..] as tokens => { + let (enum_, rest) = parse_enum(tokens) + program.push(enum_) + continue rest + } _ => raise ParseError("Unexpected token at top level") } }