diff --git a/src/parser/grammar.pest b/src/parser/grammar.pest index bb18fae..aaee271 100644 --- a/src/parser/grammar.pest +++ b/src/parser/grammar.pest @@ -13,40 +13,65 @@ string_lit = { "\"" ~ inner_str ~ "\"" } inner_str = @{ (!"\"" ~ ANY)* } // top level -import_decl = { "import" ~ string_lit } -struct_decl = { "struct" ~ identifier ~ "{" ~ struct_field* ~ "}" } -class_decl = { "class" ~ identifier ~ "{" ~ class_member* ~ "}" } +import_decl = { "import" ~ string_lit ~ ";" } + +struct_decl = { + "struct" ~ identifier ~ "{" ~ struct_field* ~ "}" +} + +class_decl = { + "class" ~ identifier ~ "{" ~ class_member* ~ "}" +} + class_member = _{ struct_field | function_decl } -function_decl = { "fn" ~ identifier ~ "(" ~ param_list? ~ ")" ~ ("->" ~ type_expr)? ~ block } +function_decl = { + "fn" ~ identifier ~ "(" ~ param_list? ~ ")" ~ ("->" ~ type_expr)? ~ block +} -struct_field = { identifier ~ ":" ~ type_expr } -param_list = { param ~ ("," ~ param)* } -param = { identifier ~ ":" ~ type_expr } +// struct fields (NO commas, Go-style) +struct_field = { identifier ~ ":" ~ type_expr ~ ";" } + +// params (allow trailing comma) +param_list = { param ~ ("," ~ param)* ~ ","? } +param = { identifier ~ ":" ~ type_expr } // statements -block = { "{" ~ statement* ~ "}" } +block = { "{" ~ statement* ~ "}" } + statement = _{ let_stmt | return_stmt | if_stmt | for_stmt | assign_stmt - | expression + | expression_stmt } -assign_stmt = { identifier ~ "=" ~ expression } -let_stmt = { "let" ~ identifier ~ (":" ~ type_expr)? ~ "=" ~ expression } -return_stmt = { "return" ~ expression? } -if_stmt = { "if" ~ expression ~ block ~ ("else" ~ block)? } -for_stmt = { "for" ~ identifier ~ "in" ~ expression ~ block } +expression_stmt = { expression ~ ";" } + +assign_stmt = { identifier ~ "=" ~ expression ~ ";" } + +let_stmt = { + "let" ~ identifier ~ (":" ~ type_expr)? ~ "=" ~ expression ~ ";" +} + +return_stmt = { "return" ~ expression? ~ ";" } + +if_stmt = { + "if" ~ expression ~ block ~ ("else" ~ block)? +} + +for_stmt = { + "for" ~ identifier ~ "in" ~ expression ~ block +} // types type_expr = { base_type ~ "?"? } base_type = _{ array_type | identifier } array_type = { "[" ~ type_expr ~ "]" } -// expressions (still simple, no precedence yet) +// expressions (still no precedence yet) expression = { term ~ (bin_op ~ term)* } bin_op = _{ @@ -78,6 +103,7 @@ and = { "&&" } or = { "||" } // literals + struct_literal = { identifier ~ "{" ~ struct_init_list? ~ "}" } @@ -94,7 +120,7 @@ array_literal = { "[" ~ (expression ~ ("," ~ expression)*)? ~ ","? ~ "]" } -// expressions continuation +// chaining term = { primary ~ (field_access | call_suffix)* } field_access = { "." ~ identifier } @@ -103,6 +129,7 @@ call_suffix = { "(" ~ (expression ~ ("," ~ expression)*)? ~ ","? ~ ")" } +// primary primary = _{ struct_literal | array_literal diff --git a/test/main.ms b/test/main.ms index d75832f..b8ebcb6 100644 --- a/test/main.ms +++ b/test/main.ms @@ -1,120 +1,120 @@ -import "fmt" -import "strings" +import "fmt"; +import "strings"; // structs are plain data struct Point { - x: float - y: float + x: float; + y: float; } // classes have fields and methods class Animal { - name: string - age: int + name: string; + age: int; fn speak() -> string { - return "..." + return "..."; } fn describe() -> string { - return "I am " + self.name + return "I am " + self.name; } } class Dog { - name: string - age: int + name: string; + age: int; fn speak() -> string { - return "Woof!" + return "Woof!"; } fn fetch(item: string) -> string { - return self.name + " fetched the " + item + return self.name + " fetched the " + item; } } // basic function fn add(a: int, b: int) -> int { - return a + b + return a + b; } // optional return type fn find(name: string) -> string? { if name == "mist" { - return name + return name; } - return null + return null; } // array types fn sum(numbers: [int]) -> int { - let total: int = 0 + let total: int = 0; for n in numbers { - total = total + n + total = total + n; } - return total + return total; } // multiple params, no return fn greet(first: string, last: string) { - let full: string = first + " " + last - print(full) + 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 - } + y: y, + }; } // if / else fn classify(n: int) -> string { if n < 0 { - return "negative" + return "negative"; } else { - return "positive" + return "positive"; } } // entry point fn main() { // variables - let x: int = 10 - let y: int = 20 - let result: int = add(x, y) + 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) + let message = "Hello from Mist!"; + print(message); // struct usage - let p: Point = make_point(1.5, 2.5) - print(p.x) + 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")) + 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) + let nums: [int] = [1, 2, 3, 4, 5]; + let total: int = sum(nums); + print(total); // for loop for n in nums { - print(n) + print(n); } // optional - let found: string? = find("mist") + let found: string? = find("mist"); if found { - print(found) + print(found); } }